class Influencer { constructor(options) { this._limit = options.limit; this._parseQuery = options.parseQuery; } addItem() {} getSuggestions() {} _addSearchPrefix(items, query) { const searchPrefix = this._getSearchPrefix(query); return items.map(s => (searchPrefix ? searchPrefix + s : s)); } _getSearchPrefix(query) { const { isSearch, key, split } = this._parseQuery(query); return isSearch ? `${key}${split} ` : false; } } class DefaultInfluencer extends Influencer { constructor({ defaultSuggestions }) { super(...arguments); this._defaultSuggestions = defaultSuggestions; } getSuggestions(query) { return new Promise(resolve => { const suggestions = this._defaultSuggestions[query]; resolve(suggestions ? suggestions.slice(0, this._limit) : []); }); } } class CommandsInfluencer extends Influencer { constructor({ commands, queryParser }) { super(...arguments); this._commands = commands; } getSuggestions(rawQuery) { const { query } = this._parseQuery(rawQuery); if (!query) return Promise.resolve([]); return new Promise(resolve => { const suggestions = []; const commands = this._commands; commands.forEach(command => { if(this._getDomain(command.url).startsWith(rawQuery)){ suggestions.push(command.url); } }); resolve(suggestions); }); } _getHostName(url) { let match = url.match(/:\/\/(www[0-9]?\.)?(.[^/:]+)/i); if (match != null && match.length > 2 && typeof match[2] === 'string' && match[2].length > 0) { return match[2]; } else { return null; } } _getDomain(url){ let hostName = this._getHostName(url); let domain = hostName; if (hostName != null) { let parts = hostName.split('.').reverse(); if (parts != null && parts.length > 1) { domain = parts[1] + '.' + parts[0]; if (hostName.toLowerCase().indexOf('.co.uk') != -1 && parts.length > 2) { domain = parts[2] + '.' + domain; } } } return domain; } } class DuckDuckGoInfluencer extends Influencer { constructor({ queryParser }) { super(...arguments); } getSuggestions(rawQuery) { const { query } = this._parseQuery(rawQuery); if (!query) return Promise.resolve([]); return new Promise(resolve => { const endpoint = 'https://duckduckgo.com/ac/'; const callback = 'autocompleteCallback'; window[callback] = res => { const suggestions = res .map(i => i.phrase) .filter(s => !$.ieq(s, query)) .slice(0, this._limit); resolve(this._addSearchPrefix(suggestions, rawQuery)); }; $.jsonp(`${endpoint}?callback=${callback}&q=${query}`); }); } } class HistoryInfluencer extends Influencer { constructor() { super(...arguments); this._storeName = 'history'; } addItem(query) { if (query.length < 2) return; let exists; const history = this._getHistory().map(([item, count]) => { const match = $.ieq(item, query); if (match) exists = true; return [item, match ? count + 1 : count]; }); if (!exists) history.push([query, 1]); const sorted = history .sort((current, next) => current[1] - next[1]) .reverse(); this._setHistory(sorted); } getSuggestions(query) { return new Promise(resolve => { const suggestions = this._getHistory() .map(([item]) => item) .filter(item => query && !$.ieq(item, query) && $.iin(item, query)) .slice(0, this._limit); resolve(suggestions); }); } _fetch() { return JSON.parse(localStorage.getItem(this._storeName)) || []; } _getHistory() { this._history = this._history || this._fetch(); return this._history; } _save(history) { localStorage.setItem(this._storeName, JSON.stringify(history)); } _setHistory(history) { this._history = history; this._save(history); } }