').addClass('ins-slug').text(slug) : null))
+ .append(preview ? $('').addClass('ins-search-preview').text(preview) : null)
+ .attr('data-url', url);
+ }
+
+ function sectionFactory (type, array) {
+ var sectionTitle;
+ var $searchItems;
+ if (array.length == 0) return null;
+ sectionTitle = CONFIG.TRANSLATION[type];
+ switch (type) {
+ case 'POSTS':
+ case 'PAGES':
+ $searchItems = array.map(function (item) {
+ // Use config.root instead of permalink to fix url issue
+ return searchItem('file', item.title, null, item.text.slice(0, 150), CONFIG.ROOT_URL + item.path);
+ });
+ break;
+ case 'CATEGORIES':
+ case 'TAGS':
+ $searchItems = array.map(function (item) {
+ return searchItem(type == 'CATEGORIES' ? 'folder' : 'tag', item.name, item.slug, null, item.permalink);
+ });
+ break;
+ default:
+ return null;
+ }
+ return section(sectionTitle).append($searchItems);
+ }
+
+ function extractToSet (json, key) {
+ var values = {};
+ var entries = json.pages.concat(json.posts);
+ entries.forEach(function (entry) {
+ if (entry[key]) {
+ entry[key].forEach(function (value) {
+ values[value.name] = value;
+ });
+ }
+ });
+ var result = [];
+ for (var key in values) {
+ result.push(values[key]);
+ }
+ return result;
+ }
+
+ function parseKeywords (keywords) {
+ return keywords.split(' ').filter(function (keyword) {
+ return !!keyword;
+ }).map(function (keyword) {
+ return keyword.toUpperCase();
+ });
+ }
+
+ /**
+ * Judge if a given post/page/category/tag contains all of the keywords.
+ * @param Object obj Object to be weighted
+ * @param Array fields Object's fields to find matches
+ */
+ function filter (keywords, obj, fields) {
+ var result = false;
+ var keywordArray = parseKeywords(keywords);
+ var containKeywords = keywordArray.filter(function (keyword) {
+ var containFields = fields.filter(function (field) {
+ if (!obj.hasOwnProperty(field))
+ return false;
+ if (obj[field].toUpperCase().indexOf(keyword) > -1)
+ return true;
+ });
+ if (containFields.length > 0)
+ return true;
+ return false;
+ });
+ return containKeywords.length == keywordArray.length;
+ }
+
+ function filterFactory (keywords) {
+ return {
+ POST: function (obj) {
+ return filter(keywords, obj, ['title', 'text']);
+ },
+ PAGE: function (obj) {
+ return filter(keywords, obj, ['title', 'text']);
+ },
+ CATEGORY: function (obj) {
+ return filter(keywords, obj, ['name', 'slug']);
+ },
+ TAG: function (obj) {
+ return filter(keywords, obj, ['name', 'slug']);
+ }
+ };
+ }
+
+ /**
+ * Calculate the weight of a matched post/page/category/tag.
+ * @param Object obj Object to be weighted
+ * @param Array fields Object's fields to find matches
+ * @param Array weights Weight of every field
+ */
+ function weight (keywords, obj, fields, weights) {
+ var value = 0;
+ parseKeywords(keywords).forEach(function (keyword) {
+ var pattern = new RegExp(keyword, 'img'); // Global, Multi-line, Case-insensitive
+ fields.forEach(function (field, index) {
+ if (obj.hasOwnProperty(field)) {
+ var matches = obj[field].match(pattern);
+ value += matches ? matches.length * weights[index] : 0;
+ }
+ });
+ });
+ return value;
+ }
+
+ function weightFactory (keywords) {
+ return {
+ POST: function (obj) {
+ return weight(keywords, obj, ['title', 'text'], [3, 1]);
+ },
+ PAGE: function (obj) {
+ return weight(keywords, obj, ['title', 'text'], [3, 1]);
+ },
+ CATEGORY: function (obj) {
+ return weight(keywords, obj, ['name', 'slug'], [1, 1]);
+ },
+ TAG: function (obj) {
+ return weight(keywords, obj, ['name', 'slug'], [1, 1]);
+ }
+ };
+ }
+
+ function search (json, keywords) {
+ var WEIGHTS = weightFactory(keywords);
+ var FILTERS = filterFactory(keywords);
+ var posts = json.posts;
+ var pages = json.pages;
+ var tags = extractToSet(json, 'tags');
+ var categories = extractToSet(json, 'categories');
+ return {
+ posts: posts.filter(FILTERS.POST).sort(function (a, b) { return WEIGHTS.POST(b) - WEIGHTS.POST(a); }).slice(0, 5),
+ pages: pages.filter(FILTERS.PAGE).sort(function (a, b) { return WEIGHTS.PAGE(b) - WEIGHTS.PAGE(a); }).slice(0, 5),
+ categories: categories.filter(FILTERS.CATEGORY).sort(function (a, b) { return WEIGHTS.CATEGORY(b) - WEIGHTS.CATEGORY(a); }).slice(0, 5),
+ tags: tags.filter(FILTERS.TAG).sort(function (a, b) { return WEIGHTS.TAG(b) - WEIGHTS.TAG(a); }).slice(0, 5)
+ };
+ }
+
+ function searchResultToDOM (searchResult) {
+ $container.empty();
+ for (var key in searchResult) {
+ $container.append(sectionFactory(key.toUpperCase(), searchResult[key]));
+ }
+ }
+
+ $.getJSON(CONFIG.CONTENT_URL, function (json) {
+ if (location.hash.trim() == '#ins-search') {
+ $main.addClass('show');
+ }
+ $('.ins-search-input').on('input', function () {
+ var keywords = $(this).val();
+ searchResultToDOM(search(json, keywords));
+ });
+ $('.ins-search-input').trigger('input');
+ });
+})(jQuery, window.INSIGHT_CONFIG);
\ No newline at end of file