diff options
-rw-r--r-- | css/fulltextsearch.css | 32 | ||||
-rw-r--r-- | img/options.svg | 1 | ||||
-rw-r--r-- | img/options_black.svg | 1 | ||||
-rw-r--r-- | js/fulltextsearch.v1.api.js | 4 | ||||
-rw-r--r-- | js/fulltextsearch.v1.js | 2 | ||||
-rw-r--r-- | js/fulltextsearch.v1.searchbar.js | 233 | ||||
-rw-r--r-- | js/fulltextsearch.v1.searchbox.js | 261 | ||||
-rw-r--r-- | js/fulltextsearch.v1.settings.js | 48 | ||||
-rw-r--r-- | js/navigate.js | 8 | ||||
-rw-r--r-- | lib/Api/v1/FullTextSearch.php | 2 | ||||
-rw-r--r-- | templates/settings.admin.php | 20 |
11 files changed, 338 insertions, 274 deletions
diff --git a/css/fulltextsearch.css b/css/fulltextsearch.css index d4da377..8f9ae63 100644 --- a/css/fulltextsearch.css +++ b/css/fulltextsearch.css @@ -1,4 +1,23 @@ +INPUT#searchbox { + background-size: 16px !important; +} + +.search_more { + width: 400px; + padding: 15px; + right: 0px; + position: absolute; + top: 44px; + border-radius: 3px; + border: 1px solid; + background: #ffffff; +} + +/** + + */ + .provider_result { font-style: italic; } @@ -88,17 +107,6 @@ margin-top: 40px; } -.search_more { - background: #fbfbfb; - width: 400px; - padding: 15px; - right: 30px; - position: absolute; - top: 41px; - border-radius: 3px; - border: solid #cecece 1px; -} - .icon-page-prev { background-image: url('/apps/fulltextsearch/img/page-prev.svg'); } @@ -135,7 +143,6 @@ margin: 2px !important; } - .div-table { display: table; width: auto; @@ -153,7 +160,6 @@ display: table-column; } - .div-table-col-left { width: 220px; margin-top: 8px; diff --git a/img/options.svg b/img/options.svg new file mode 100644 index 0000000..bed27eb --- /dev/null +++ b/img/options.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M3 6a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm5 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm5 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z" fill="#fff"/></svg> diff --git a/img/options_black.svg b/img/options_black.svg new file mode 100644 index 0000000..c510e70 --- /dev/null +++ b/img/options_black.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M3 6a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm5 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm5 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/></svg> diff --git a/js/fulltextsearch.v1.api.js b/js/fulltextsearch.v1.api.js index 1cc826e..7ef39c1 100644 --- a/js/fulltextsearch.v1.api.js +++ b/js/fulltextsearch.v1.api.js @@ -54,14 +54,14 @@ var api = { }, - options: function (providerId, callback) { + retreiveOptions: function (providerId, callback) { var res = {status: -1}; $.ajax({ method: 'GET', url: OC.generateUrl('/apps/fulltextsearch/options/' + providerId) }).done(function (res) { - searchbar.onOptionsLoaded(res); + searchbox.onOptionsLoaded(res); api.onCallback(callback, res); }).fail(function () { nav.failedToAjax(); diff --git a/js/fulltextsearch.v1.js b/js/fulltextsearch.v1.js index d956088..78a2a36 100644 --- a/js/fulltextsearch.v1.js +++ b/js/fulltextsearch.v1.js @@ -39,7 +39,7 @@ var FullTextSearch = function () { $.extend(FullTextSearch.prototype, settings); $.extend(FullTextSearch.prototype, result); - $.extend(FullTextSearch.prototype, searchbar); + $.extend(FullTextSearch.prototype, searchbox); $.extend(FullTextSearch.prototype, nav); $.extend(FullTextSearch.prototype, api); diff --git a/js/fulltextsearch.v1.searchbar.js b/js/fulltextsearch.v1.searchbar.js deleted file mode 100644 index 7bd6e8d..0000000 --- a/js/fulltextsearch.v1.searchbar.js +++ /dev/null @@ -1,233 +0,0 @@ -/* - * FullTextSearch - Full text search framework for Nextcloud - * - * This file is licensed under the Affero General Public License version 3 or - * later. See the COPYING file. - * - * @author Maxence Lange <maxence@artificial-owl.com> - * @copyright 2018 - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/** global: OCA */ -/** global: nav */ -/** global: _ */ -/** global: api */ -/** global: search */ -/** global: result */ -/** global: fullTextSearch */ -/** global: settings */ - - -var searchbox = { - searchTimeout: null, - search_more: null, - search_icon_more: null, - search_icon_close: null, - search_icon: null, - search_input: null, - search_form: null -}; - - -var searchbar = { - - init: function () { - var divHeaderRight = $('div.header-right'); - - searchbox.search_div = $('<div>', {class: 'next_search_div'}); - divHeaderRight.prepend(searchbox.search_div); - - searchbox.search_icon = $('<div>', {class: 'icon-fulltextsearch'}); - searchbox.search_icon.css('background-image', - "url('/apps/fulltextsearch/img/fulltextsearch.svg')"); - searchbox.search_icon.fadeTo(0, 0.7); - searchbox.search_div.append(searchbox.search_icon); - - searchbox.search_form = $('<div>'); - searchbox.search_form.fadeTo(0, 0); - - searchbox.search_input = $('<input>', { - id: 'next_search_input', - placeholder: 'Search' - }); - searchbox.search_form.append(searchbox.search_input); - - searchbox.search_more = $('<div>', {class: 'search_more'}); - searchbox.search_more.fadeTo(0, 0).hide(); - - searchbox.search_icon_more = $('<div>', {class: 'icon-more-white icon-more-fulltextsearch'}); - searchbox.search_icon_more.fadeTo(0, 0); - searchbox.search_icon_more.on('click', function () { - if (curr.moreDisplayed) { - searchbox.search_more.stop().fadeTo(100, 0, function () { - $(this).hide(); - }); - curr.moreDisplayed = false; - } else { - searchbox.search_more.stop().show().fadeTo(100, 1); - curr.moreDisplayed = true; - } - }); - searchbox.search_form.append(searchbox.search_icon_more); - - searchbox.search_icon_close = $('<div>', {class: 'icon-close-white icon-close-fulltextsearch'}); - searchbox.search_icon_close.fadeTo(0, 0); - searchbox.search_icon_close.on('click', function () { - settings.lockSearchbox = false; - searchbox.search_icon_more.stop().fadeTo(100, 0); - searchbox.search_icon_close.stop().fadeTo(100, 0); - searchbox.search_more.stop().fadeTo(100, 0, function () { - $(this).hide(); - }); - curr.moreDisplayed = false; - searchbox.search_input.val(''); - nav.onSearchReset(); - }); - searchbox.search_form.append(searchbox.search_icon_close); - - searchbox.search_form.hover(function () { - searchbox.search_icon.stop().fadeTo(100, 0); - searchbox.search_form.stop().fadeTo(100, 0.8); - }, function () { - if (settings.lockSearchbox === true) { - return; - } - searchbox.search_form.stop().fadeTo(500, 0); - searchbox.search_icon.stop().fadeTo(800, 0.7); - }); - searchbox.search_div.append(searchbox.search_form); - searchbox.search_div.append(searchbox.search_more); - - searchbox.search_input.on('focus', function () { - searchbar.searching(); - }); - - searchbox.search_input.on('input', function () { - - if ($(this).val() === '') { - nav.onSearchReset(); - } - - // if (settings.parentHasMethod('onEntryGenerated')) { - // settings.parent.onEntryGenerated(); - // } - - if (searchbox.searchTimeout === null && searchbar.initSearch(false)) { - searchbox.searchTimeout = _.delay(function () { - searchbar.initSearch(false); - searchbox.searchTimeout = null; - }, 2000); - } - }); - - fullTextSearch.options(settings.searchProviderId); - - $(window).bind('keydown', function (event) { - if (event.ctrlKey || event.metaKey) { - if (String.fromCharCode(event.which).toLowerCase() === 'f') { - event.preventDefault(); - searchbar.searching(); - } - } - }); - }, - - - searching: function () { - if (settings.lockSearchbox === true) { - return; - } - settings.lockSearchbox = true; - searchbox.search_icon.stop().fadeTo(100, 0); - searchbox.search_form.stop().fadeTo(100, 0.8); - searchbox.search_input.focus(); - searchbox.search_icon_close.stop().fadeTo(200, 1); - if (settings.noMoreOptions) { - searchbox.search_icon_more.stop().fadeTo(200, 1); - } - }, - - - onOptionsLoaded: function (result) { - if (!result[settings.searchProviderId]) { - searchbox.search_icon_more.off('click').hide(); - searchbox.search_input.css('width', '245px'); - return; - } - settings.noMoreOptions = true; - searchbox.search_more.html(result[settings.searchProviderId]); - searchbox.search_more.find('INPUT').each(function () { - $(this).on('change', function () { - var search = searchbox.search_input.val(); - fullTextSearch.search({ - providers: settings.searchProviderId, - search: search, - page: curr.page, - options: searchbar.getSearchOptions(), - size: 20 - }); - }); - }) - }, - - - getSearchOptions: function () { - var options = {}; - searchbox.search_more.find('INPUT').each(function () { - var value = $(this).val(); - - if ($(this).attr('type') === 'checkbox' && !$(this).is(':checked')) { - value = ''; - } - - options[$(this).attr('id')] = value; - }); - - return options; - }, - - - // TODO: do we really need this initSearch, or should we use the one from fulltextsearch.js !? - initSearch: function (force) { - var search = searchbox.search_input.val(); - - if (!force && search.length < 3) { - return false; - } - - if (curr.lastRequest === search) { - return true; - } - - curr.lastRequest = search; - - fullTextSearch.search({ - providers: settings.searchProviderId, - search: search, - page: curr.page, - options: searchbar.getSearchOptions(), - size: 20 - }); - - return true; - } - - -}; - - diff --git a/js/fulltextsearch.v1.searchbox.js b/js/fulltextsearch.v1.searchbox.js new file mode 100644 index 0000000..2ab55bd --- /dev/null +++ b/js/fulltextsearch.v1.searchbox.js @@ -0,0 +1,261 @@ +/* + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/** global: OCA */ +/** global: nav */ +/** global: _ */ +/** global: api */ +/** global: search */ +/** global: result */ +/** global: fullTextSearch */ +/** global: settings */ + + +var box_elements = { + searchTimeout: null, + + // v0.6.0 + + searchBoxInitialized: false, + search_form: null, + search_input: null, + moreOptions: false, + moreDisplayed: false, + search_more: null, + iconSearchOptions: 'options.svg', + iconSearch: 'fulltextsearch.svg', + currentBackgroundImage: '' +}; + + +var searchbox = { + + init: function () { + + var self = this; + box_elements.search_form = $('FORM.searchbox'); + box_elements.search_input = $('INPUT#searchbox'); + + + // on focus of the searchbox, we remove all keyup event + box_elements.search_input.bind('keydown', function () { + self.initFullTextSearchBox(); + }); + + // options + if (OCA.Theming.inverted) { + box_elements.iconSearchOptions = 'options_black.svg'; + box_elements.iconSearch = 'fulltextsearch_black.svg'; + } + + box_elements.currentBackgroundImage = box_elements.iconSearch; + box_elements.search_input.css({ + 'background-image': 'url(/apps/fulltextsearch/img/' + box_elements.iconSearch + ')' + }); + + box_elements.search_input.click(function (e) { + var elm = $(this); + var xPos = e.pageX - elm.offset().left; + if (xPos < 26) { + self.switchSearchOptions(); + } + }); + + fullTextSearch.retreiveOptions(settings.searchProviderId); + + box_elements.search_more = + $('<div>', {class: 'search_more'}).css({'border-color': OCA.Theming.color}); + + box_elements.search_form.append(box_elements.search_more); + box_elements.search_more.fadeTo(0, 0).hide(); + }, + + + initFullTextSearchBox: function () { + if (box_elements.searchBoxInitialized) { + return; + } + var self = this; + + box_elements.search_input.unbind('keyup'); + box_elements.search_input.bind('keyup blur change', function () { + if ($(this).val() === '') { + self.displaySearchOptionsIcon(false); + } else { + self.displaySearchOptionsIcon(true); + } + + self.searching(); + }); + + box_elements.searchBoxInitialized = true; + }, + + + switchSearchOptions: function () { + this.displaySearchOptions(!box_elements.moreDisplayed); + }, + + displaySearchOptions: function (display) { + if (!box_elements.moreOptions) { + return; + } + + if (display) { + box_elements.search_more.stop().show().fadeTo(100, 1); + } else { + box_elements.search_more.stop().fadeTo(100, 0, function () { + $(this).hide(); + }); + } + box_elements.moreDisplayed = display; + }, + + + displaySearchOptionsIcon: function (display) { + + if (!box_elements.moreOptions) { + return; + } + + if (display) { + this.switchInputBackgroundImage(box_elements.iconSearchOptions); + } else { + if (box_elements.search_input.val() !== '') { + return; + } + + this.displaySearchOptions(false); + this.switchInputBackgroundImage(box_elements.iconSearch); + } + }, + + + switchInputBackgroundImage: function (image) { + + if (image === box_elements.currentBackgroundImage) { + return; + } + box_elements.currentBackgroundImage = image; + + box_elements.search_input.stop().animate({'background-position-x': '-70px'}, 150, + function () { + $(this).css({ + 'background-image': 'url(/apps/fulltextsearch/img/' + image + ')' + }).animate({'background-position-x': '6px'}, 150); + }); + }, + + + searching: function () { + + var search = box_elements.search_input.val(); + console.log('searching ' + search); + + // fullTextSearch.search({ + // providers: settings.searchProviderId, + // search: search, + // page: curr.page, + // options: searchbox.getSearchOptions(), + // size: 20 + // }); + // }); + + // if (settings.lockSearchbox === true) { + // return; + // } + // settings.lockSearchbox = true; + // searchbox.search_icon.stop().fadeTo(100, 0); + // searchbox.search_form.stop().fadeTo(100, 0.8); + // searchbox.search_input.focus(); + // searchbox.search_icon_close.stop().fadeTo(200, 1); + // if (settings.noMoreOptions) { + // searchbox.search_icon_more.stop().fadeTo(200, 1); + // } + }, + + + onOptionsLoaded: function (result) { + if (!result[settings.searchProviderId]) { + box_elements.moreOptions = false; + return; + } + + box_elements.moreOptions = true; + box_elements.search_input.find('background-image').on('click', function () { + console.log('___'); + }); + box_elements.search_more.html(result[settings.searchProviderId]); + box_elements.search_more.find('INPUT').each(function () { + $(this).on('change', searchbox.searching); + }) + }, + + + getSearchOptions: function () { + var options = {}; + // searchbox.search_more.find('INPUT').each(function () { + // var value = $(this).val(); + // + // if ($(this).attr('type') === 'checkbox' && !$(this).is(':checked')) { + // value = ''; + // } + // + // options[$(this).attr('id')] = value; + // }); + + return options; + }, + + + // TODO: do we really need this initSearch, or should we use the one from fulltextsearch.js !? + initSearch: function (force) { + // var search = searchbox.search_input.val(); + // + // if (!force && search.length < 3) { + // return false; + // } + // + // if (curr.lastRequest === search) { + // return true; + // } + // + // curr.lastRequest = search; + // + // fullTextSearch.search({ + // providers: settings.searchProviderId, + // search: search, + // page: curr.page, + // options: searchbar.getSearchOptions(), + // size: 20 + // }); + // + // return true; + } + + +}; + + diff --git a/js/fulltextsearch.v1.settings.js b/js/fulltextsearch.v1.settings.js index fb101ea..afdb0cc 100644 --- a/js/fulltextsearch.v1.settings.js +++ b/js/fulltextsearch.v1.settings.js @@ -28,18 +28,21 @@ var settings = { - parent: null, delay_provider: 300, delay_result: 150, resultContainer: null, entryTemplate: null, - searchProviderId: '', - lockSearchbox: false, - noMoreOptions: false, entryTemplateDefault: null, divNoResult: null, + // 0.6.0 + parent: null, + searchProviderId: '', + + /** + * generate the default template to dsplay search result entries + */ generateDefaultTemplate: function () { var divLeft = $('<div>', {class: 'result_entry_left'}); @@ -58,6 +61,9 @@ var settings = { }, + /** + * generate a no result display + */ generateNoResultDiv: function () { var div = $('<div>', {id: 'noresult'}); div.html('no result'); @@ -66,21 +72,45 @@ var settings = { }, - setEntryTemplateId: function (template, parent) { + /** + * used to set the template to display search result entries + * + * @param template + */ + setEntryTemplate: function (template) { settings.entryTemplate = template; - settings.parent = parent; }, - setResultContainerId: function (container) { + /** + * used to set the container for the search result entries + * + * @param container + */ + setResultContainer: function (container) { settings.resultContainer = container; settings.resultContainer.prepend(settings.divNoResult); }, - addSearchBar: function (providerId) { + + /** + * initialize the full text search and assign a providerId + * + * @param providerId + * @param parent + */ + initFullTextSearch: function (providerId, parent) { settings.searchProviderId = providerId; - searchbar.init(); + settings.parent = parent; + searchbox.init(); }, + + /** + * check that the app that call the lib contains a specific method + * + * @param method + * @returns {boolean} + */ parentHasMethod: function (method) { if (settings.parent === null) { return false; diff --git a/js/navigate.js b/js/navigate.js index 04ed30a..c4660e5 100644 --- a/js/navigate.js +++ b/js/navigate.js @@ -46,8 +46,8 @@ Navigate.prototype = { init: function () { var self = this; - fullTextSearch.setEntryTemplateId($('#template_entry'), self); - fullTextSearch.setResultContainerId($('#search_result')); + fullTextSearch.setEntryTemplate($('#template_entry'), self); + fullTextSearch.setResultContainer($('#search_result')); elements.search_input = $('#search_input'); elements.search_submit = $('#search_submit'); @@ -82,7 +82,7 @@ Navigate.prototype = { $.ajax({ method: 'GET', - url: OC.generateUrl('/apps/fulltextsearch//navigation/panels') + url: OC.generateUrl('/apps/fulltextsearch/navigation/panels') }).done(function (res) { self.displayPanels(res); }); @@ -136,8 +136,6 @@ Navigate.prototype = { li.append(ul); elements.search_panels.append(li); - - } }, diff --git a/lib/Api/v1/FullTextSearch.php b/lib/Api/v1/FullTextSearch.php index d97135a..acf8195 100644 --- a/lib/Api/v1/FullTextSearch.php +++ b/lib/Api/v1/FullTextSearch.php @@ -76,7 +76,7 @@ class FullTextSearch { Util::addStyle(Application::APP_NAME, 'fulltextsearch'); Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.api'); Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.settings'); - Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.searchbar'); + Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.searchbox'); Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.result'); Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.navigation'); Util::addScript(Application::APP_NAME, 'fulltextsearch.v1'); diff --git a/templates/settings.admin.php b/templates/settings.admin.php index 83ff49f..27ef68a 100644 --- a/templates/settings.admin.php +++ b/templates/settings.admin.php @@ -48,16 +48,16 @@ Util::addStyle(Application::APP_NAME, 'admin'); <h2><?php p($l->t('Full text search')) ?></h2> <div class="div-table"> - <div class="div-table-row"> - <div class="div-table-col div-table-col-left"> - <span class="leftcol">Enable App Navigation:</span> - <br/> - <em>Add a global search within all your content provider.</em> - </div> - <div class="div-table-col"> - <input type="checkbox" id="fts_navigation" value="1"/> - </div> - </div> +<!-- <div class="div-table-row">--> +<!-- <div class="div-table-col div-table-col-left">--> +<!-- <span class="leftcol">Enable App Navigation:</span>--> +<!-- <br/>--> +<!-- <em>Add a global search within all your content provider.</em>--> +<!-- </div>--> +<!-- <div class="div-table-col">--> +<!-- <input type="checkbox" id="fts_navigation" value="1"/>--> +<!-- </div>--> +<!-- </div>--> <div class="div-table-row"> <div class="div-table-col div-table-col-left"> |