From be36a67da9bbd5a52d390402f9feef22c4a7b2d4 Mon Sep 17 00:00:00 2001 From: Stephen Cameron Date: Thu, 22 Jun 2017 20:01:55 +0200 Subject: [PATCH] WIP #807 @6.5 --- js/libs/fluidbook/fluidbook.desktop.js | 3 +- js/libs/fluidbook/fluidbook.js | 26 ++++++- js/libs/fluidbook/fluidbook.menu.js | 3 +- js/libs/fluidbook/fluidbook.nav.js | 104 +++++++++++++++++++++++-- js/main.js | 2 + style/mmenu/mmenu.less | 26 ++++++- 6 files changed, 154 insertions(+), 10 deletions(-) diff --git a/js/libs/fluidbook/fluidbook.desktop.js b/js/libs/fluidbook/fluidbook.desktop.js index 14c7e48f..60fed437 100644 --- a/js/libs/fluidbook/fluidbook.desktop.js +++ b/js/libs/fluidbook/fluidbook.desktop.js @@ -46,7 +46,8 @@ FluidbookDesktop.prototype = { return false; }, wheelZoom: function (delta) { - if ($("body").hasClass('view')) { + // Disable scroll zoom when either a view or the menu is open... + if ($("body").is('.view, .menu-open')) { return; } this.fluidbook.zoom.setZoom(this.fluidbook.zoom.zoom + delta / 3, delta > 0 ? 1 : -1); diff --git a/js/libs/fluidbook/fluidbook.js b/js/libs/fluidbook/fluidbook.js index 59d982ea..360ce80b 100644 --- a/js/libs/fluidbook/fluidbook.js +++ b/js/libs/fluidbook/fluidbook.js @@ -32,6 +32,7 @@ Fluidbook.prototype = { this.service = new FluidbookService(this, datas.id); this.support = new FluidbookSupport(this); this.loader = new FluidbookLoader(this); + this.index = new FluidbookIndex(this); this.search = new FluidbookSearch(this); this.pad = new FluidbookPad(this); this.links = new FluidbookLinks(this); @@ -723,6 +724,9 @@ Fluidbook.prototype = { $('#menuList > ul > li').not(exception).fadeIn(300); }, + initSearchResults: function () { + this.menuSearchResults = $('#menuSearchResults'); + }, initSearchHints: function () { @@ -730,6 +734,9 @@ Fluidbook.prototype = { this.hideMenuItems('#menuSearch'); // Hide everything except the search form so we can have space for the hints this.menuSearchHints.fadeIn(300); + + this.initSearchResults(); + // if (this.menuSearchHints.hasClass('mm-hidden')) { // this.nav.menuAPI.openPanel(this.menuSearchHints, false); // } @@ -770,8 +777,25 @@ Fluidbook.prototype = { // $("#searchHints").html(''); // $("#searchHints").hide(); this.menuSearchHints.html('').hide(); // Clear and hide all hints - this.showMenuItems('#menuSearch'); // Show menu items that were hidden previously }, + + hideSearchResults: function () { + this.menuSearchResults.html('').hide(); + }, + + // Check if a search is active in the interface + isSearchActive: function () { + return ($('#q').val().length > 0); + }, + + // Clear search query and close search related menu items + closeSearch: function () { + $('#q').val(''); // Clear search field + this.hideSearchHints(); + this.hideSearchResults(); + this.showMenuItems(); // Show menu items that were hidden previously + }, + getLocationToShare: function () { if (this.datas.phonegap) { return this.datas.offlineLink; diff --git a/js/libs/fluidbook/fluidbook.menu.js b/js/libs/fluidbook/fluidbook.menu.js index 53fde9b4..aec4e8e4 100644 --- a/js/libs/fluidbook/fluidbook.menu.js +++ b/js/libs/fluidbook/fluidbook.menu.js @@ -5,7 +5,6 @@ function FluidbookMenu(fluidbook) { FluidbookMenu.prototype = { init: function () { - this.index = new FluidbookIndex(this.fluidbook); var $this = this; $(document).on('click', ".mview .back", function () { @@ -374,7 +373,7 @@ FluidbookMenu.prototype = { openIndex: function (title, group, closeAll, callback) { var c = !closeAll ? ' one' : ''; var index = '
' + this.closeButton(c) + '

' + title + '

