Browse Source
- use dexie instead of idb_wrapper.imba - use dexie-export-import instead of upload.imba - use downloadjs instead of download.imba - use fzi instead of bundling fzy.imba - rename link.link to link.url in database v2 - change default links - use config.search_engine object for search engine options - allow multiple of same name - show date in main-input instead of fuzzyhome version - print fuzzyhome version in consolemain
familyfriendlymikey
2 years ago
9 changed files with 2965 additions and 458 deletions
@ -1,5 +0,0 @@ |
|||
let state = {} |
|||
state.query = '' |
|||
state.links = [] |
|||
state.scored_links = [] |
|||
export default state |
@ -1,14 +0,0 @@ |
|||
def get_datetime_string |
|||
let obj = new Date!.toString!.split(" ") |
|||
let date = obj.slice(1, 4).join("-").toLowerCase! |
|||
let time = obj[4].split(":").join("-") |
|||
"{date}_{time}" |
|||
|
|||
export default def download_json_file data, prefix="" |
|||
let element = document.createElement 'a' |
|||
element.setAttribute 'href', 'data:text/plain;charset=utf-8,' + window.encodeURIComponent(data) |
|||
element.setAttribute 'download', "{prefix}{get_datetime_string!}.json" |
|||
element.style.display = 'none' |
|||
document.body.appendChild element |
|||
element.click! |
|||
document.body.removeChild element |
@ -1,95 +0,0 @@ |
|||
let SCORE_MIN = -Infinity |
|||
let SCORE_MAX = Infinity |
|||
let SCORE_GAP_LEADING = -0.005 |
|||
let SCORE_GAP_TRAILING = -0.005 |
|||
let SCORE_GAP_INNER = -0.01 |
|||
let SCORE_MATCH_CONSECUTIVE = 1.0 |
|||
let SCORE_MATCH_SLASH = 0.9 |
|||
let SCORE_MATCH_WORD = 0.8 |
|||
let SCORE_MATCH_DOT = 0.6 |
|||
|
|||
def fzy arr, query, keyname="name" |
|||
let needle = query.trim!.toLowerCase! |
|||
return [] unless arr.length > 0 |
|||
let scored = [] |
|||
let M = new Array(100_000) |
|||
let D = new Array(100_000) |
|||
let B = new Array(100_000) |
|||
for obj in arr |
|||
continue unless obj.hasOwnProperty keyname |
|||
let haystack = obj[keyname].trim!.toLowerCase! |
|||
continue unless has_match needle, haystack |
|||
obj.fzy_score = score(needle, haystack, M, D, B) |
|||
sorted_insert obj, scored |
|||
scored |
|||
|
|||
def score needle, haystack, M, D, match_bonus |
|||
let n = needle.length |
|||
let m = haystack.length |
|||
if n < 1 or m < 1 |
|||
return SCORE_MIN |
|||
if n === m |
|||
return SCORE_MAX |
|||
if m > 1024 |
|||
return SCORE_MIN |
|||
compute needle, haystack, M, D, match_bonus |
|||
M[(n - 1)*m + (m - 1)] |
|||
|
|||
def compute needle, haystack, M, D, match_bonus |
|||
let n = needle.length |
|||
let m = haystack.length |
|||
precompute_bonus haystack, match_bonus |
|||
for i in [0 .. n - 1] |
|||
let prev_score = SCORE_MIN |
|||
let gap_score = i === n - 1 ? SCORE_GAP_TRAILING : SCORE_GAP_INNER |
|||
for j in [0 .. m - 1] |
|||
let ij = i*m + j |
|||
let pij = (i - 1)*m + (j - 1) |
|||
if needle[i] === haystack[j] |
|||
let score = SCORE_MIN |
|||
if i === 0 |
|||
score = (j * SCORE_GAP_LEADING) + match_bonus[j] |
|||
elif j > 0 |
|||
score = Math.max(M[pij] + match_bonus[j], D[pij] + SCORE_MATCH_CONSECUTIVE) |
|||
D[ij] = score |
|||
M[ij] = prev_score = Math.max(score, prev_score + gap_score) |
|||
else |
|||
D[ij] = SCORE_MIN |
|||
M[ij] = prev_score = prev_score + gap_score |
|||
|
|||
def precompute_bonus haystack, match_bonus |
|||
let m = haystack.length |
|||
let last_ch = '/' |
|||
for i in [0 .. m - 1] |
|||
let ch = haystack[i] |
|||
if last_ch === '/' |
|||
match_bonus[i] = SCORE_MATCH_SLASH |
|||
elif last_ch === '-' || last_ch === '_' || last_ch === ' ' |
|||
match_bonus[i] = SCORE_MATCH_WORD |
|||
elif last_ch === '.' |
|||
match_bonus[i] = SCORE_MATCH_DOT |
|||
else |
|||
match_bonus[i] = 0 |
|||
last_ch = ch |
|||
|
|||
def has_match needle, haystack |
|||
let i = 0 |
|||
let n = -1 |
|||
let letter |
|||
while letter = needle[i++] |
|||
if (n = haystack.indexOf(letter, n + 1)) === -1 |
|||
return no |
|||
return yes |
|||
|
|||
def sorted_insert elem, arr |
|||
let low = 0 |
|||
let high = arr.length |
|||
while low < high |
|||
let mid = (low + high) >>> 1 |
|||
if elem.fzy_score > arr[mid].fzy_score |
|||
high = mid |
|||
else |
|||
low = mid + 1 |
|||
arr.splice(low, 0, elem) |
|||
|
|||
export default fzy |
@ -1,94 +0,0 @@ |
|||
let p = console.log |
|||
|
|||
class idb_wrapper |
|||
|
|||
constructor db_name, table_name, version |
|||
db_name = db_name |
|||
table_name = table_name |
|||
version = version |
|||
openRequest = null |
|||
|
|||
def open |
|||
|
|||
openRequest = global.indexedDB.open(db_name, version) |
|||
|
|||
openRequest.onupgradeneeded = do |event| |
|||
p "Upgrading from DB version {event.oldVersion} to {event.newVersion}." |
|||
let db = openRequest.result |
|||
switch event.oldVersion |
|||
|
|||
when 0 |
|||
db.createObjectStore(table_name, { keyPath: 'id', autoIncrement: true }) |
|||
|
|||
openRequest.onerror = do |
|||
p "Open db error." |
|||
|
|||
openRequest.onsuccess = do |
|||
p "Open db success." |
|||
if global.navigator.storage and global.navigator.storage.persist |
|||
global.navigator.storage.persist!.then! do |persistent| |
|||
p "db is persistent: {persistent}" |
|||
|
|||
def reload |
|||
let store |
|||
|
|||
while yes |
|||
try |
|||
store = #get_store "readonly" |
|||
p "Get store success." |
|||
break |
|||
catch |
|||
p "Failed to get store, retrying." |
|||
await #sleep 10 |
|||
|
|||
let request = store.getAll! |
|||
|
|||
return new Promise! do |resolve| |
|||
|
|||
request.onsuccess = do |
|||
p "Load db success." |
|||
resolve request.result |
|||
imba.commit! |
|||
|
|||
request.onerror = do |
|||
p "Load db error." |
|||
resolve no |
|||
|
|||
def delete obj |
|||
let store = #get_store! |
|||
let request = store.delete(obj.id) |
|||
|
|||
return new Promise! do |resolve| |
|||
|
|||
request.onsuccess = do |
|||
p "deleted link: {obj}" |
|||
resolve no |
|||
|
|||
request.onerror = do |
|||
p "Failed to delete link: {obj}" |
|||
resolve yes |
|||
|
|||
def put obj |
|||
let store = #get_store! |
|||
let request = store.put(obj) |
|||
|
|||
return new Promise! do |resolve| |
|||
|
|||
request.onsuccess = do |
|||
p "Successfully put link: {obj}" |
|||
resolve request.result |
|||
|
|||
request.onerror = do |
|||
p "Failed to put link: {obj}" |
|||
resolve no |
|||
|
|||
def #get_store permission="readwrite" |
|||
let db = openRequest.result |
|||
let transaction = db.transaction(table_name, permission) |
|||
transaction.objectStore(table_name) |
|||
|
|||
def #sleep ms |
|||
new Promise! do |resolve| |
|||
setTimeout resolve, ms |
|||
|
|||
export default idb_wrapper |
@ -1,14 +0,0 @@ |
|||
export default def upload_json_file e |
|||
return new Promise! do |resolve| |
|||
let files = e.target.files |
|||
resolve no if files.length < 1 |
|||
let file = files[0] |
|||
let reader = new FileReader() |
|||
reader.onloadend = do |
|||
try |
|||
resolve JSON.parse(reader.result) |
|||
catch |
|||
resolve no |
|||
reader.onerror = do |
|||
resolve no |
|||
reader.readAsText(file) |
File diff suppressed because it is too large
Loading…
Reference in new issue