isomorphic-search
Version:
A configurable search interface.
253 lines (222 loc) • 7.55 kB
JavaScript
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['exports'], factory);
} 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;
});