'; - index += this.index.getView(group); + index += this.fluidbook.index.getView(group); $("#view").append('
' + index + '
'); this.fluidbook.bookmarks.updateBookmarks(); if (callback != undefined) { diff --git a/js/libs/fluidbook/fluidbook.nav.js b/js/libs/fluidbook/fluidbook.nav.js index 88c5c460..a5244acd 100644 --- a/js/libs/fluidbook/fluidbook.nav.js +++ b/js/libs/fluidbook/fluidbook.nav.js @@ -56,10 +56,12 @@ FluidbookNav.prototype = { // Bind API hooks (see http://mmenu.frebsite.nl/documentation/core/off-canvas.html#h4) this.menuAPI.bind("open:finish", function () { + $('body').addClass('menu-open'); $this.menuIsOpen = true; }); this.menuAPI.bind("close:finish", function () { + $('body').removeClass('menu-open'); $this.menuIsOpen = false; }); @@ -337,8 +339,18 @@ FluidbookNav.prototype = { // Click handler to close menu $(document).on('click', '#' + buttonID, function(e) { + e.preventDefault(); - $this.menuAPI.close(); + + // If the search is active, the close button should clear the search + // and return the user to the main menu instead of closing the menu + if ($this.fluidbook.isSearchActive()) { + $this.fluidbook.closeSearch(); + } else { + $this.menuAPI.close(); + } + + }); return ''+ getSpriteIcon('interface-close') +''; @@ -364,15 +376,94 @@ FluidbookNav.prototype = { // Search form handler $(document).on('submit', '#searchForm', function () { var q = $("#q").val(); + if (q == '') { return false; } $this.fluidbook.search.find(q, function (results) { - // Todo: see FluidbookMenu displayResults function... + + // Handle empty result set + if (results.total <= 0) { + fluidbook.menuSearchResults.html(this.fluidbook.l10n.__('no result found')); + return false; + } + + var hits = []; + + // Create a list of all pages so we can record which ones have a hit on the search term + for (var i = 0; i <= $this.fluidbook.datas.pages; i++) { + hits[i] = 0; + } + // Map result hits to pages + $.each(results.results, function (k, v) { + hits[k] += v; + }); + + // ToDo: check the purpose of the group variable? Also check tracking //$this.displayResults(r, group, cb); - console.log('Search results...'); - console.log(results); + //console.log('Search results...'); + //console.log(results); + + // Display results + //res += $this.fluidbook.l10n.__('search results for') + ' « ' + q + " »" + + // Use the index of all pages as a starting point to filter results thumbnails + fluidbook.menuSearchResults.html($this.fluidbook.index.getView()).hide(); + + // Process each spread of pages to collect the ones with results + fluidbook.menuSearchResults.find('.doubleThumb').each(function() { + + var currentPages = $(this).data('pages').toString().split(','), + totalHits = 0, + pagesWithHits = []; + + // Get total number of hits for pages in this spread + for (var i in currentPages) { + var pageNum = parseInt(currentPages[i]); + if (hits[pageNum] > 0) { + totalHits += hits[pageNum]; + pagesWithHits.push(currentPages[i]); + } + } + + + // If there's already a .hits element, this spread has already been processed + if ($(this).find('.hits').length > 0) { + return; + } + + if (totalHits == 0) { + // Should pages with no results still be shown? + if (fluidbook.datas.searchShowNoResultsPages) { + $(this).append('
'); + $(this).append('
' + $this.fluidbook.l10n.__('no result found') + '
'); + } else { + $(this).remove(); + return; + } + } else { + // Add the + $(this).append('
' + totalHits + ' ' + fluidbook.l10n.__('hit(s)') + '
'); + if (fluidbook.pad.enabled) { + if (pagesWithHits.length == 1) { + $(this).find('a').attr('href', '#/page/' + pagesWithHits[0]); + } else { + $(this).find('a').attr('href', '#/search/' + e + '/' + $(this).attr('page')); + } + } else { + $(this).find('a').attr('href', '#/page/' + $(this).attr('page')); + } + } + + }); + + // Todo: handle results.terms here... Highlighting? + + + fluidbook.hideSearchHints(); + fluidbook.menuSearchResults.fadeIn(300); + }); // window.location.hash = '/search/' + q; @@ -385,7 +476,10 @@ FluidbookNav.prototype = { }); //$("#q").keyup(searchHints); - $(document).on('keyup', '#q', searchHints); + $(document).on('keyup', '#q', function(key) { + if (13 == key.which) return; // Ignore enter key otherwise hints are re-displayed after form is submitted + searchHints(); + }); $(document).on('click', ".hint", function () { var e = $("#q").val().split(' '); diff --git a/js/main.js b/js/main.js index 592a9769..fd562bf9 100644 --- a/js/main.js +++ b/js/main.js @@ -505,6 +505,8 @@ function searchHints() { } else { try { fluidbook.hideSearchHints(); + fluidbook.hideSearchResults(); + fluidbook.showMenuItems(); // Show main menu items that were hidden previously } catch (err) { } diff --git a/style/mmenu/mmenu.less b/style/mmenu/mmenu.less index 64a601a0..f7995bb1 100644 --- a/style/mmenu/mmenu.less +++ b/style/mmenu/mmenu.less @@ -89,6 +89,8 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim]~#mm-blocker { // Main menu with icons #menuList { + padding-top: 60px; // Offset for the fixed search box... + &:before { height: 0; // Fix spacing with search box } @@ -115,7 +117,9 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim]~#mm-blocker { #searchForm { - position: relative; + position: fixed; + top: 0; + left: 0; padding: 0; text-align: left; } @@ -141,5 +145,25 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim]~#mm-blocker { .svg-icon { width: 20px; height: 20px; + margin-top: 1px; // Fixes weird clipping of top of icon + } +} + +#menuSearchResults, #menuSearchHints { + display: none; // Hidden by default, displayed via JS +} + +#menuSearchResults { + max-height: ~"calc(100vh - 60px)"; + overflow-y: auto; + padding-top: 20px; + + .doubleThumb { + display: block !important; + margin: 10px auto 40px auto !important; + } + + .padding { + display: none !important; } } \ No newline at end of file -- 2.39.5