/** * amWiki Web端 - 全库搜索模块 * @author Tevin */ ; (function (win) { 'use strict'; /** * 全局搜索 * @param {Storage} _storage * @constructor */ var Search = function (_storage) { this._storage = _storage; this.$e = { //显示搜索面板按钮 searchShow: $('#searchShow'), //更新全部缓存按钮 searchUpdate: this._storage.$e.searchUpdate, //搜索面板 searchBox: $('#searchBox'), //搜索结果列表 results: $('#results'), //搜索结果信息提示 resultMsg: $('#resultMsg'), //搜素结果显示更多 resultMore: $('#resultMore'), //搜索按钮 search: $('#search'), //搜索文本 searchText: $('#searchText') }; this._data = { //搜素结果 result: [], //单条结果的模板 template: $('#template\\:searchResult').text(), //每页结果数 pageSize: 15, //当前页码 pagination: 0 }; this._bindCtrl(); //用户执行重建缓存的回调 this.onNeedRebuildStorage = null; }; /** * 绑定用户操作 * @private */ Search.prototype._bindCtrl = function () { var that = this; //展开折叠搜索面板 this.$e.searchShow.on('click', function () { if (that.$e.searchBox.hasClass('on')) { that.displayBox('off'); that.$e.searchShow.trigger('searchoff'); } else { that.displayBox('on', function () { resetResHeight(); }); that.$e.searchShow.trigger('searchon'); } }); //设置结果区域高度 var resetResHeight = function () { var hOut = that.$e.searchBox.height(); var dt = that.$e.results.offset().top - that.$e.searchUpdate.offset().top; that.$e.results.height(hOut - dt); }; $(win).on('resize', function () { if (that.$e.searchBox.hasClass('on')) { resetResHeight(); } }); //当本地浏览且存在页面挂载数据时,隐藏重建缓存按钮 if (location.protocol == 'file:' && typeof AWPageMounts != 'undefined') { this.$e.searchUpdate.parent().addClass('off'); } //重建缓存 this.$e.searchUpdate.on('click', function () { //开启重建缓存时,如果存在搜索子进程,则干掉子进程 if (that._worker) { that._worker.terminate(); that._worker = null; that.$e.resultMsg.hide(); } that.$e.search.prop('disabled', true); that.$e.searchUpdate.prop('disabled', true); that.onNeedRebuildStorage(function () { that.$e.search.prop('disabled', false); that.$e.searchUpdate.val('请勿频繁使用'); }); }); //更新全部缓存按钮使用的时间限制:一小时内不允许重复使用 var lastBuild = this._storage.getLastBuildTs(); if (lastBuild) { var lave = Date.now() - lastBuild; if (lave < 60 * 60 * 1000) { this.$e.searchUpdate.prop('disabled', true).val('请勿频繁使用'); } } //点击搜索 this.$e.search.on('click', function () { that._search(); }); this.$e.searchText.on('keyup', function (e) { if (e.keyCode == 13) { that._search(); } }); //结果翻页 this.$e.resultMore.on('click', function () { that._nextResultPage(); }); }; /** * 显示隐藏搜索面板 * @param {String} type - on 显示 / off 隐藏 * @param {Function} callback * @public */ Search.prototype.displayBox = function (type, callback) { var that = this; var $box = this.$e.searchBox; if (type == 'on' && !$box.hasClass('on')) { $box .addClass('on') .css({ 'display': 'block', 'width': '0', 'opacity': 0 }) .animate({ 'width': '100%', 'opacity': 1 }, 300, 'swing', function () { callback && callback(); }); } else if (type == 'off' && $box.hasClass('on')) { $box .removeClass('on') .animate({ 'width': '30%', 'opacity': 0 }, 200, 'swing', function () { $box.removeAttr('style'); callback && callback(); }); } }; /** * 启动搜素 * @private */ Search.prototype._search = function () { var that = this; if (this.$e.searchText.val() == '') { this.$e.searchText.focus(); return; } var words = this.$e.searchText.val(); this.$e.resultMsg.show().text('创建搜索中...'); if (typeof win.Worker !== "undefined") { //开启一次新搜索时,如果存在搜索子进程,则干掉子进程 if (this._worker) { this._worker.terminate(); this._worker = null; this.$e.resultMsg.hide(); } try { //创建搜素子进程搜素 this._worker = new win.Worker('amWiki/js/amWiki.search.worker.js'); this._searchByWorker(words); } catch (e) { //在当前环境搜索 this._searchByPresent(words); } } else { //在当前环境搜索 this._searchByPresent(words); } }; /** * 搜索子进程通讯 * @param {String} words * @private */ Search.prototype._searchByWorker = function (words) { var that = this; //收到子进程搜素消息 this._worker.onmessage = function (event) { var data = event.data; //加载成功后发送文档数据 if (data.type == 'searcher:loaded') { that._worker.postMessage({type: 'searcher:docs', docs: that._storage.getAllDocs()}); } //文档预处理完成后开始搜索 else if (data.type == 'searcher:ready') { that.$e.resultMsg.show().html('正在搜索,请稍后...'); that._worker.postMessage({type: 'searcher:search', words: words}); } //搜索结果排行 else if (data.type == 'searcher:result') { that._data.result = data.result; that._showResultList(); that._worker.terminate(); that._worker = null; } }; //子进程出错 this._worker.onerror = function (e) { console.error(e); this.$e.resultMsg.show().text('Sorry,出错了!
' + e.msg); that._worker.terminate(); that._worker = null; }; }; /** * 在当前环境搜索 * @param {String} words * @private */ Search.prototype._searchByPresent = function (words) { var searcher = new AWSearcher(); searcher.initDocs(this._storage.getAllDocs()); this.$e.resultMsg.show().html('正在搜索,请稍后...'); searcher.matchWords(words); this._data.result = searcher.getResult(); this._showResultList(); }; /** * 显示结果列表 * @private */ Search.prototype._showResultList = function () { this.$e.results.children('ul').children().remove(); this.$e.resultMsg.hide(); this._data.pagination = 0; this._nextResultPage(); }; /** * 显示结果列表下一页 * @private */ Search.prototype._nextResultPage = function () { var html = ''; var count = 0; for (var i = this._data.pagination * this._data.pageSize, item; item = this._data.result[i]; i++) { html += this._renderRankItem(this._data.template, item); //超过页码跳出 if (++count >= this._data.pageSize) { break; } } this.$e.results.children('ul').append(html); this._data.pagination++; //如果还有结果没显示完,显示显示更多按钮 if (this._data.pagination * this._data.pageSize >= this._data.result.length) { this.$e.resultMore.hide(); } else { this.$e.resultMore.show(); } }; /** * 渲染单条模板 * @param {String} template * @param {Object} data * @returns {String} * @private */ Search.prototype._renderRankItem = function (template, data) { var tmpl = template; data.time = win.tools.formatTime(data.timestamp); delete data.timestamp; for (var p in data) { if (data.hasOwnProperty(p)) { tmpl = tmpl.replace(new RegExp('{{' + p + '}}', 'g'), data[p]); } } return tmpl; }; return win.AWSearch = Search; })(window);