Поиск

Нативный текстовый поиск в композиции Viewer

Doconut Viewer предоставляет обычный поиск, используя текст, извлечённый просмотрщиком формата, или перенаправление PDF на основе текста. Для этого требуется возможность лицензии Search.

Включить пользовательский интерфейс поиска

Поиск — это модуль Viewer, а не отдельная панель инструментов. Полная страница должна включать ресурсы Viewer, панель инструментов Viewer, монтирование Viewer и инициализированный objViewer; затем Ribbon поиска монтируется и привязывается к тому же экземпляру.

Поиск и аннотация являются встроенными лицензированными функциями, а не пакетами AddPlugin<T>(). Запросите ресурсы поиска у Viewer; их теги генерируются только при наличии лицензии на поиск. В представлениях MVC 5 нет @inject, поэтому сформируйте теги в контроллере и передайте их через ViewBag, вместе с флагом лицензии, необходимым странице:

csharp
var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
{
    IncludeViewerCss = true,
    IncludeSearchCss = true
});
ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
{
    IncludeJQuery        = true,
    IncludeViewerScripts = true,
    IncludeSearchScripts = true,
    IncludeSearchBar     = true
});
ViewBag.IsSearchEnabled = viewer.IsSearchEnabled;

Запишите их в представление с помощью @Html.Raw(ViewBag.ViewerCss) и @Html.Raw(ViewBag.ViewerScripts). В Web Forms откройте те же значения из кода‑behind и запишите их с помощью <%= %>.

Встроенный Ribbon вызывает те же методы JavaScript, доступные пользовательскому интерфейсу.

Сохраните полную композицию Viewer видимой в разметке, сначала инициализируйте docViewer, а затем прикрепите лицензированный Ribbon:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <!-- Элементы управления просмотрщиком, включая кнопку, открывающую поиск -->
</nav>
<div id="searchBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>

<script>
    let searchBar = null;
    let currentToken = '';

    const objViewer = $('#div_ctlDoc').docViewer({
        BasePath: '/',
        ResPath: 'doconut-res/images'
    });

    @if ((bool)ViewBag.IsSearchEnabled)
    {
        <text>
    searchBar = $('#searchBarMount').doconutSearchBar({
        docId: 'ctlDoc',
        getRequestParams: () => ({ token: currentToken }),
        onStatus: (message) => console.log(message),
        onToast: (message, type) => console.log(type, message),
        onLayout: () => requestAnimationFrame(() => objViewer.Refit())
    });
    searchBar.attach(objViewer);
        </text>
    }
</script>

Серверный if имеет значение: без возможности поиска ReferenceScripts исключает скрипт Ribbon, поэтому вызов без защиты doconutSearchBar(...) приведёт к ошибке и остановит загрузку страницы Viewer. В Web Forms напишите такой же guard как <% if (IsSearchEnabled) { %> … <% } %>.

Компонент внедряет группы Find, Options и Results и обрабатывает поиск, очистку, подсчёт совпадений и навигацию к предыдущему/следующему совпадению. Панель инструментов Viewer, принадлежащая хосту, только должна переключать её:

javascript
searchBar.isOpen() ? searchBar.close() : searchBar.open();

Его публичный API намеренно небольшого размера:

МетодНазначение
attach(objViewer)Подключить Ribbon к инициализированному viewer; требуется один раз
open() / close()Показать или скрыть Ribbon; закрытие также очищает подсветки
reset()Очистить текущий запрос, количество результатов и подсветки
isOpen()Сообщить, виден ли Ribbon
setStatus(message)Переслать статусное сообщение через настроенный callback

Опциональный callback onToggle(isOpen) позволяет хосту синхронизировать кнопку поиска, а onLayout позволяет изменять размер/подгонять viewer, когда высота Ribbon меняется. Для последовательности запуска комбинированных Viewer, Search и Annotation см. Быстрый старт.

Поиск из JavaScript

javascript
objViewer.Search(keyword, false, function (resultCount) {
    console.log('Matches:', resultCount);
});

Второй аргумент — поиск целых слов/точное совпадение. Количество совпадений приходит в обратный вызов: Search сам отправляется на сервер и возвращает ничего полезного, поэтому var n = objViewer.Search(keyword, false) всегда читает undefined — и страница, построенная таким образом, сообщает «ничего не найдено», в то время как просмотрщик выделяет совпадения. После обратного вызова:

