small changes + fix from #18

This commit is contained in:
Cade Scroggins
2018-10-09 12:15:49 -07:00
parent 692d8a3041
commit 380d9d92d1
2 changed files with 95 additions and 113 deletions
+18 -10
View File
@@ -8,9 +8,9 @@ Inspired by [/r/startpages](https://www.reddit.com/r/startpages)—the idea is t
To go to a site, enter the corresponding key. To view the available sites and their keys, press `?`. If your input doesn't match any of the commands, a generic Google search will be triggered. For example: To go to a site, enter the corresponding key. To view the available sites and their keys, press `?`. If your input doesn't match any of the commands, a generic Google search will be triggered. For example:
* Entering `r` would redirect you to [www.reddit.com](https://www.reddit.com). - Entering `r` would redirect you to [www.reddit.com](https://www.reddit.com).
* Entering `t` would redirect you to [twitch.tv](https://www.twitch.tv). - Entering `t` would redirect you to [twitch.tv](https://www.twitch.tv).
* Entering `cats` would search [Google for cats](https://encrypted.google.com/search?q=cats). - Entering `cats` would search [Google for cats](https://encrypted.google.com/search?q=cats).
On mobile, you can click the clock to focus the search input. On mobile, you can click the clock to focus the search input.
@@ -18,26 +18,34 @@ On mobile, you can click the clock to focus the search input.
You can search any of the sites by typing a colon after the site's key, followed by your search query. For example: You can search any of the sites by typing a colon after the site's key, followed by your search query. For example:
* Entering `g:tilde` would search [GitHub for tilde](https://github.com/search?q=tilde). - Entering `g:tilde` would search [GitHub for tilde](https://github.com/search?q=tilde).
* Entering `s:radiohead` would search [SoundCloud for radiohead](https://soundcloud.com/search?q=radiohead). - Entering `s:radiohead` would search [SoundCloud for radiohead](https://soundcloud.com/search?q=radiohead).
### Specific Locations ### Specific Locations
You can go to a specific location on a site by typing a forward slash after the site's key, followed by the location on the site you'd like to be redirected to. For example: You can go to a specific location on a site by typing a forward slash after the site's key, followed by the location on the site you'd like to be redirected to. For example:
* Entering `r/r/startpages` would redirect you to [www.reddit.com/r/startpages](https://www.reddit.com/r/startpages) - Entering `r/r/startpages` would redirect you to [www.reddit.com/r/startpages](https://www.reddit.com/r/startpages)
* Entering `h/popular` would redirect you to [hypem.com/popular](http://hypem.com/popular). - Entering `h/popular` would redirect you to [hypem.com/popular](http://hypem.com/popular).
### URL Redirects ### URL Redirects
If you enter in a full domain or URL, you will be redirected to said domain or URL. For example: If you enter in a full domain or URL, you will be redirected to said domain or URL. For example:
* Entering `stallman.org` would redirect you to [stallman.org](https://stallman.org/). - Entering `stallman.org` would redirect you to [stallman.org](https://stallman.org/).
* Entering `https://smile.amazon.com` would redirect you to [smile.amazon.com](https://smile.amazon.com/). - Entering `https://smile.amazon.com` would redirect you to [smile.amazon.com](https://smile.amazon.com/).
### Query Paramater
Additionally, you can pass any query via the `q` query param. For example:
- Going to `file:///path/to/tilde/index.html?q=cats` would search [Google for cats](https://encrypted.google.com/search?q=cats).
This allows you to invoke Tilde with your native browser search bar.
## Configuration ## Configuration
The above is just the beginning. Open up the [index.html](index.html) file and read through the `CONFIG`! The above is _just the beginning_. Open up the [index.html](index.html) file and read through the `CONFIG`!
## License ## License
+77 -103
View File
@@ -83,14 +83,10 @@
pathDelimiter: '/', pathDelimiter: '/',
// the delimiter between the hours and minutes in the clock // the delimiter between the hours and minutes in the clock
clockDelimiter: ' ', clockDelimiter: ' ',
// change clock to twelve hour format // change clock to twelve hour format
twelveHour: false, twelveHour: false,
// note: you can pass in your search query via the q query param
// e.g. going to file:///path/to/tilde/index.html?q=hamsters is equivalent
// to typing "hamsters" and pressing enter
}; };
</script> </script>
@@ -220,12 +216,12 @@
.search-suggestion b::after { .search-suggestion b::after {
content: ' '; content: ' ';
position: absolute; position: absolute;
top: 51%;
right: 0; right: 0;
bottom: -.4em;
left: 0; left: 0;
height: 3px; height: 3px;
background-color: var(--color0); background-color: var(--color0);
opacity: .8; opacity: .3;
} }
.search-suggestion.highlight b::after { .search-suggestion.highlight b::after {
@@ -374,7 +370,7 @@
<form class="overlay center" id="search-form" autocomplete="off" spellcheck="false"> <form class="overlay center" id="search-form" autocomplete="off" spellcheck="false">
<div> <div>
<input id="search-input" type="text"> <input id="search-input" type="text" title="search">
<ul id="search-suggestions"></ul> <ul id="search-suggestions"></ul>
</div> </div>
</form> </form>
@@ -420,6 +416,8 @@
case 91: return 'super'; case 91: return 'super';
} }
}, },
pad: v => ('0' + v.toString()).slice(-2),
}; };
class Clock { class Clock {
@@ -429,21 +427,13 @@
this._form = options.form; this._form = options.form;
this._twelveHour = options.twelveHour; this._twelveHour = options.twelveHour;
this._setTime = this._setTime.bind(this); this._setTime = this._setTime.bind(this);
this._registerEvents();
this._start();
}
_pad(num) {
return ('0' + num.toString()).slice(-2);
}
_registerEvents() {
this._el.addEventListener('click', this._form.show); this._el.addEventListener('click', this._form.show);
this._start();
} }
_setTime() { _setTime() {
const date = new Date(); const date = new Date();
let hours = this._pad(date.getHours()); let hours = $.pad(date.getHours());
let amPm = ''; let amPm = '';
if (this._twelveHour) { if (this._twelveHour) {
@@ -457,7 +447,7 @@
`${date.getHours() > 12 ? 'PM' : 'AM'}</span>`; `${date.getHours() > 12 ? 'PM' : 'AM'}</span>`;
} }
const minutes = this._pad(date.getMinutes()); const minutes = $.pad(date.getMinutes());
this._el.innerHTML = `${hours}${this._delimiter}${minutes}${amPm}`; this._el.innerHTML = `${hours}${this._delimiter}${minutes}${amPm}`;
this._el.setAttribute('datetime', date.toTimeString()); this._el.setAttribute('datetime', date.toTimeString());
} }
@@ -474,8 +464,8 @@
this._commands = options.commands; this._commands = options.commands;
this._newTab = options.newTab; this._newTab = options.newTab;
this._toggled = false; this._toggled = false;
this._handleKeydown = this._handleKeydown.bind(this);
this._buildAndAppendLists(); this._buildAndAppendLists();
this._bindMethods();
this._registerEvents(); this._registerEvents();
} }
@@ -484,10 +474,6 @@
this._toggled ? $.bodyClassAdd('help') : $.bodyClassRemove('help'); this._toggled ? $.bodyClassAdd('help') : $.bodyClassRemove('help');
} }
_bindMethods() {
this._handleKeydown = this._handleKeydown.bind(this);
}
_buildAndAppendLists() { _buildAndAppendLists() {
const lists = document.createElement('ul'); const lists = document.createElement('ul');
lists.classList.add('categories'); lists.classList.add('categories');
@@ -506,18 +492,20 @@
} }
_buildListCommands(category) { _buildListCommands(category) {
return this._commands.map(([cmdCategory, name, key, url]) => { return this._commands
if (cmdCategory === category) { .map(([cmdCategory, name, key, url]) => {
return ( if (cmdCategory === category) {
`<li class="command"> return (
<a href="${url}" target="${this._newTab ? '_blank' : '_self'}"> `<li class="command">
<span class="command-key">${key}</span> <a href="${url}" target="${this._newTab ? '_blank' : '_self'}">
<span class="command-name">${name}</span> <span class="command-key">${key}</span>
</a> <span class="command-name">${name}</span>
</li>` </a>
); </li>`
} );
}).join(''); }
})
.join('');
} }
_getCategories() { _getCategories() {
@@ -544,7 +532,6 @@
} }
addItem() {} addItem() {}
getSuggestions() {} getSuggestions() {}
_addSearchPrefix(items, query) { _addSearchPrefix(items, query) {
@@ -619,14 +606,19 @@
}); });
if (!exists) history.push([query, 1]); if (!exists) history.push([query, 1]);
this._setHistory(this._sort(history));
const sorted = history
.sort((current, next) => current[1] - next[1])
.reverse();
this._setHistory(sorted);
} }
getSuggestions(query) { getSuggestions(query) {
return new Promise(resolve => { return new Promise(resolve => {
const suggestions = this._getHistory() const suggestions = this._getHistory()
.map(([item]) => item) .map(([item]) => item)
.filter(item => this._itemContainsQuery(query, item)) .filter(item => query && !$.ieq(item, query) && $.iin(item, query))
.slice(0, this._limit); .slice(0, this._limit);
resolve(suggestions); resolve(suggestions);
@@ -642,10 +634,6 @@
return this._history; return this._history;
} }
_itemContainsQuery(query, item) {
return query && !$.ieq(item, query) && $.iin(item, query);
}
_save(history) { _save(history) {
localStorage.setItem(this._storeName, JSON.stringify(history)); localStorage.setItem(this._storeName, JSON.stringify(history));
} }
@@ -654,10 +642,6 @@
this._history = history; this._history = history;
this._save(history); this._save(history);
} }
_sort(history) {
return history.sort((current, next) => current[1] - next[1]).reverse();
}
} }
class Suggester { class Suggester {
@@ -666,7 +650,7 @@
this._influencers = options.influencers; this._influencers = options.influencers;
this._limit = options.limit; this._limit = options.limit;
this._suggestionEls = []; this._suggestionEls = [];
this._bindMethods(); this._handleKeydown = this._handleKeydown.bind(this);
this._registerEvents(); this._registerEvents();
} }
@@ -692,8 +676,9 @@
if (input === '') this._clearSuggestions(); if (input === '') this._clearSuggestions();
Promise.all(this._getInfluencerPromises(input)).then(res => { Promise.all(this._getInfluencerPromises(input)).then(res => {
const suggestions = this._flattenAndUnique(res); const suggestions = Suggester._flattenAndUnique(res);
this._clearSuggestions(); this._clearSuggestions();
if (suggestions.length) { if (suggestions.length) {
this._appendSuggestions(suggestions, input); this._appendSuggestions(suggestions, input);
this._registerSuggestionEvents(); this._registerSuggestionEvents();
@@ -702,8 +687,13 @@
}); });
} }
// [[1, 2], [1, 2, 3, 4]] -> [1, 2, 3, 4]
static _flattenAndUnique(array) {
return [...new Set([].concat.apply([], array))];
}
_appendSuggestions(suggestions, input) { _appendSuggestions(suggestions, input) {
suggestions.some((suggestion, i) => { for (const [i, suggestion] of suggestions.entries()) {
const match = new RegExp($.escapeRegex(input), 'ig'); const match = new RegExp($.escapeRegex(input), 'ig');
const suggestionHtml = suggestion.replace(match, `<b>${input}</b>`); const suggestionHtml = suggestion.replace(match, `<b>${input}</b>`);
@@ -721,16 +711,12 @@
</li>`, </li>`,
); );
return i + 1 >= this._limit; if (i + 1 >= this._limit) break;
}); }
this._suggestionEls = $.els('.js-search-suggestion'); this._suggestionEls = $.els('.js-search-suggestion');
} }
_bindMethods() {
this._handleKeydown = this._handleKeydown.bind(this);
}
_clearClickEvents() { _clearClickEvents() {
this._suggestionEls.forEach(el => { this._suggestionEls.forEach(el => {
const callback = this._onClick.bind(null, el.value); const callback = this._onClick.bind(null, el.value);
@@ -745,11 +731,6 @@
this._el.innerHTML = ''; this._el.innerHTML = '';
} }
// [[1, 2], [1, 2, 3, 4]] -> [1, 2, 3, 4]
_flattenAndUnique(array) {
return [...new Set([].concat.apply([], array))];
}
_focusNext(e) { _focusNext(e) {
const exists = this._suggestionEls.some((el, i) => { const exists = this._suggestionEls.some((el, i) => {
if (el.classList.contains('highlight')) { if (el.classList.contains('highlight')) {
@@ -797,12 +778,18 @@
} }
_registerSuggestionEvents() { _registerSuggestionEvents() {
this._suggestionEls.forEach(el => { const noHighlightUntilMouseMove = () => {
const value = el.getAttribute('data-suggestion'); window.removeEventListener('mousemove', noHighlightUntilMouseMove);
el.addEventListener('mouseover', this._highlight.bind(this, el));
el.addEventListener('mouseout', this._unHighlight.bind(this)); this._suggestionEls.forEach(el => {
el.addEventListener('click', this._onClick.bind(null, value)); const value = el.getAttribute('data-suggestion');
}); el.addEventListener('mouseover', this._highlight.bind(this, el));
el.addEventListener('mouseout', this._unHighlight.bind(this));
el.addEventListener('click', this._onClick.bind(null, value));
});
};
window.addEventListener('mousemove', noHighlightUntilMouseMove);
} }
_unHighlight(e) { _unHighlight(e) {
@@ -845,12 +832,12 @@
if (res.isSearch && searchPath) { if (res.isSearch && searchPath) {
res.split = this._searchDelimiter; res.split = this._searchDelimiter;
res.query = this._shiftAndTrim(splitSearch, res.split); res.query = QueryParser._shiftAndTrim(splitSearch, res.split);
res.redirect = this._prepSearch(url, searchPath, res.query); res.redirect = QueryParser._prepSearch(url, searchPath, res.query);
} else if (res.isPath) { } else if (res.isPath) {
res.split = this._pathDelimiter; res.split = this._pathDelimiter;
res.path = this._shiftAndTrim(splitPath, res.split); res.path = QueryParser._shiftAndTrim(splitPath, res.split);
res.redirect = this._prepPath(url, res.path); res.redirect = QueryParser._prepPath(url, res.path);
} else { } else {
res.redirect = url; res.redirect = url;
} }
@@ -859,48 +846,41 @@
} }
if (key === '*') { if (key === '*') {
res.redirect = this._prepSearch(url, searchPath, query); res.redirect = QueryParser._prepSearch(url, searchPath, query);
} }
}); });
} }
res.color = this._getColorFromUrl(res.redirect); res.color = QueryParser._getColorFromUrl(this._commands, res.redirect);
return res; return res;
} }
_getColorFromUrl(url) { static _getColorFromUrl(commands, url) {
const domain = this._getHostname(url); const domain = new URL(url).hostname;
const color = this._commands
.filter(c => this._getHostname(c[3]) === domain)
.map(c => c[5])[0];
return color || null; return commands
.filter(c => new URL(c[3]).hostname === domain)
.map(c => c[5])[0] || null;
} }
_getHostname(url) { static _prepPath(url, path) {
const parser = document.createElement('a'); return QueryParser._stripUrlPath(url) + '/' + path;
parser.href = url;
return parser.hostname.replace(/^www./, '');
} }
_prepPath(url, path) { static _prepSearch(url, searchPath, query) {
return this._stripUrlPath(url) + '/' + path;
}
_prepSearch(url, searchPath, query) {
if (!searchPath) return url; if (!searchPath) return url;
const baseUrl = this._stripUrlPath(url); const baseUrl = QueryParser._stripUrlPath(url);
const urlQuery = encodeURIComponent(query); const urlQuery = encodeURIComponent(query);
searchPath = searchPath.replace('{}', urlQuery); searchPath = searchPath.replace('{}', urlQuery);
return baseUrl + searchPath; return baseUrl + searchPath;
} }
_shiftAndTrim(arr, delimiter) { static _shiftAndTrim(arr, delimiter) {
arr.shift(); arr.shift();
return arr.join(delimiter).trim(); return arr.join(delimiter).trim();
} }
_stripUrlPath(url) { static _stripUrlPath(url) {
const parser = document.createElement('a'); const parser = document.createElement('a');
parser.href = url; parser.href = url;
return `${parser.protocol}//${parser.hostname}`; return `${parser.protocol}//${parser.hostname}`;
@@ -918,7 +898,12 @@
this._instantRedirect = options.instantRedirect; this._instantRedirect = options.instantRedirect;
this._newTab = options.newTab; this._newTab = options.newTab;
this._inputElVal = ''; this._inputElVal = '';
this._bindMethods(); this._clearPreview = this._clearPreview.bind(this);
this.show = this.show.bind(this);
this._handleInput = this._handleInput.bind(this);
this._handleKeydown = this._handleKeydown.bind(this);
this._previewValue = this._previewValue.bind(this);
this._submitForm = this._submitForm.bind(this);
this._registerEvents(); this._registerEvents();
this._loadQueryParam(); this._loadQueryParam();
} }
@@ -934,17 +919,6 @@
this._inputEl.focus(); this._inputEl.focus();
} }
_bindMethods() {
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
this._clearPreview = this._clearPreview.bind(this);
this._handleKeydown = this._handleKeydown.bind(this);
this._handleInput = this._handleInput.bind(this);
this._previewValue = this._previewValue.bind(this);
this._submitForm = this._submitForm.bind(this);
this._submitWithValue = this._submitWithValue.bind(this);
}
_clearPreview() { _clearPreview() {
this._previewValue(this._inputElVal); this._previewValue(this._inputElVal);
this._inputEl.focus(); this._inputEl.focus();