├── README.md
├── index.html
└── index.js
/README.md:
--------------------------------------------------------------------------------
1 | # TagRename
2 | Rename Hypothesis tags
3 |
4 | More Hypothesis tools .
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Rename Hypothesis tags
6 |
7 |
8 |
36 |
37 |
38 |
39 |
40 |
42 |
43 | view/edit/reply
44 |
45 |
48 |
51 |
52 |
53 |
54 |
55 | Rename Hypothesis tags
56 |
57 |
58 | This tool lists your Hypothesis tags, and enables you to rename one or more of them.
59 | If you have many annotations to search, it'll take a while to build the list. You can
60 | shortcut that process by specifying a particular tag you want to rename.
61 |
62 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
To see all your tags, increase the max to a number greater than your total # of annotations.
78 |
Please do make a safe copy your annotations first. And proceed with care. There a way to lose information without any technical malfunction. Suppose you are using three tags, A, B, and C, to classify annotations into three buckets. Then you rename B to C. Now bucket B is gone. There is only A, unchanged. and C, which includes what was in B. You can't reverse the arrow of entropy and reconstitute the set of annotations that were in B!
79 |
80 | More Hypothesis tools .
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | let allTags = {}
2 |
3 | const externalLinkStyle = `style="display:inline;width:.6em;height:.6em;margin-left:2px;margin-top:3px;"`
4 |
5 | hlib.createUserInputForm(hlib.getById('userContainer'), 'Your Hypothesis username')
6 | hlib.createTagInputForm(hlib.getById('tagContainer'), 'Leave empty to search all tags')
7 | hlib.createMaxInputForm(hlib.getById('maxContainer'), 'Max annotations to search')
8 | hlib.createApiTokenInputForm(hlib.getById('tokenContainer'))
9 | hlib.getById('searchButton').onclick = search
10 |
11 | function initializeTagDiv(tag) {
12 | const externalLink = renderIcon('icon-external-link', externalLinkStyle)
13 | const facetUrl = `https://jonudell.info/h/facet?user=${getUser()}&tag=${tag}&expanded=true&exactTagSearch=true`
14 | return `
15 | `
20 | }
21 |
22 | function getUser() {
23 | return hlib.getSettings().user
24 | }
25 |
26 | function getTag() {
27 | return hlib.getSettings().tag
28 | }
29 |
30 | function renderIcon(iconClass, style) {
31 | const _style = style ? style : `style="display:block"`
32 | return ` `
33 | }
34 |
35 | function addRenameUX(tag) {
36 | if (hlib.getById(`_${tag}`)) {
37 | return
38 | }
39 | let tagDivs = Array.from(document.querySelectorAll('.tag'))
40 | let tags = tagDivs.map(tagDiv => {
41 | return tagDiv.innerText
42 | })
43 | tags.forEach(_tag => {
44 | try {
45 | cancelSetup(_tag)
46 | } catch (e) {
47 | console.log(e)
48 | }
49 | })
50 | let element = hlib.getById(tag)
51 | element.querySelector('a').setAttribute('onclick', null)
52 | element.innerHTML += `
53 |
54 | rename
55 | cancel `
56 | }
57 |
58 | // rename an individual tag
59 | function rename(tag) {
60 | if (hlib.getById(`_${tag}`).value === '') {
61 | alert('Cannot rename to nothing')
62 | return
63 | }
64 | let fromTag = tag
65 | let params = {
66 | user: getUser(),
67 | max: hlib.getSettings().max,
68 | tag: fromTag
69 | }
70 | hlib.search(params)
71 | .then( data => {
72 | processRenameResults(data[0], data[1])
73 | })
74 | }
75 |
76 | function cancelSetup(tag) {
77 | let element = hlib.getById(tag)
78 | element.outerHTML = initializeTagDiv(tag)
79 | }
80 |
81 | function tokenReset() {
82 | localStorage.setItem('h_token', '')
83 | }
84 |
85 | function processSearchResults(annos, replies) {
86 | annos = annos.concat(replies)
87 | const _tag = getTag()
88 | annos.forEach(anno => {
89 | for (let i = 0; i < anno.tags.length; i++) {
90 | let tag = anno.tags[i]
91 | if (_tag && tag !== _tag) {
92 | continue
93 | }
94 | tag = tag.replace(/"/g,'').trim()
95 | if (!allTags.hasOwnProperty(tag)) {
96 | allTags[tag] = 1
97 | } else {
98 | allTags[tag] += 1
99 | }
100 | }
101 | })
102 | let tagList = Object.keys(allTags).sort(function (a, b) {
103 | return a.toLowerCase().localeCompare(b.toLowerCase())
104 | })
105 | tagList = tagList.map(tag => {
106 | return initializeTagDiv(tag)
107 | })
108 | hlib.getById('tags').innerHTML += tagList.join('\n')
109 | hlib.getById('progress').innerHTML = ''
110 | }
111 |
112 | function processRenameResults(annos, replies) {
113 | annos = annos.concat(replies)
114 | let fromTag = document.querySelector('.renamer').parentElement.id
115 | let toTag = document.querySelector('.renamer').value
116 | for (i = 0; i < annos.length; i++ ) {
117 | let anno = annos[i]
118 | let tags = anno.tags
119 | let _tags = []
120 | tags.forEach(tag => {
121 | if (tag === fromTag) {
122 | tag = toTag
123 | }
124 | _tags.push(tag)
125 | })
126 | let payload = {
127 | tags: _tags
128 | }
129 | let payloadJson = JSON.stringify(payload)
130 | hlib.updateAnnotation(anno.id, hlib.getToken(), payloadJson)
131 | .then(data => {
132 | console.log(data)
133 | if (i == annos.length) {
134 | hlib.getById(fromTag).innerHTML = `${fromTag} ${toTag}`
135 | }
136 | })
137 | }
138 | }
139 |
140 | async function search() {
141 | if (!getUser()) {
142 | alert('Please provide the Hypothesis username corresponding to the API token')
143 | return
144 | }
145 | allTags = {}
146 | hlib.getById('tags').innerHTML = ''
147 | let params = {
148 | user: getUser(),
149 | max: hlib.getSettings().max
150 | }
151 | const tag = getTag()
152 | if (tag) {
153 | params.tag = tag
154 | }
155 | const data = await hlib.search(params, 'progress')
156 | processSearchResults(data[0], data[1])
157 | }
158 |
159 | setTimeout(_ => {
160 | hlib.manageTokenDisplayAndReset()
161 | }, 200)
162 |
163 |
--------------------------------------------------------------------------------