UNPKG

isomorphic-search

Version:
725 lines (602 loc) 22.7 kB
var Search = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.l = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/Users/luzmcosta/Documents/development/isomorphic-search/build"; /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 3); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports, __webpack_require__(1), __webpack_require__(2)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else if (typeof exports !== "undefined") { factory(exports, require('./abstraction'), require('./presentation')); } else { var mod = { exports: {} }; factory(mod.exports, global.abstraction, global.presentation); global.control = mod.exports; } })(this, function (exports, _abstraction, _presentation) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _abstraction2 = _interopRequireDefault(_abstraction); var _presentation2 = _interopRequireDefault(_presentation); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Search agent's control. */ var control = { constructor: function constructor() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // Configure. this.abstraction = Object.assign(_abstraction2.default, options); this.presentation = _presentation2.default; // Run. this.set(data); // Enable chaining. return this; }, engine: function engine(_engine, data, options) { // Notify if search engine has not been set. if (!_engine) { return this.abstraction.notify(this.abstraction.messages.engine); } // Instantiate. if (typeof _engine === 'function') { _engine = new _engine(data, options); } // Get search method. if (_engine.search && typeof _engine.search === 'function') { _engine = _engine.search.bind(_engine); } // Save instantiated engine to abstraction. this.abstraction.search = _engine; return _engine; }, onSearch: function onSearch() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var search = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var engine = arguments[2]; var results = engine(search); this.presentation.renderSearchResults(results, this.abstraction); return results; }, execute: function execute(abstraction, data, engine) { var $el = abstraction.$el, attr = abstraction.attr, $input = $el.input, search = $input.val(), hiddenClass = attr.hidden, eachResult = $el.result; // Handle empty search value. if (!search) { // Show all possible results. eachResult.removeClass(hiddenClass); return search; } // Initiate search for user input. this.onSearch(data, search, engine); return search; }, set: function set(data) { var model = this.abstraction, valid = model.validate(data); if (valid !== true) { return this.abstraction.notify(valid); } // Render form and bind events to it. this.renderForm(data); // Render results. this.renderResults(model, data); return data; }, renderForm: function renderForm(data) { var model = this.abstraction, $parent = model.$el.parent, form = model.template.form, engine = this.engine(model.engine, data, model.options), metadata = model.metadata, callback = metadata && metadata.form && metadata.form.callback ? metadata.form.callback : this.execute.bind(this); // Render form. this.presentation.render($parent, form(model), { action: 'prepend' }); // Bind events to view. this.presentation.bind(model, data, engine, callback); return true; }, renderResults: function renderResults(model, data) { var _this = this; var $el = model.$el, metadata = model.metadata, template = model.template, callback = metadata && metadata.result ? metadata.result.callback : false; // Render results view. this.presentation.render($el.container, template.results(model), { action: 'append' }); // Get results list. var resultsList = model.$el.resultsList; // Render each potential result. data.forEach(function (datum) { // Render. _this.presentation.render(resultsList, template.list(datum, model), { action: 'append' }); // Execute callback on this list item. if (callback) { callback(datum); } }); } }; exports.default = control; }); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else if (typeof exports !== "undefined") { factory(exports); } else { var mod = { exports: {} }; factory(mod.exports); global.abstraction = mod.exports; } })(this, function (exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); /** * Search module's abstraction */ var identifier = 'id'; var label = 'name'; var abstraction = { // Set the identifying property among the objects in the list. identifier: identifier, // Set the labeling property among the objects in the list. label: label, // The notification system used when set-up fails. See control.set method. notify: console ? console.log : function (error) { return error; }, // Set default parent selector. parent: 'header', // Empowers searching by representing the current search criteria. searchBy: false, // Threshold for error when matching search to potential results. threshold: 0.2, // Search parameters. keys: [{ name: identifier, weight: 0.3 }, { name: label, weight: 0.7 }], // Represents icon classes. icon: { search: 'fa-search', cancel: 'fa-close' }, // Options passed to the search engine. set options(options) { var existing = Object.create(this._options || null); delete this._options; this._options = Object.assign(existing, options); }, get options() { return this._options = Object.assign({ keys: this.keys, threshold: this.threshold }, this._options); }, // Classes and other identifiers to be attached to elements. set attr(attr) { var existing = Object.create(this._attr || null); delete this._attr; this._attr = Object.assign(existing, attr); }, get attr() { // @TODO Abstract. var defaults = { body: 'body', container: 'search', parent: this.parent, input: 'search-field', hidden: 'invisible', instructions: 'instructions', menu: 'search-menu', noResults: 'no-results', result: 'result', results: 'search-results', resultsList: 'search-results-list', searchFieldContainer: 'search-field-container', searchContainer: 'search-container', submit: 'search-submit', title: 'search-title' }; return this._attr = Object.assign(defaults, this._attr || null); }, // Elements set el(element) { var existing = Object.create(this._el || null); delete this._el; this._el = Object.assign(existing, element); }, get el() { var existing = this._el, elements = this.attr, _el = {}; Object.keys(elements).forEach(function (el) { if (el === 'parent' || el === 'body') { _el[el] = elements[el]; } else { _el[el] = '.' + elements[el]; } }); return this._el = _el; }, // DOM Nodes set $el(element) { var existing = Object.create(this._$el || null); delete this._$el; this._$el = Object.assign(existing, element); }, get $el() { var existing = this._$el, el = this.el, _$el = {}; Object.keys(el).forEach(function (element) { var isWrapper = ['body', 'container', 'parent'].indexOf(element) !== -1; if (!isWrapper) { _$el[element] = $(el.container).find(el[element]); } else { _$el[element] = $(el[element]); } }); return this._$el = _$el; }, validate: function validate(data) { if (!data) { return this.messages.unavailable; } if (!data.length) { return this.messages.empty; } return true; }, // Errors messages: { empty: { message: 'The search list is empty.', name: 'empty', type: 'warn' }, engine: { message: 'The search feature requires an engine.', name: 'engine', type: 'warn' }, noResults: { message: 'Your search returned no results.', name: 'no results', type: 'info' }, unavailable: { message: 'The search list is unavailable.', name: 'unavailable', type: 'warn' } }, // Metadata event default method. metadataCallback: function metadataCallback(event, search) { return { event: event, search: search }; }, // Elements' metadata set metadata(metadata) { var existing = Object.create(this._metadata || null); delete this._metadata; this._metadata = Object.assign(existing, metadata); }, get metadata() { var defaults = { input: { placeholder: 'Search', cancel: this.metadataCallback, change: this.metadataCallback, focus: this.metadataCallback }, results: { instructions: 'Choose from the list.' } }; return this._metadata = Object.assign(defaults, this._metadata || null); }, // Templates. template: { error: function error(_ref) { var attr = _ref.attr; return '<div class="' + attr.noResults + '">\n We found no results matching your search.\n </div>'; }, form: function form(_ref2) { var icon = _ref2.icon, attr = _ref2.attr, placeholder = _ref2.metadata.input.placeholder; return '<div class="' + attr.container + '">\n <div class="' + attr.searchFieldContainer + '">\n <input class="' + attr.input + '" placeholder="' + placeholder + '" type="text" />\n <div class="' + attr.menu + '">\n <i class="' + attr.submit + ' fa ' + icon.search + '"></i>\n </div>\n </div>\n </div>'; }, header: function header(title) { return '<h1>' + title + '</h1>'; }, // @TODO Compute `id` & `name` from `this.label` & `this.identifier`. list: function list(_ref3, _ref4) { var id = _ref3.id, name = _ref3.name; var attr = _ref4.attr; return '<li class="' + attr.result + '" data-id="' + id + '" data-name="' + name + '">\n ' + name + '\n </li>'; }, noResults: function noResults(_ref5) { var attr = _ref5.attr, messages = _ref5.messages; return '<div class="' + attr.noResults + '">' + messages.noResults.message + '</div>'; }, result: function result(_ref6) { var attr = _ref6.attr; return '<div class="' + attr.hidden + ' ' + attr.searchResults + '"></div>'; }, results: function results(_ref7) { var attr = _ref7.attr, metadata = _ref7.metadata; var _metadata$results = metadata.results, className = _metadata$results.className, instructions = _metadata$results.instructions, title = _metadata$results.title; return '<div class="' + attr.results + ' ' + attr.hidden + '">\n ' + (title ? '<div class="' + attr.title + '">' + title + '</div>' : '') + '\n ' + (instructions ? '<div class="' + attr.instructions + '">' + instructions + '</div>' : '') + '\n <ul class="' + className + ' ' + attr.resultsList + '"></ul>\n </div>'; } } }; exports.default = abstraction; }); /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else if (typeof exports !== "undefined") { factory(exports); } else { var mod = { exports: {} }; factory(mod.exports); global.presentation = mod.exports; } })(this, function (exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); /** * Client-side */ var presentation = { insertAt: function insertAt($container, action, index, content) { var siblings = $container.children(); if (siblings.length) { return siblings.eq(index).after(content); } return $container[action](content); }, render: function render($container, content, _ref) { var _ref$action = _ref.action, action = _ref$action === undefined ? 'append' : _ref$action, _ref$index = _ref.index, index = _ref$index === undefined ? false : _ref$index; if (!index && index !== 0) { $container[action](content); } else { this.insertAt($container, content, { action: action, index: index }); } return; }, renderSearchResults: function renderSearchResults(results, abstraction) { // Reset view. abstraction.$el.noResults.remove(); // Get elements. var $el = abstraction.$el, el = abstraction.el, attr = abstraction.attr, identifier = abstraction.identifier, template = abstraction.template, hiddenClass = attr.hidden, $results = $el.results, $resultsList = $el.resultsList, $li = $el.result, li = el.result; // Empty view before rendering results only. $li.addClass(hiddenClass); if (!results || !results.length) { $resultsList.prepend(template.noResults(abstraction)); return results; } results.forEach(function (result) { // Display matching search result. $results.find(li + '[data-' + identifier + '="' + result[identifier] + '"]').removeClass(hiddenClass); }); return results; }, search: { // Cancel search. cancel: function cancel(event, _ref2) { var attr = _ref2.attr, $el = _ref2.$el, icon = _ref2.icon, metadata = _ref2.metadata; var cancelClass = icon.cancel, hiddenClass = attr.hidden, iconClasses = cancelClass + ' ' + icon.search, input = metadata.input, search = $el.input.val(); // Reset value of search field. $el.input.val(''); // Remove no results view. $el.noResults.remove(); // Hide results from view. $el.results.addClass(hiddenClass); // Reveal individual results so they'll be exposed with container. $el.result.removeClass(hiddenClass); // Toggle from cancel button to search button. $el.container.find('.' + cancelClass).toggleClass(iconClasses); // Execute callback. if (input && input.cancel && input.cancel.callback) { input.cancel.callback(event, search); } }, // Update input. // @TODO Review change method. change: function change(event, abstraction, data, engine, searchCallback) { var input = abstraction.metadata.input; // Execute search. var search = searchCallback(abstraction, data, engine); // Execute callback on change. if (input && input.change && input.change.callback) { input.change.callback(event, search); } }, // Focus on input. focus: function focus(event, abstraction) { var $el = abstraction.$el, attr = abstraction.attr, icon = abstraction.icon, template = abstraction.template, metadata = abstraction.metadata, input = metadata.input, hiddenClass = attr.hidden, search = $el.input.val(); // Replace the search icon with the cancel icon. $el.submit.removeClass(icon.search).addClass(icon.cancel); // Display all potential results. $el.results.removeClass(hiddenClass); // Execute callback. if (input && input.focus && input.focus.callback) { input.focus.callback(event, search); } return true; } }, bind: function bind(abstraction, data, engine, onChangeCallback) { var _this = this; var attr = abstraction.attr, $el = abstraction.$el, icon = abstraction.icon; // Set events on search input. $el.input.off().on('focus', function (event) { _this.search.focus(event, abstraction); }).on('keyup, paste, input', function (event) { _this.search.change(event, abstraction, data, engine, onChangeCallback); }); $el.menu.off(). // Set events on search icon. on('click', '.' + icon.search, function (event) { _this.search.focus(event, abstraction); }). // Set events on cancel icon. on('click', '.' + icon.cancel, function (event) { _this.search.cancel(event, abstraction); }); } }; exports.default = presentation; }); /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [module, __webpack_require__(0)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else if (typeof exports !== "undefined") { factory(module, require('./agent/control')); } else { var mod = { exports: {} }; factory(mod, global.control); global.searchBrowser = mod.exports; } })(this, function (module, _control) { 'use strict'; var _control2 = _interopRequireDefault(_control); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } module.exports = _control2.default; }); /***/ }) /******/ ]);