summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJörn Friedrich Dreyer <jfd@butonic.de>2014-12-11 16:23:39 +0100
committerJörn Friedrich Dreyer <jfd@butonic.de>2015-01-02 10:28:41 +0100
commit0e9b05b7012844e348d36b5b35e1c50487a3bbc4 (patch)
treee910ca1483a8936327b0667eb2e28e75d10df3d4
parentc738359a111445aac90518db39b5d5883e44892d (diff)
downloadnextcloud-server-0e9b05b7012844e348d36b5b35e1c50487a3bbc4.tar.gz
nextcloud-server-0e9b05b7012844e348d36b5b35e1c50487a3bbc4.zip
ajax paging, some js cleanups
-rw-r--r--lib/private/search.php4
-rw-r--r--search/ajax/search.php2
-rw-r--r--search/css/results.css6
-rw-r--r--search/js/result.js211
-rw-r--r--search/js/search.js320
-rw-r--r--search/templates/part.results.html (renamed from search/templates/part.results.php)0
6 files changed, 300 insertions, 243 deletions
diff --git a/lib/private/search.php b/lib/private/search.php
index 4629d52b40e..22f92534cbd 100644
--- a/lib/private/search.php
+++ b/lib/private/search.php
@@ -64,8 +64,10 @@ class Search implements ISearch {
$providerResults = $provider->search($query);
if ($size > 0) {
$slicedResults = array_slice($providerResults, $page * $size, $size);
+ $results = array_merge($results, $slicedResults);
+ } else {
+ $results = array_merge($results, $providerResults);
}
- $results = array_merge($results, $slicedResults);
} else {
\OC::$server->getLogger()->warning('Ignoring Unknown search provider', array('provider' => $provider));
}
diff --git a/search/ajax/search.php b/search/ajax/search.php
index 90771084659..e26432d1eb2 100644
--- a/search/ajax/search.php
+++ b/search/ajax/search.php
@@ -46,7 +46,7 @@ if (isset($_GET['page'])) {
if (isset($_GET['size'])) {
$size = (int)$_GET['size'];
} else {
- $size = 0;
+ $size = 30;
}
if($query) {
$result = \OC::$server->getSearch()->search($query, $inApps, $page, $size);
diff --git a/search/css/results.css b/search/css/results.css
index 78b60e65e45..5dbfa2bd50e 100644
--- a/search/css/results.css
+++ b/search/css/results.css
@@ -14,6 +14,9 @@
box-sizing: border-box;
z-index:75;
}
+#searchresults * {
+ box-sizing: content-box;
+}
#searchresults table {
border-spacing:0;
@@ -23,6 +26,9 @@
}
#searchresults td {
+ padding: 0 15px;
+ font-style: normal;
+ vertical-align: middle;
border-top: 20px solid white;
border-bottom: none;
}
diff --git a/search/js/result.js b/search/js/result.js
index 95526749c53..217d66dc1e3 100644
--- a/search/js/result.js
+++ b/search/js/result.js
@@ -8,171 +8,76 @@
*
*/
-OC.Search.hide = function(){
- $('#searchresults').hide();
- if($('#searchbox').val().length>2){
- $('#searchbox').val('');
- if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
- FileList.unfilter();
- }
- };
- if ($('#searchbox').val().length === 0) {
- if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
- FileList.unfilter();
- }
- }
-};
-OC.Search.showResults = function(results){
- if(results.length === 0){
- return;
- }
- if (!OC.Search.showResults.loaded){
- var parent = $('<div class="searchresults-wrapper"/>');
- $('#app-content').append(parent);
- parent.load(OC.filePath('search','templates','part.results.php'),function(){
- OC.Search.showResults.loaded = true;
- $('#searchresults').click(function(event){
- OC.Search.hide();
- event.stopPropagation();
- });
- $(document).click(function(event){
- OC.Search.hide();
- if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
- FileList.unfilter();
- }
- });
- OC.Search.lastResults=results;
- OC.Search.showResults(results);
- });
- } else {
- $('#searchresults tr.result').remove();
- $('#searchresults').show();
- jQuery.each(results, function(i, result) {
- var $row = $('#searchresults tr.template').clone();
- $row.removeClass('template');
- $row.addClass('result');
+//FIXME move to files?
+$(document).ready(function() {
+ // wait for other apps/extensions to register their event handlers and file actions
+ // in the "ready" clause
+ _.defer(function() {
+ OC.Search.setFormatter('file', function ($row, result) {
+ // backward compatibility:
+ if (typeof result.mime !== 'undefined') {
+ result.mime_type = result.mime;
+ } else if (typeof result.mime_type !== 'undefined') {
+ result.mime = result.mime_type;
+ }
- $row.data('result', result);
+ $pathDiv = $('<div class="path"></div>').text(result.path);
+ $row.find('td.info div.name').after($pathDiv).text(result.name);
- // generic results only have four attributes
- $row.find('td.info div.name').text(result.name);
- $row.find('td.info a').attr('href', result.link);
+ $row.find('td.result a').attr('href', result.link);
- $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'places/link') + ')');
- /**
- * Give plugins the ability to customize the search results. For example:
- * OC.search.customResults.file = function (row, item){ FIXME
- * if(item.name.search('.json') >= 0) ...
- * };
- */
- if (OC.Search.hasFormatter(result.type)) {
- OC.Search.getFormatter(result.type)($row, result);
+ if (OCA.Files) {
+ OCA.Files.App.fileList.lazyLoadPreview({
+ path: result.path,
+ mime: result.mime,
+ callback: function (url) {
+ $row.find('td.icon').css('background-image', 'url(' + url + ')');
+ }
+ });
} else {
- // for backward compatibility add text div
- $row.find('td.info div.name').addClass('result')
- $row.find('td.result div.name').after('<div class="text"></div>');
- $row.find('td.result div.text').text(result.name);
- if(OC.search.customResults && OC.search.customResults[result.type]) {
- OC.search.customResults[result.type]($row, result);
+ // FIXME how to get mime icon if not in files app
+ var mimeicon = result.mime.replace('/', '-');
+ $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'filetypes/' + mimeicon) + ')');
+ var dir = OC.dirname(result.path);
+ if (dir === '') {
+ dir = '/';
}
+ $row.find('td.info a').attr('href',
+ OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', {dir: dir, scrollto: result.name})
+ );
}
- $('#searchresults tbody').append($row);
});
-
- $('#searchresults').on('click', 'tr.result', function (event) {
- var $row = $(this);
- var result = $row.data('result');
- if(OC.Search.hasHandler(result.type)){
- var result = OC.Search.getHandler(result.type)($row, result, event);
- OC.Search.hide();
- event.stopPropagation();
- return result;
+ OC.Search.setHandler('file', function ($row, result, event) {
+ if (OCA.Files) {
+ OCA.Files.App.fileList.changeDirectory(OC.dirname(result.path));
+ OCA.Files.App.fileList.scrollTo(result.name);
+ return false;
+ } else {
+ return true;
}
});
- }
-};
-OC.Search.showResults.loaded = false;
-OC.Search.renderCurrent = function(){
- var $resultsContainer = $('#searchresults');
- var result = $resultsContainer.find('tr.result')[OC.Search.currentResult]
- if (result) {
- var $result = $(result);
- var currentOffset = $resultsContainer.scrollTop();
- $resultsContainer.animate({
- // Scrolling to the top of the new result
- scrollTop: currentOffset + $result.offset().top - $result.height() * 2
- }, {
- duration: 100
- });
- $resultsContainer.find('tr.result.current').removeClass('current');
- $result.addClass('current');
- }
-};
-
-OC.Search.setFormatter('file', function ($row, result) {
- // backward compatibility:
- if (typeof result.mime !== 'undefined') {
- result.mime_type = result.mime;
- } else if (typeof result.mime_type !== 'undefined') {
- result.mime = result.mime_type;
- }
-
- $pathDiv = $('<div class="path"></div>').text(result.path);
- $row.find('td.info div.name').after($pathDiv).text(result.name);
+ OC.Search.setFormatter('folder', function ($row, result) {
+ // backward compatibility:
+ if (typeof result.mime !== 'undefined') {
+ result.mime_type = result.mime;
+ } else if (typeof result.mime_type !== 'undefined') {
+ result.mime = result.mime_type;
+ }
- $row.find('td.result a').attr('href', result.link);
+ var $pathDiv = $('<div class="path"></div>').text(result.path)
+ $row.find('td.info div.name').after($pathDiv).text(result.name);
- if (OCA.Files) {
- OCA.Files.App.fileList.lazyLoadPreview({
- path: result.path,
- mime: result.mime,
- callback: function (url) {
- $row.find('td.icon').css('background-image', 'url(' + url + ')');
+ $row.find('td.result a').attr('href', result.link);
+ $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'filetypes/folder') + ')');
+ });
+ OC.Search.setHandler('folder', function ($row, result, event) {
+ if (OCA.Files) {
+ OCA.Files.App.fileList.changeDirectory(result.path);
+ return false;
+ } else {
+ return true;
}
});
- } else {
- // FIXME how to get mime icon if not in files app
- var mimeicon = result.mime.replace('/','-');
- $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'filetypes/'+mimeicon) + ')');
- var dir = OC.dirname(result.path);
- if (dir === '') {
- dir = '/';
- }
- $row.find('td.info a').attr('href',
- OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', {dir:dir, scrollto:result.name})
- );
- }
-});
-OC.Search.setHandler('file', function ($row, result, event) {
- if (OCA.Files) {
- OCA.Files.App.fileList.changeDirectory(OC.dirname(result.path));
- OCA.Files.App.fileList.scrollTo(result.name);
- return false;
- } else {
- return true;
- }
-});
-
-OC.Search.setFormatter('folder', function ($row, result) {
- // backward compatibility:
- if (typeof result.mime !== 'undefined') {
- result.mime_type = result.mime;
- } else if (typeof result.mime_type !== 'undefined') {
- result.mime = result.mime_type;
- }
-
- var $pathDiv = $('<div class="path"></div>').text(result.path)
- $row.find('td.info div.name').after($pathDiv).text(result.name);
-
- $row.find('td.result a').attr('href', result.link);
- $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'filetypes/folder') + ')');
-});
-OC.Search.setHandler('folder', function ($row, result, event) {
- if (OCA.Files) {
- OCA.Files.App.fileList.changeDirectory(result.path);
- return false;
- } else {
- return true;
- }
+ });
});
diff --git a/search/js/search.js b/search/js/search.js
index 06a96fd582b..7a6428bce33 100644
--- a/search/js/search.js
+++ b/search/js/search.js
@@ -4,113 +4,257 @@
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright Bernhard Posselt 2014
+ * @author Jörn Friedrich Dreyer <jfd@owncloud.com>
+ * @copyright Jörn Friedrich Dreyer 2014
*/
-(function (exports) {
-
- 'use strict';
+(function () {
+ /**
+ * @class OCA.Search
+ * @classdesc
+ *
+ * The Search class manages a search queries and their results
+ *
+ * @param $searchBox container element with existing markup for the #searchbox form
+ */
+ var Search = function($searchBox) {
+ this.initialize($searchBox);
+ };
+ /**
+ * @memberof OC
+ */
+ Search.prototype = {
- exports.Search = {
- /**
- * contains closures that are called to format search results
- */
- formatter:{},
- setFormatter: function(type, formatter) {
- this.formatter[type] = formatter;
- },
- hasFormatter: function(type) {
- return typeof this.formatter[type] !== 'undefined';
- },
- getFormatter: function(type) {
- return this.formatter[type];
- },
- /**
- * contains closures that are called when a search result has been clicked
- */
- handler:{},
- setHandler: function(type, handler) {
- this.handler[type] = handler;
- },
- hasHandler: function(type) {
- return typeof this.handler[type] !== 'undefined';
- },
- getHandler: function(type) {
- return this.handler[type];
- },
- currentResult:-1,
- lastQuery:'',
- lastResults:{},
/**
- * Do a search query and display the results
- * @param {string} query the search query
+ * Initialize the search box and results
+ *
+ * @param $searchBox container element with existing markup for the #searchbox form
+ * @private
*/
- search: _.debounce(function(query, page, size) {
- if(query) {
- exports.addStyle('search','results');
- if (typeof page !== 'number') {
- page = 0;
+ initialize: function($searchBox) {
+
+ var that = this;
+
+ /**
+ * contains closures that are called to format search results
+ */
+ var formatters = {};
+ this.setFormatter = function(type, formatter) {
+ formatters[type] = formatter;
+ };
+ this.hasFormatter = function(type) {
+ return typeof formatters[type] !== 'undefined';
+ };
+ this.getFormatter = function(type) {
+ return formatters[type];
+ };
+
+ /**
+ * contains closures that are called when a search result has been clicked
+ */
+ var handlers = {};
+ this.setHandler = function(type, handler) {
+ handlers[type] = handler;
+ };
+ this.hasHandler = function(type) {
+ return typeof handlers[type] !== 'undefined';
+ };
+ this.getHandler = function(type) {
+ return handlers[type];
+ };
+
+ var currentResult = -1;
+ var lastQuery = '';
+ var lastPage = 0;
+ var lastSize = 30;
+ var lastResults = {};
+
+ /**
+ * Do a search query and display the results
+ * @param {string} query the search query
+ */
+ this.search = _.debounce(function(query, page, size) {
+ if(query) {
+ OC.addStyle('search','results');
+ if (typeof page !== 'number') {
+ page = 0;
+ }
+ if (typeof size !== 'number') {
+ size = 30;
+ }
+ // prevent double pages
+ if (query === lastPage && page === lastPage && currentResult !== -1) {
+ return;
+ }
+ $.getJSON(OC.generateUrl('search/ajax/search.php'), {query:query, page:page, size:size }, function(results) {
+ lastQuery = query;
+ lastPage = page;
+ lastSize = size;
+ lastResults = results;
+ if (page === 0) {
+ showResults(results);
+ } else {
+ addResults(results);
+ }
+ });
+ }
+ }, 500);
+ var $searchResults = false;
+
+ function showResults(results) {
+ if (results.length === 0) {
+ return;
}
- if (typeof size !== 'number') {
- size = 30;
+ if (!$searchResults) {
+ var $parent = $('<div class="searchresults-wrapper"/>');
+ $('#app-content').append($parent);
+ $parent.load(OC.webroot + '/search/templates/part.results.html', function () {
+ $searchResults = $parent.find('#searchresults');
+ $searchResults.click(function (event) {
+ that.hideResults();
+ event.stopPropagation();
+ });
+ $(document).click(function (event) {
+ that.hideResults();
+ if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
+ FileList.unfilter();
+ }
+ });
+ $searchResults.on('scroll', _.bind(onScroll, this));
+ lastResults = results;
+ showResults(results);
+ });
+ } else {
+ $searchResults.find('tr.result').remove();
+ $searchResults.show();
+ addResults(results);
}
- $.getJSON(OC.generateUrl('search/ajax/search.php'), {query:query, page:page, size:size }, function(results) {
- exports.Search.lastResults = results;
- exports.Search.showResults(results);
- });
}
- }, 500)
- };
+ function addResults(results) {
+ var $template = $searchResults.find('tr.template');
+ jQuery.each(results, function (i, result) {
+ var $row = $template.clone();
+ $row.removeClass('template');
+ $row.addClass('result');
+ $row.data('result', result);
- $(document).ready(function () {
- $('form.searchbox').submit(function(event) {
- event.preventDefault();
- });
- $('#searchbox').keyup(function(event) {
- if (event.keyCode === 13) { //enter
- if(exports.Search.currentResult > -1) {
- var result = $('#searchresults tr.result a')[exports.Search.currentResult];
- window.location = $(result).attr('href');
- }
- } else if(event.keyCode === 38) { //up
- if(exports.Search.currentResult > 0) {
- exports.Search.currentResult--;
- exports.Search.renderCurrent();
+ // generic results only have four attributes
+ $row.find('td.info div.name').text(result.name);
+ $row.find('td.info a').attr('href', result.link);
+ $row.find('td.icon').css('background-image', 'url(' + OC.imagePath('core', 'places/link') + ')');
+ /**
+ * Give plugins the ability to customize the search results. see result.js for examples
+ */
+ if (that.hasFormatter(result.type)) {
+ that.getFormatter(result.type)($row, result);
+ } else {
+ // for backward compatibility add text div
+ $row.find('td.info div.name').addClass('result');
+ $row.find('td.result div.name').after('<div class="text"></div>');
+ $row.find('td.result div.text').text(result.name);
+ if (OC.search.customResults && OC.search.customResults[result.type]) {
+ OC.search.customResults[result.type]($row, result);
+ }
+ }
+ $searchResults.find('tbody').append($row);
+ });
+ }
+ function renderCurrent() {
+ var result = $searchResults.find('tr.result')[currentResult];
+ if (result) {
+ var $result = $(result);
+ var currentOffset = $searchResults.scrollTop();
+ $searchResults.animate({
+ // Scrolling to the top of the new result
+ scrollTop: currentOffset + $result.offset().top - $result.height() * 2
+ }, {
+ duration: 100
+ });
+ $searchResults.find('tr.result.current').removeClass('current');
+ $result.addClass('current');
}
- } else if(event.keyCode === 40) { //down
- if(exports.Search.lastResults.length > exports.Search.currentResult + 1){
- exports.Search.currentResult++;
- exports.Search.renderCurrent();
- }
- } else if(event.keyCode === 27) { //esc
- exports.Search.hide();
- if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
- FileList.unfilter();
+ }
+ this.hideResults = function() {
+ if ($searchResults) {
+ $searchResults.hide();
+ if ($searchBox.val().length > 2) {
+ $searchBox.val('');
+ if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
+ FileList.unfilter();
+ }
+ }
+ if ($searchBox.val().length === 0) {
+ if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
+ FileList.unfilter();
+ }
+ }
}
- } else {
- var query = $('#searchbox').val();
- if (exports.Search.lastQuery !== query) {
- exports.Search.lastQuery = query;
- exports.Search.currentResult = -1;
- if (FileList && typeof FileList.filter === 'function') { //TODO add hook system
- FileList.filter(query);
+ };
+
+ $searchBox.keyup(function(event) {
+ if (event.keyCode === 13) { //enter
+ if(currentResult > -1) {
+ var result = $searchResults.find('tr.result a')[currentResult];
+ window.location = $(result).attr('href');
}
- if (query.length > 2) {
- exports.Search.search(query);
- } else {
- if (exports.Search.hide) {
- exports.Search.hide();
+ } else if(event.keyCode === 38) { //up
+ if(currentResult > 0) {
+ currentResult--;
+ renderCurrent();
+
+ }
+ } else if(event.keyCode === 40) { //down
+ if(lastResults.length > currentResult + 1){
+ currentResult++;
+ renderCurrent();
+ }
+ } else if(event.keyCode === 27) { //esc
+ that.hideResults();
+ if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
+ FileList.unfilter();
+ }
+ } else {
+ var query = $searchBox.val();
+ if (lastQuery !== query) {
+ lastQuery = query;
+ currentResult = -1;
+ if (FileList && typeof FileList.filter === 'function') { //TODO add hook system
+ FileList.filter(query);
+ }
+ if (query.length > 2) {
+ that.search(query);
+ } else {
+ if (that.hideResults) {
+ that.hideResults();
+ }
}
}
}
+ });
+
+ /**
+ * Event handler for when scrolling the list container.
+ * This appends/renders the next page of entries when reaching the bottom.
+ */
+ function onScroll(e) {
+ if ( $searchResults.scrollTop() + $searchResults.height() > $searchResults.find('table').height() - 300 ) {
+ that.search(lastQuery, lastPage + 1);
+ }
}
- });
- });
-}(OC));
+ $('form.searchbox').submit(function(event) {
+ event.preventDefault();
+ });
+ }
+ };
+ OCA.Search = Search;
+})();
+
+$(document).ready(function() {
+ OC.Search = new OCA.Search($('#searchbox'));
+});
/**
* @deprecated use get/setFormatter() instead
diff --git a/search/templates/part.results.php b/search/templates/part.results.html
index 451df7b143f..451df7b143f 100644
--- a/search/templates/part.results.php
+++ b/search/templates/part.results.html