МетодРезультат
SearchMatchCount()Общее количество отдельных совпадений в документе.
SearchSummary(false)[pageNumber, matchCount] записей без перерисовки.
SearchSummary(true)Тот же итог и отрисовывает выделения на странице/миниатюре.
GotoSearchMatch(index)Переходит к совпадению с нулевым индексом.

DocImage.axd отвечает search=<term> и exact=true|false в формате XML. Используйте API виджета, а не разбирайте этот внутренний ответ самостоятельно.

Проверка возможности поиска

Ответ инициализации сообщает:

text
X-Doconut-Can-Search: 1

После инициализации objViewer.CanSearch() раскрывает тот же результат формата/сеанса. Он возвращает false, когда сервер отправляет 0; до ответа, или при более старом сервере, который опускает заголовок, по умолчанию используется true.

Три независимых условия не должны путаться:

УсловиеВопрос
CanSearch() / response headerИмеет ли разрешённый просмотрщик собственный индекс/путь поиска?
AllowSearchЗапрашивала ли конфигурация этого формата извлечение текста, где существует переключатель?
LicenseCapability.SearchАвторизовано ли приложение выполнять поиск и получать UI‑пакеты?

Формат может быть технически доступным для поиска, хотя текущая лицензия запрещает эту операцию.

Включить извлечение по формату

csharp
var token = await viewer.OpenDocumentAsync(path, new PdfConfig
{
    AllowSearch = true,
    AllowCopy   = true   // необязательно: позволяет пользователю перетаскивать область и копировать её текст
});

AllowSearch и AllowCopy существуют на PdfConfig, WordConfig, ExcelConfig и PptConfig. Свойства Office делегируют своим вложенным PdfConfig. Оба по умолчанию используют false.

Обычные адаптеры нативного поиска существуют для PDF, Word, Excel, PowerPoint, TXT, Visio, email, EPUB и MHT. XPS по умолчанию использует свой путь PDF. HTML и Microsoft Project выигрывают от перенаправления на текстовый PDF:

csharp
// DefaultRender = false → преобразуется в PDF на основе текста → поддаётся поиску
var token = await viewer.OpenDocumentAsync(path, new HtmlConfig { DefaultRender = false });

Для нативных рендереров CanSearch() описывает возможности просмотрщика; это не гарантирует, что конкретный документ содержит пригодный текст. PDF, страницы которого являются только отсканированными изображениями, всё равно может давать ноль нативных результатов.

Обычное поведение поиска

Сервер пытается использовать источники поиска в следующем порядке:

  1. Нативные результаты ISearchableViewer.
  2. Предсозданный поисковый индекс .srh.
  3. Ошибка/пустой результат, когда источник поиска отсутствует.

CanSearch() может быть истинным для просмотрщика с поддержкой поиска, даже если конкретный документ не имеет текстового слоя и поэтому не возвращает совпадений.

Лицензирование и поведение UI

Активная временная/демо‑лицензия предоставляет возможность поиска в течение своего активного периода. Отсутствующая лицензия и устаревший файл TRIAL не предоставляют возможности поиска. Без поиска:

  • ReferenceCss и ReferenceScripts опускают поисковые пакеты.
  • DocImage.axd отклоняет запросы поиска вместо возврата результатов.

Управляйте видимостью пользовательского UI через IDoconutLicenseService.IsCapabilityGranted(LicenseCapability.Search) и используйте CanSearch() для отдельного результата формата/сеанса.

Устранение неполадок

СимптомПроверка
Поисковая панель отсутствуетВозможность поиска и IncludeSearchCss/IncludeSearchScripts/IncludeSearchBar
CanSearch() ложноПросмотрщик формата, выбранный путь DefaultRender и заголовок ответа инициализации
Поиск возвращает ноль для отсканированного PDFДокумент не имеет текстового слоя; используйте источник с текстом или проекцию PDF, сохраняющую текст
Поиск работает, но выделения смещеныПуть рендеринга, разрешение, трансформации документа и извлечённые рамки слов

Была ли эта страница полезной?