Commit 147810aa authored by Robert Knight's avatar Robert Knight

Port tag suggestion service to JS

parent 93632029
module.exports = ['localStorage', (localStorage) ->
TAGS_LIST_KEY = 'hypothesis.user.tags.list'
TAGS_MAP_KEY = 'hypothesis.user.tags.map'
filter: (query) ->
savedTags = localStorage.getObject TAGS_LIST_KEY
savedTags ?= []
# Only show tags having query as a substring
filterFn = (e) ->
e.toLowerCase().indexOf(query.toLowerCase()) > -1
savedTags.filter(filterFn)
# Add newly added tags from an annotation to the stored ones and refresh
# timestamp for every tags used.
store: (tags) ->
savedTags = localStorage.getObject TAGS_MAP_KEY
savedTags ?= {}
for tag in tags
if savedTags[tag.text]?
# Update counter and timestamp
savedTags[tag.text].count += 1
savedTags[tag.text].updated = Date.now()
else
# Brand new tag, create an entry for it
savedTags[tag.text] = {
text: tag.text
count: 1
updated: Date.now()
}
localStorage.setObject TAGS_MAP_KEY, savedTags
tagsList = []
for tag of savedTags
tagsList[tagsList.length] = tag
# Now produce TAGS_LIST, ordered by (count desc, lexical asc)
compareFn = (t1, t2) ->
if savedTags[t1].count != savedTags[t2].count
return savedTags[t2].count - savedTags[t1].count
else
return -1 if t1 < t2
return 1 if t1 > t2
return 0
tagsList = tagsList.sort(compareFn)
localStorage.setObject TAGS_LIST_KEY, tagsList
]
'use strict';
/**
* @typedef Tag
* @property {string} text - The label of the tag
* @property {number} count - The number of times this tag has been used.
* @property {number} updated - The timestamp when this tag was last used.
*/
/**
* Service for fetching tag suggestions and storing data to generate them.
*
* The `tags` service stores metadata about recently used tags to local storage
* and provides a `filter` method to fetch tags matching a query, ranked based
* on frequency of usage.
*/
// @ngInject
function tags(localStorage) {
var TAGS_LIST_KEY = 'hypothesis.user.tags.list';
var TAGS_MAP_KEY = 'hypothesis.user.tags.map';
/**
* Return a list of tag suggestions matching `query`.
*
* @param {string} query
* @return {Tag[]} List of matching tags
*/
function filter(query) {
var savedTags = localStorage.getObject(TAGS_LIST_KEY) || [];
return savedTags.filter((e) => {
return e.toLowerCase().indexOf(query.toLowerCase()) !== -1;
});
}
/**
* Update the list of stored tag suggestions based on the tags that a user has
* entered for a given annotation.
*
* @param {Tag} tags - List of tags.
*/
function store(tags) {
// Update the stored (tag, frequency) map.
var savedTags = localStorage.getObject(TAGS_MAP_KEY) || {};
tags.forEach((tag) => {
if (savedTags[tag.text]) {
savedTags[tag.text].count += 1;
savedTags[tag.text].updated = Date.now();
} else {
savedTags[tag.text] = {
text: tag.text,
count: 1,
updated: Date.now(),
};
}
});
localStorage.setObject(TAGS_MAP_KEY, savedTags);
// Sort tag suggestions by frequency.
var tagsList = Object.keys(savedTags).sort((t1, t2) => {
if (savedTags[t1].count !== savedTags[t2].count) {
return savedTags[t2].count - savedTags[t1].count;
}
return t1.localeCompare(t2);
});
localStorage.setObject(TAGS_LIST_KEY, tagsList);
}
return {
filter,
store,
};
}
module.exports = tags;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment