startpage/js/influencers.js
2020-07-31 11:25:34 +03:00

168 lines
4.0 KiB
JavaScript

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);
}
}