diff --git a/css/global.scss b/css/global.scss index 41ae33b20..0dcd63a46 100644 --- a/css/global.scss +++ b/css/global.scss @@ -1 +1,2 @@ @include icon-black-white('notes', 'notes', 1); +@include icon-black-white('notes-trans', 'notes', 1); diff --git a/img/notes-trans.svg b/img/notes-trans.svg new file mode 100644 index 000000000..1850accbb --- /dev/null +++ b/img/notes-trans.svg @@ -0,0 +1 @@ + diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index fff09806f..261fb666f 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -20,6 +20,7 @@ public function __construct(array $urlParams = []) { public function register(IRegistrationContext $context): void { $context->registerCapability(Capabilities::class); + $context->registerSearchProvider(SearchProvider::class); $context->registerDashboardWidget(DashboardWidget::class); $context->registerEventListener( BeforeTemplateRenderedEvent::class, diff --git a/lib/AppInfo/SearchProvider.php b/lib/AppInfo/SearchProvider.php new file mode 100644 index 000000000..aa6802294 --- /dev/null +++ b/lib/AppInfo/SearchProvider.php @@ -0,0 +1,84 @@ +util = $util; + $this->notesService = $notesService; + $this->url = $url; + } + + + public function getId(): string { + return Application::APP_ID; + } + + public function getName(): string { + return $this->util->l10n->t('Notes'); + } + + public function getOrder(string $route, array $routeParameters): int { + if (strpos($route, 'files' . '.') === 0) { + return 25; + } elseif (strpos($route, Application::APP_ID . '.') === 0) { + return -1; + } + return 4; + } + + public function search(IUser $user, ISearchQuery $query): SearchResult { + $notes = $this->notesService->search($user->getUID(), $query->getTerm()); + // sort by modified time + usort($notes, function (Note $a, Note $b) { + return $b->getModified() - $a->getModified(); + }); + // create SearchResultEntry from Note + $result = array_map( + function (Note $note) : SearchResultEntry { + $excerpt = $note->getCategory(); + try { + $excerpt = $note->getExcerpt(); + } catch (\Throwable $e) { + } + return new SearchResultEntry( + '', + $note->getTitle(), + $excerpt, + $this->url->linkToRouteAbsolute('notes.page.index') . 'note/'.$note->getId(), + 'icon-notes-trans' + ); + }, + $notes + ); + return SearchResult::complete( + $this->getName(), + $result + ); + } +} diff --git a/lib/Service/NotesService.php b/lib/Service/NotesService.php index 3c940b8e3..d7621be1b 100644 --- a/lib/Service/NotesService.php +++ b/lib/Service/NotesService.php @@ -58,6 +58,39 @@ public function get(string $userId, int $id) : Note { return $note; } + public function search(string $userId, string $search) : array { + $terms = preg_split('/\s+/', $search); + $notes = $this->getAll($userId)['notes']; + return array_values(array_filter( + $notes, + function (Note $note) use ($terms) : bool { + return $this->searchTermsInNote($note, $terms); + } + )); + } + private function searchTermsInNote(Note $note, array $terms) : bool { + try { + $d = $note->getData(); + $strings = [ $d['title'], $d['category'], $d['content'] ]; + foreach ($terms as $term) { + if (!$this->searchTermInData($strings, $term)) { + return false; + } + } + return true; + } catch (\Throwable $e) { + return false; + } + } + private function searchTermInData(array $strings, string $term) : bool { + foreach ($strings as $str) { + if (stripos($str, $term) !== false) { + return true; + } + } + return false; + } + /** * @throws \OCP\Files\NotPermittedException diff --git a/src/App.vue b/src/App.vue index ed7253a18..f69421727 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,7 +13,6 @@ @@ -45,7 +44,6 @@ import { Content, } from '@nextcloud/vue' import { showSuccess } from '@nextcloud/dialogs' -import { emit } from '@nextcloud/event-bus' import '@nextcloud/dialogs/styles/toast.scss' import { config } from './config' @@ -70,7 +68,6 @@ export default { return { filter: { category: null, - search: '', }, loading: { notes: true, @@ -89,20 +86,12 @@ export default { }, filteredNotes() { - const search = this.filter.search.toLowerCase() - const notes = this.notes.filter(note => { if (this.filter.category !== null && this.filter.category !== note.category && !note.category.startsWith(this.filter.category + '/')) { return false } - const searchFields = ['title', 'category'] - if (search !== '') { - return searchFields.some( - searchField => note[searchField].toLowerCase().indexOf(search) !== -1 - ) - } return true }) @@ -128,9 +117,6 @@ export default { created() { store.commit('setDocumentTitle', document.title) - if (typeof OCA.Search === 'function') { - this.search = new OCA.Search(this.onSearch, this.onResetSearch) - } window.addEventListener('beforeunload', this.onClose) this.loadNotes() }, @@ -205,16 +191,6 @@ export default { } }, - onSearch(query) { - this.filter.search = query - - emit('toggle-navigation', { open: true }) - }, - - onResetSearch() { - this.filter.search = '' - }, - onNewNote() { if (this.loading.create) { return diff --git a/src/components/NavigationList.vue b/src/components/NavigationList.vue index b72d36097..9f0ba6789 100644 --- a/src/components/NavigationList.vue +++ b/src/components/NavigationList.vue @@ -7,24 +7,6 @@ @category-selected="$emit('category-selected', $event)" /> - - - - -
  • - -
  • -