${html}
`
113 | results.appendChild(hit)
114 | }
115 | }
116 |
117 | /*document.getElementById('close').addEventListener('click',(evt) => {
118 | evt.preventDefault()
119 | evt.stopPropagation()
120 | window.close();
121 | })*/
122 |
123 | document.getElementById('form').onsubmit = (evt) => {
124 | evt.preventDefault()
125 | evt.stopPropagation()
126 | if (query.value.trim() > '')
127 | search(query.value.trim().toLowerCase());
128 | }
129 |
--------------------------------------------------------------------------------
/yawas-content-script.js:
--------------------------------------------------------------------------------
1 | var signedin = false;
2 | var highlightswrapper = document.querySelector('#yawas_highlightswrapper');
3 | var forecolor = "#000000";
4 | var currentColor = "yellow";
5 | var hoverColor = 'lightgray';//'pink'
6 | var hoverElement = null;
7 | var lastHighlight = null;
8 | var leftMark = '<<';//'“'
9 | var rightMark = '>>';//'”'
10 | var lenquote = rightMark.length;//2;
11 | var googleColors = [];
12 | googleColors['yellow'] = '#FFFF66';
13 | googleColors['blue'] = '#0df';
14 | googleColors['red'] = '#ff9999';
15 | googleColors['green'] = '#99ff99';
16 | googleColors['white'] = 'transparent';
17 | var notRemapped = [];
18 |
19 | function dragElement(div)
20 | {
21 | let draggedDiv = div;
22 | let left = 0;
23 | let top = 0;
24 | draggedDiv.querySelector('#dragheader').addEventListener('mousedown',dragMouseDown);
25 |
26 | function dragMouseDown(e)
27 | {
28 | e.preventDefault();
29 | let rect = draggedDiv.getBoundingClientRect();
30 | left = e.clientX - rect.left;
31 | top = e.clientY - rect.top;
32 | document.addEventListener('mouseup',closeDragElement);
33 | document.addEventListener('mousemove',elementDrag);
34 | };
35 |
36 | function elementDrag(e)
37 | {
38 | e.preventDefault();
39 | let x = e.clientX;
40 | let y = e.clientY;
41 | draggedDiv.style.right = 'unset';
42 | draggedDiv.style.bottom = 'unset';
43 | let draggedWidth = draggedDiv.offsetWidth + 24;
44 | let draggedHeight = draggedDiv.offsetHeight + 8;
45 | let newleft = (x - left);
46 | let newtop = (y - top);
47 | if (newleft < 8)
48 | newleft = 8;
49 | if (newleft > window.innerWidth - draggedWidth)
50 | newleft = window.innerWidth - draggedWidth;
51 | if (newtop < 8)
52 | newtop = 8;
53 | if (newtop > window.innerHeight - draggedHeight)
54 | newtop = window.innerHeight - draggedHeight;
55 | draggedDiv.style.left = newleft + 'px';
56 | draggedDiv.style.top = newtop + 'px';
57 | };
58 | function closeDragElement(e)
59 | {
60 | document.removeEventListener('mouseup',closeDragElement);
61 | document.removeEventListener('mousemove',elementDrag);
62 | }
63 | }
64 |
65 | function contentScriptRequestCallback(request, sender, sendResponse) {
66 | //console.error('contentScriptRequestCallback',request);
67 | if (request.action)
68 | {
69 | if (request.action === 'signedin')
70 | {
71 | if (!signedin)
72 | {
73 | signedin = true; // this avoids loops: we declare we're signed first
74 | if (highlightswrapper)
75 | {
76 | setHighlightCaption('Yawas ➜ Refresh to view annotations');
77 | highlightswrapper.style.display = 'block';
78 | }
79 | }
80 | }
81 | else if (request.action === 'yawas_next_highlight')
82 | yawas_next_highlight();
83 | else if (request.action === 'yawas_chrome')
84 | yawas_chrome(request.color);
85 | else if (request.action === 'yawas_delete_highlight')
86 | yawas_delete_highlight();
87 | else if (request.action === 'yawas_copytoclipboard')
88 | yawas_copytoclipboard(request.payload);
89 | }
90 | if (sendResponse)
91 | {
92 | //console.log('sending response to background page');
93 | sendResponse({reponse:'ok'});
94 | }
95 | return true; // important in case we need sendResponse asynchronously
96 | }
97 |
98 | function yawas_copytoclipboard(html) {
99 |
100 | if(typeof ClipboardItem === "undefined") {
101 | alert("Sorry! ClipboardItem not available in your browser.")
102 | return;
103 | }
104 |
105 | const type = "text/html";
106 | const blob = new Blob([html], {type});
107 | const data = [new ClipboardItem({[type]: blob})];
108 |
109 | navigator.clipboard.write(data).then(function () {
110 | alert('Yawas highlights copied to your clipboard!')
111 | }, function (e) {
112 | alert('error copying to clipboard')
113 | });
114 | }
115 |
116 | /*function yawas_copytoclipboard(text) {
117 | console.log('yawas_copytoclipboard',text)
118 | var copyFrom = document.createElement("textarea");
119 | copyFrom.textContent = text;
120 | var body = document.getElementsByTagName('body')[0];
121 | body.appendChild(copyFrom);
122 | copyFrom.select();
123 | document.execCommand('copy');
124 | body.removeChild(copyFrom);
125 | }*/
126 |
127 | //chrome.runtime.onMessage.addListener(contentScriptRequestCallback);
128 | chrome.runtime.onConnect.addListener((port) => {
129 | //console.log('onconnect to port',port);
130 | port.onMessage.addListener(contentScriptRequestCallback);
131 | });
132 |
133 | let charactersUsed = 0;
134 | function setCharactersLeft(txt)
135 | {
136 | charactersUsed = txt;
137 | if (highlightswrapper && highlightswrapper.querySelector('#charactersleft'))
138 | highlightswrapper.querySelector('#charactersleft').textContent = txt + '/2048 chars';
139 |
140 | }
141 | function setHighlightCaption(txt)
142 | {
143 | if (highlightswrapper && highlightswrapper.querySelector('#highlightcaption'))
144 | highlightswrapper.querySelector('#highlightcaption').textContent = txt;
145 | }
146 |
147 | function showNotFound(evt)
148 | {
149 | if (highlightsnotfoundtext.style.display === 'none')
150 | {
151 | var html = [];
152 | notRemapped.forEach(highlight => html.push(highlight.selection));
153 | highlightsnotfoundtext.innerHTML = `
${html.join(' ')}
`;
154 | highlightsnotfoundtext.style.display = 'block';
155 | }
156 | else
157 | highlightsnotfoundtext.style.display = 'none';
158 | }
159 |
160 | function setHighlightsNotFound(array)
161 | {
162 | if (highlightswrapper && highlightswrapper.querySelector('#highlightsnotfound'))
163 | {
164 | if (array.length > 0)
165 | {
166 | highlightswrapper.querySelector('#highlightsnotfound').textContent = array.length + ' missing';
167 | }
168 | else
169 | highlightswrapper.querySelector('#highlightsnotfound').textContent = '';
170 | }
171 | }
172 |
173 | function updateHighlightCaption() {
174 | if (highlightswrapper)
175 | {
176 | var nbNotRemapped = notRemapped.length;
177 | var nhighlights = document.getElementsByClassName('yawas-highlight').length;
178 | if (nhighlights > 0)
179 | {
180 | highlightswrapper.style.display = 'block';
181 | if (nhighlights > 1)
182 | {
183 | var current = currentHighlight + 1;
184 | setHighlightCaption(current + '/' + nhighlights + ' highlights');
185 | }
186 | else
187 | {
188 | setHighlightCaption(nhighlights + ' highlight');
189 | }
190 | setHighlightsNotFound(notRemapped);
191 | }
192 | else
193 | {
194 | highlightswrapper.style.display = 'none';
195 | }
196 | }
197 |
198 | }
199 |
200 | function purifyURL(href)
201 | {
202 | if (href && href.indexOf('https://mail.google') === 0)
203 | return href;
204 | var url = href;
205 | var pos = url.indexOf('#');
206 | if (pos > 0)
207 | url = url.substring(0,pos);
208 | url = url.replace(/[?&]utm_.*/,'');
209 | url = url.replace(/[?&]WT\..*/,'');
210 | url = url.replace(/[?&]ns_.*/,'');
211 | url = url.replace(/[?&]rand=.*/,'');
212 | url = url.replace(/[?&]src=.*/,'');
213 | url = url.replace(/[?&]imm_mid=.*/,'');
214 | url = url.replace(/[?&]cmp=.*/,'');
215 | url = url.replace(/[?&]ncid=.*/,'');
216 | url = url.replace(/[?&]cps=.*/,'');
217 | url = url.replace(/[?&]mc_cid=.*/,'');
218 | url = url.replace(/[?&]mc_eid=.*/,'');
219 | url = url.replace(/[?&]mbid=.*/,'');
220 | if (url.indexOf('nytimes.com')!=-1)
221 | url = url.split('?')[0];
222 | //console.log('purifyURL=',href,'=',url);
223 | return url;
224 | }
225 |
226 | function yawas_getGoodUrl(doc)//,url)
227 | {
228 | var url = null;
229 | if (doc && doc.location && doc.location.hostname.indexOf('readability.com') !== -1)
230 | {
231 | var origin = doc.querySelector('.entry-origin a');
232 | if (origin)
233 | url = origin.href;
234 | }
235 | if (!url)
236 | url = doc.location.href;
237 |
238 | if (url.indexOf("q=cache:") > 0)
239 | {
240 | try {
241 | return purifyURL(doc.getElementsByTagName('base')[0].href);
242 | } catch (e) {}
243 | }
244 | else
245 | return purifyURL(url);
246 | }
247 |
248 | function needSignIn()
249 | {
250 | signedin = false;
251 | if (highlightswrapper)
252 | {
253 | setHighlightCaption('Signed out');
254 | highlightswrapper.style.display = 'block';
255 | }
256 | }
257 |
258 | function askForAnnotations(delay)
259 | {
260 | var url = yawas_getGoodUrl(document);
261 | var additionalInfo = {
262 | "fn": "yawas_getAnnotations",
263 | "title": document.title,
264 | "url": url
265 | };
266 | if (!delay)
267 | delay = 0;
268 | setTimeout(function () {
269 | sendMessage(additionalInfo, function (res) {
270 | if (res && res.error)
271 | {
272 | if (res.signedout)
273 | {
274 | needSignIn();
275 | if (res.url)
276 | {
277 | //window.open(res.url);
278 | //console.log('res.url=',res.url);
279 | }
280 | }
281 | }
282 | else if (res && res.noannotation)
283 | {
284 | signedin = true;
285 | hoverElement = null;
286 | updateHighlightCaption();
287 | }
288 | else if (res && res.annotations)
289 | {
290 | signedin = true;
291 | hoverElement = null;
292 | setCharactersLeft(computeLength(res.annotations));
293 | yawas_remapAnnotations(res.annotations);
294 | updateHighlightCaption();
295 | }
296 | });
297 | }, delay);
298 | }
299 |
300 | function yawas_signin()
301 | {
302 | var width = 400;
303 | var height = 360;
304 | var left = Math.floor( (screen.width - width) / 2);
305 | var top = Math.floor( (screen.height - height) / 2);
306 | window.open('https://www.google.com/accounts/ServiceLogin?service=toolbar&nui=1&hl=en&continue=http%3A%2F%2Ftoolbar.google.com%2Fcommand%3Fclose_browser','bkmk_popup','left='+left+',top='+top+',height='+height+'px,width='+width+'px,resizable=1');
307 | }
308 |
309 | /*function isSavingLocally(cb)
310 | {
311 | chrome.storage.sync.get({saveLocally: false}, function(items) {
312 | if (items && items.saveLocally === true)
313 | cb(true);
314 | else
315 | cb(false);
316 | });
317 | }*/
318 |
319 | function yawas_undohighlight()
320 | {
321 | if (lastHighlight !== null)
322 | {
323 | var f = document.createDocumentFragment();
324 | while(lastHighlight.firstChild)
325 | f.appendChild(lastHighlight.firstChild);
326 | lastHighlight.parentNode.replaceChild(f,lastHighlight);
327 | lastHighlight = null;
328 | }
329 | }
330 |
331 | function addHighlightsWrapper()
332 | {
333 | if (highlightswrapper === null)
334 | {
335 | highlightswrapper = document.createElement('div');
336 | highlightswrapper.id = 'yawas_highlightswrapper';
337 | highlightswrapper.style.userSelect = 'none';
338 | highlightswrapper.style.display = 'none';
339 | highlightswrapper.style.position = 'fixed';
340 | highlightswrapper.style.zIndex = 200000;
341 | highlightswrapper.style.margin = '0px';
342 | highlightswrapper.style.userSelect = 'none';
343 | highlightswrapper.style.fontFamily = '"avenir next",Helvetica';
344 | highlightswrapper.style.right = '8px';
345 | highlightswrapper.style.bottom = '8px';
346 | highlightswrapper.style.borderRadius = '8px';
347 | highlightswrapper.style.boxShadow = '0 0 2px black';
348 | highlightswrapper.style.color = 'white';
349 | highlightswrapper.textContent = '';
350 | highlightswrapper.style.textAlign = 'center';
351 | //highlightswrapper.style.cursor = 'pointer';
352 |
353 | highlightswrapper.style.fontSize = '14px';
354 | highlightswrapper.style.fontWeight = 'bold';
355 | highlightswrapper.style.color = 'white';//'black';
356 | highlightswrapper.style.backgroundColor = '#190B33';//'#8a8';
357 | //highlightswrapper.style.borderRadius = '32px';
358 | highlightswrapper.style.padding = '8px 16px';
359 | //highlightswrapper.textContent = '';
360 |
361 | let dragheader = document.createElement('div');
362 | dragheader.id = 'dragheader';
363 | dragheader.style.textAlign = 'center';
364 | dragheader.style.cursor = 'move';
365 | dragheader.style.fontSize = '16px';
366 | dragheader.style.color = '#8a8';//'#ccc';
367 | dragheader.textContent = 'Yawas';
368 | highlightswrapper.appendChild(dragheader);
369 | var highlightcaption = document.createElement('div');
370 | highlightcaption.addEventListener('mousedown',(evt) => yawas_next_highlight(evt));
371 | highlightcaption.title = 'Click to navigate in highlights';
372 | highlightcaption.id = 'highlightcaption';
373 | highlightcaption.style.cursor = 'pointer';
374 | highlightcaption.style.userSelect = 'none';
375 | highlightcaption.style.webkitUserSelect = 'none';
376 | highlightcaption.textContent = '';
377 | highlightswrapper.appendChild(highlightcaption);
378 |
379 | var highlightsnotfound = document.createElement('div');
380 | highlightsnotfound.style.color = '#a22';
381 | highlightsnotfound.style.cursor = 'pointer';
382 | highlightsnotfound.addEventListener('click',showNotFound);
383 | highlightsnotfound.title = 'Click to show missing highlights';
384 | highlightsnotfound.id = 'highlightsnotfound';
385 | highlightswrapper.appendChild(highlightsnotfound);
386 |
387 | var highlightsnotfoundtext = document.createElement('div');
388 | highlightsnotfoundtext.style.color = '#a22';
389 | highlightsnotfoundtext.style.display = 'none';
390 | highlightsnotfoundtext.id = 'highlightsnotfoundtext';
391 | highlightswrapper.appendChild(highlightsnotfoundtext);
392 |
393 | /*var charactersleft = document.createElement('div');
394 | charactersleft.style.color = '#000';
395 | charactersleft.style.fontSize = '11px';
396 | charactersleft.style.cursor = 'pointer';
397 | charactersleft.title = 'Number of total characters used for this page in Google Bookmarks, out of 2048 possible';
398 | charactersleft.addEventListener('click',function () { alert(charactersUsed + ' characters used out of 2048 allowed by Google Bookmarks for this page')},false);
399 | charactersleft.style.display = 'block';
400 | charactersleft.id = 'charactersleft';
401 | highlightswrapper.appendChild(charactersleft);*/
402 |
403 | let close = document.createElement('div');
404 | close.textContent = '✕';
405 | close.style.position = 'absolute';
406 | close.style.top = 0;
407 | close.style.left = 0;
408 | close.style.margin = '4px';
409 | close.style.fontSize = '12px'
410 | close.style.padding = '4px';
411 | close.style.color = '#ccc';
412 | close.style.cursor = 'pointer'
413 | close.addEventListener('click',function() { highlightswrapper.style.display ='none'},false);
414 | highlightswrapper.appendChild(close);
415 | document.body.appendChild(highlightswrapper);
416 | dragElement(highlightswrapper);
417 | }
418 | }
419 |
420 | function yawas_storeHighlight(webUrl,title,highlight,occurence,couleur,addcommentwhendone)
421 | {
422 | var additionalInfo = {
423 | "fn": "addhighlight",
424 | "title": title,
425 | "url": webUrl,
426 | "selection": highlight,
427 | "occurence": occurence,
428 | "couleur": couleur
429 | };
430 | sendMessage(additionalInfo, function (res)
431 | {
432 | if (res && res.addedhighlight)
433 | {
434 | signedin = true;
435 | setCharactersLeft(res.pureLen);
436 | updateHighlightCaption();
437 | if (addcommentwhendone)
438 | {
439 | hoverElement = lastHighlight;
440 | recolor('note');
441 | }
442 | }
443 | if (res && res.toobig)
444 | {
445 | yawas_undohighlight();
446 | alert('Too many characters (>2048 even compacted)!');
447 | }
448 | if (res && res.undohighlight || res.error)
449 | {
450 | if (res.signedout)
451 | alert('Yawas cannot store your highlight because you are signed out.\nPlease signin first and then refresh this page');
452 | yawas_undohighlight();
453 | }
454 | });
455 | }
456 |
457 | function yawas_tryHighlight(wnd,addcommentwhendone)
458 | {
459 | if (!wnd)
460 | return false;
461 | var nselections = wnd.getSelection().rangeCount;
462 | if (nselections === 0)
463 | return false;
464 | var selection = wnd.getSelection().getRangeAt(0);
465 | var selectionstring = wnd.getSelection()+"";//selection.toString();
466 | selectionstring = selectionstring.trim();
467 | if (selectionstring.length === 0)
468 | return false;
469 | if (selectionstring.indexOf("\n") >= 0)
470 | {
471 | alert("Please select text without new lines");
472 | return false;
473 | }
474 | var docurl = yawas_getGoodUrl(wnd.document);
475 | var occurence = -1;
476 | wnd.getSelection().removeAllRanges();
477 | var found = false;
478 | while (!found && wnd.find(selectionstring,true,false))
479 | {
480 | occurence += 1;
481 | var rng = wnd.getSelection().getRangeAt(0);
482 | if (selection.compareBoundaryPoints(Range.END_TO_START, rng) == -1 && selection.compareBoundaryPoints(Range.START_TO_END, rng) == 1)
483 | found = true;
484 | }
485 | if (!found)
486 | occurence = -1;
487 | if (occurence >= 0)
488 | {
489 | lastHighlight = highlightNowFirefox22(wnd.getSelection().getRangeAt(0),currentColor,forecolor,wnd.document,selectionstring,occurence);
490 | wnd.getSelection().removeAllRanges();
491 | yawas_storeHighlight(docurl,wnd.document.title,selectionstring,occurence,currentColor,addcommentwhendone);
492 | return true;
493 | }
494 | else
495 | {
496 | alert('Sorry, [' + selectionstring + '] was not found.');
497 | wnd.getSelection().removeAllRanges();
498 | return false;
499 | }
500 | }
501 |
502 | function getWindowWithSelection(wnd)
503 | {
504 | //alert('hasSelection:' + wnd);
505 | if (wnd.getSelection().rangeCount>0)
506 | {
507 | //alert('found selection:' + wnd.getSelection());
508 | return wnd;
509 | }
510 | else
511 | return null;
512 | }
513 |
514 | function recolor(color)
515 | {
516 | if (color === 'note')
517 | {
518 | let caption = hoverElement.dataset.comment!==null?hoverElement.dataset.comment:'';
519 | let newcomment = prompt('Enter note',caption);
520 | if (newcomment !== null)
521 | {
522 | newcomment = newcomment.trim();
523 | if (newcomment.length === 0)
524 | {
525 | //hoverElement.style.borderBottom = 0;
526 | //delete hoverElement.dataset.yawasComment;
527 | delete hoverElement.dataset.comment;
528 | delete hoverElement.title;
529 | }
530 | else
531 | {
532 | //hoverElement.style.borderBottom = '1px dashed black';
533 | //hoverElement.dataset.yawasComment = newcomment;
534 | hoverElement.dataset.comment = newcomment;
535 | hoverElement.title = newcomment;
536 | }
537 | updateHighlight(hoverElement,color,newcomment);
538 | hoverElement = null;
539 | }
540 | return;
541 | }
542 | else
543 | {
544 | hoverElement.dataset.yawasColor = googleColors[color];
545 | hoverElement.style.backgroundColor = googleColors[color];
546 | childrenToo(hoverElement,googleColors[color]);
547 | updateHighlight(hoverElement,color,null);
548 | // clear the selection (on Firefox we selected the text inside oncontextmenu)
549 | window.getSelection().removeAllRanges();
550 | }
551 | }
552 |
553 | // from http://stackoverflow.com/questions/1482832/how-to-get-all-elements-that-are-highlighted/1483487#1483487
554 | function rangeIntersectsNode(range, node) {
555 | var nodeRange;
556 | if (range.intersectsNode) {
557 | return range.intersectsNode(node);
558 | } else {
559 | nodeRange = node.ownerDocument.createRange();
560 | try {
561 | nodeRange.selectNode(node);
562 | } catch (e) {
563 | nodeRange.selectNodeContents(node);
564 | }
565 |
566 | return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
567 | range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
568 | }
569 | }
570 |
571 | function sendMessage(info,cb)
572 | {
573 | try {
574 | chrome.runtime.sendMessage(info, function response(res) {
575 | if (res && cb)
576 | cb(res);
577 | });
578 | } catch(e)
579 | {
580 | if (cb)
581 | cb({error:e});
582 | else
583 | console.error('sendMessage error' + e);
584 | }
585 | }
586 |
587 | function yawas_chrome(color)
588 | {
589 | if (color === 'email')
590 | {
591 | var info = {
592 | "title": document.title,
593 | "url": window.location.href,
594 | "fn": "emailhighlights",
595 | };
596 | sendMessage(info);
597 | return;
598 | }
599 | if (color === 'copytoclipboard')
600 | {
601 | var info = {
602 | "title": document.title,
603 | "url": window.location.href,
604 | "fn": "copytoclipboard",
605 | };
606 | sendMessage(info);
607 | return;
608 | }
609 |
610 | if (color && color !== 'note')
611 | {
612 | currentColor = color;
613 | }
614 | else
615 | {
616 | //currentColor = 'yellow';
617 | }
618 |
619 | var elem = hoverElementOrSelection();
620 | if (elem)
621 | {
622 | hoverElement = elem;
623 | recolor(color);
624 | }
625 | else
626 | {
627 | var wndWithSelection = getWindowWithSelection(window);
628 | if (color === 'note')
629 | yawas_tryHighlight(wndWithSelection,true);
630 | else
631 | yawas_tryHighlight(wndWithSelection);
632 | }
633 | }
634 |
635 | function yawas_remapAnnotations(highlights)
636 | {
637 | return highlightDoc(window,document,highlights);
638 | }
639 |
640 | function yawas_uncompact(wnd,highlights)
641 | {
642 | for (var i=0;i
0)
704 | previousRange = wnd.getSelection().getRangeAt(0);
705 | var scrollLeft = wnd.scrollX;
706 | var scrollTop = wnd.scrollY;
707 | nremapped = 0;
708 | notRemapped = [];
709 | yawas_uncompact(wnd,highlights);
710 | for (var i=0;i '')
753 | {
754 | baseNode.dataset.comment = comment;
755 | //baseNode.dataset.yawasComment = comment;
756 | baseNode.title = comment;
757 | //baseNode.style.borderBottom = '1px dashed black';
758 | }
759 | baseNode.dataset.selection = selectionstring;
760 | baseNode.dataset.yawasOccurence = occurence;
761 | baseNode.dataset.yawasColor = googleColors[color];
762 |
763 | let node = yawas_highlight222(selectionrng, baseNode, googleColors[color]);
764 |
765 | node.addEventListener('mouseover',function (e) {
766 | hoverElement = this;
767 | },false);
768 |
769 | node.addEventListener('mouseout',function (e) {
770 | hoverElement = null;
771 | },false);
772 |
773 | return node;
774 | }
775 |
776 | // on Firefox, we need to select the text before showing the context menu
777 | // on Chrome, somehow the current word is selected when the user right clicks over words
778 | window.oncontextmenu = function () {
779 | if (hoverElement !== null)
780 | {
781 | let selection = window.getSelection();
782 | if (selection.rangeCount > 0) {
783 | selection.removeAllRanges();
784 | }
785 | let range = document.createRange();
786 | range.selectNode(hoverElement);
787 | selection.addRange(range);
788 | }
789 | }
790 |
791 | function childrenToo(docfrag,backgroundColor)
792 | {
793 | docfrag.childNodes.forEach(f => {if (f.style){f.style.backgroundColor = backgroundColor}});
794 | }
795 |
796 | function yawas_highlight222(range, node,backgroundColor)
797 | {
798 | var startContainer = range.startContainer;
799 | var startOffset = range.startOffset;
800 | var endOffset = range.endOffset;
801 | var docfrag = range.extractContents();
802 | childrenToo(docfrag,backgroundColor);
803 | var before = startContainer.splitText(startOffset);
804 | var parent = before.parentNode;
805 | node.appendChild(docfrag);
806 | parent.insertBefore(node, before);
807 | //if (whiteFont(startContainer.parentElement))
808 | // make sure we can always read the text
809 | node.style.color = 'black'
810 | return node;
811 | }
812 |
813 | function updateHighlight(elt,color,newcomment)
814 | {
815 | if (elt)
816 | {
817 | sendMessage({action: "recolor_highlight", url: yawas_getGoodUrl(document), title: document.title, highlightString: hoverElement.dataset.selection, n:hoverElement.dataset.yawasOccurence, newcolor: color, comment:newcomment}, function (res){
818 | if (res && res.error)
819 | {
820 | //console.error(res);
821 | yawas_undohighlight();
822 | if (res.toobig)
823 | alert('Too many characters (>2048 even compacted)!');
824 | }
825 | else
826 | {
827 | if (res && res.highlights)
828 | setCharactersLeft(computeLength(res.highlights));
829 | }
830 | });
831 | }
832 | }
833 |
834 | function hoverElementOrSelection() {
835 | if (hoverElement !== null)
836 | return hoverElement;
837 | var wndWithSelection = getWindowWithSelection(window);
838 | if (!wndWithSelection)
839 | return null;
840 | let rng = wndWithSelection.getSelection().getRangeAt(0);
841 | let elems = document.querySelectorAll('.yawas-highlight');
842 |
843 | for (let i=0;i 0)
862 | annotation += '@' + highlights[i].n;
863 | if (highlights[i].color != 'yellow')
864 | annotation += '#' + highlights[i].color;
865 | annotation += rightMark + ' ';
866 | }
867 | return annotation.length;
868 | }
869 |
870 | function yawas_delete_highlight() {
871 | let elem = hoverElementOrSelection();
872 | if (elem)
873 | {
874 | sendMessage({action: "delete_highlight", url: yawas_getGoodUrl(document), title: document.title, highlightString: elem.dataset.selection, n:elem.dataset.yawasOccurence }, function (res)
875 | {
876 | if (res && res.highlights)
877 | setCharactersLeft(computeLength(res.highlights));
878 | });
879 | childrenToo(elem,null);
880 | var f = document.createDocumentFragment();
881 | while(elem.firstChild)
882 | f.appendChild(elem.firstChild);
883 | elem.parentNode.replaceChild(f,elem);
884 | hoverElement = null;
885 | updateHighlightCaption();
886 | }
887 | }
888 |
889 | var currentHighlight = 0;
890 |
891 | function addStyle(doc,css)
892 | {
893 | var style = document.createElement('style');
894 | style.innerHTML = css;
895 | doc.head.appendChild(style);
896 | }
897 |
898 | function yawas_next_highlight(evt)
899 | {
900 | // prevent text selection
901 | if (evt) {
902 | evt.preventDefault();
903 | evt.stopPropagation();
904 | }
905 | if (!signedin)
906 | return yawas_signin();
907 |
908 | var highlights = document.getElementsByClassName('yawas-highlight');
909 | if (highlights.length==0)
910 | return;
911 | currentHighlight = currentHighlight % highlights.length;
912 | updateHighlightCaption();
913 | let h = highlights[currentHighlight];
914 | h.style.transition = 'opacity 0.3s ease-in-out';
915 | h.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
916 | h.style.opacity = 0.2;
917 | currentHighlight += 1;
918 | setTimeout(function () { h.style.opacity=1.0; }, 300);
919 | }
920 |
921 | window.onhashchange = function (evt) {
922 | askForAnnotations(2000);
923 | };
924 |
925 | if (document.location.hostname === 'toolbar.google.com' && document.location.pathname === '/command' && document.location.search && document.location.search.indexOf('close_browser') !== -1)
926 | {
927 | window.close();
928 | sendMessage({fn: "yawas_toolbar_signed_in"});
929 | }
930 | else if (document.location.href.indexOf('accounts.google.com/ServiceLogin') != -1)
931 | {
932 | //console.error('not asking getannotations for servicelogin window');
933 | }
934 | else
935 | {
936 | //window.addEventListener("keydown", keyListener, false);
937 | if (window.top !== window)
938 | {
939 | //console.error('cookkie_handler not calling getannotations because not top window');
940 | }
941 | else
942 | {
943 | //addScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js");
944 | addHighlightsWrapper();
945 | addStyle(window.document,'.yawas-highlight:hover{opacity:0.6;}.yawas-highlight[data-comment]{border-bottom:1px dashed black}');
946 | askForAnnotations(2000);
947 | }
948 | /*var elems = document.querySelectorAll('*');
949 | for (var i=0;i {
18 | if (res.length > 0) {
19 | yawasBookmarkId = res[0].id;
20 | console.log('yawasBookmarkId=',yawasBookmarkId)
21 | }
22 | else {
23 | chrome.bookmarks.create({title:'Yawas'}, newfolder => {
24 | yawasBookmarkId = newfolder.id;
25 | console.log('yawasBookmarkId=',yawasBookmarkId)
26 | })
27 | }
28 | })
29 |
30 | function getFolderName(url,dateString) {
31 | let res = 'unknown'
32 | //if (dateString)
33 | //res = new Date(dateString).toLocaleDateString('en-US',{year:'numeric',month:'numeri'})
34 | res = new Date(dateString).getFullYear() + '-' + String((new Date(dateString).getMonth()+1)).padStart(2,'0')
35 | //else {
36 | try {
37 | res = new URL(url).hostname.replace('www.','')
38 | } catch (e) {
39 | }
40 | //}
41 | return res
42 | }
43 |
44 | async function remove(id) {
45 | if (!id)
46 | return
47 | return new Promise((resolve,reject) => {
48 | chrome.bookmarks.remove(id,res => resolve(res))
49 | })
50 | }
51 |
52 | async function search(obj) {
53 | return new Promise((resolve,reject) => {
54 | chrome.bookmarks.search(obj,res => resolve(res))
55 | })
56 | }
57 |
58 | function subtree(res) {
59 | let result = []
60 | if (res.url > '')
61 | result.push(res)
62 | if (res.children) {
63 | for (let c of res.children) {
64 | result = result.concat(subtree(c))
65 | }
66 | }
67 | return result
68 | }
69 |
70 | async function getYawasBookmarks() {
71 | return new Promise((resolve,reject) => {
72 | console.log(yawasBookmarkId)
73 | chrome.bookmarks.getSubTree(yawasBookmarkId, res => {
74 | resolve(subtree(res[0]))
75 | })
76 | })
77 | }
78 |
79 | /*
80 | chrome.bookmarks.search({}, async res => {
81 | res.forEach((item, i) => {
82 | chrome.bookmarks.remove(item.id)
83 | });})
84 | */
85 |
86 | async function create(obj) {
87 | return new Promise((resolve,reject) => {
88 | chrome.bookmarks.create(obj,res => resolve(res))
89 | })
90 | }
91 |
92 | async function folderExists(name,parentId) {
93 | parentId = parentId ? parentId : yawasBookmarkId
94 | let res = await search({title:name})
95 | return res.find(f => f.parentId === parentId)
96 | }
97 |
98 | async function createFolder(year,month) {
99 | let yearFolder = await folderExists(year)
100 | if (!yearFolder)
101 | yearFolder = await create({title:year,parentId: yawasBookmarkId})
102 | let monthFolder = await folderExists(month,yearFolder.id)
103 | if (!monthFolder)
104 | monthFolder = await create({title:month,parentId: yearFolder.id})
105 | return monthFolder
106 | }
107 |
108 | async function createBookmark(obj,date) {
109 | let year = ''+date.getFullYear()
110 | let month = date.toLocaleDateString('en-US',{month:'long'})
111 | let folder = await createFolder(year,month)
112 | //console.log(year,month,folder)
113 | await create({title:obj.title,url:obj.url,parentId: folder.id})
114 | }
115 |
116 | chrome.runtime.onMessage.addListener(requestCallback);
117 |
118 | chrome.storage.sync.get({
119 | handlePDF: false,
120 | saveLocally: false,
121 | saveChromeBookmarks: true,
122 | }, function(items) {
123 | if (items)
124 | {
125 | handlePDF = items.handlePDF;
126 | saveLocally = items.saveLocally;
127 | saveChromeBookmarks = items.saveChromeBookmarks;
128 | }
129 | });
130 |
131 | chrome.storage.onChanged.addListener(function(changes, namespace) {
132 | for (key in changes)
133 | {
134 | var storageChange = changes[key];
135 | if (key === 'handlePDF')
136 | {
137 | handlePDF = storageChange.newValue;
138 | }
139 | if (key === 'saveLocally')
140 | {
141 | saveLocally = storageChange.newValue;
142 | }
143 | if (key === 'saveChromeBookmarks')
144 | {
145 | saveChromeBookmarks = storageChange.newValue;
146 | }
147 | }
148 | });
149 |
150 | yawas_setStatusIcon("off");
151 |
152 | var INSTAPAPER_PREFIX = "http://www.instapaper.com/text?u="
153 | var VIEWTEXT_PREFIX = "http://viewtext.org/article?url="
154 | var READABILITY_PREFIX = "http://www.readability.com/m?url="
155 |
156 | function stripMobilizer(url)
157 | {
158 | var i = url.indexOf(VIEWTEXT_PREFIX);
159 | if (i == 0)
160 | return decodeURIComponent(url.substring(VIEWTEXT_PREFIX.length));
161 |
162 | i = url.indexOf(INSTAPAPER_PREFIX);
163 | if (i == 0)
164 | return decodeURIComponent(url.substring(INSTAPAPER_PREFIX.length));
165 |
166 | i = url.indexOf(READABILITY_PREFIX);
167 | if (i == 0)
168 | return decodeURIComponent(url.substring(READABILITY_PREFIX.length));
169 |
170 | return url;
171 | }
172 |
173 | // dangerous deletes all your chrome.Bookmarks
174 | async function deleteYawasFolder() {
175 | let res = await search({title:'Yawas'})
176 | for (let item of res) {
177 | await chrome.bookmarks.remove(item.id)
178 | }
179 | }
180 |
181 | /*async function moveBookmarksIntoFolders() {
182 | let res = await search({})
183 | for (let item in res) {
184 | if (item.parentId === yawasBookmarkId) {
185 | let folder = getFolderName(item.url)
186 | let res = await search({title:folder})
187 | if (res.length === 1) {
188 | chrome.bookmarks.move(item.id,{parentId:res.id})
189 | } else {
190 | await createBookmark({title:item.title,url:item.url})
191 | }
192 | chrome.bookmarks.remove(item.id)
193 | }
194 | }
195 | }*/
196 |
197 | /*async function importAllBookmarks(callback)
198 | {
199 | //let existing = await search({})
200 | let existing = await getYawasBookmarks()
201 | //existing = existing.filter(item => item.url > '')
202 | let existingUrls = {};
203 | for (let item of existing) {
204 | existingUrls[item.url] = true;
205 | await remove(item.id); // will be recreated properly at the end
206 | }
207 | var start = 0;
208 | //var list = [];
209 | var loop = true;
210 | var n = 0;
211 | let max = 800;
212 | let importedUrls = new Set()
213 |
214 | // Laurent: note that output=xml returns ALL bookmarks along with tags
215 | while (loop)// && n <= max)
216 | {
217 | console.log('start=',start);
218 | let urlBookmarks = 'https://www.google.com/bookmarks/lookup?output=rss&start=' + start;
219 | let res = null
220 | try {
221 | res = await fetch(urlBookmarks);
222 | } catch (fetcherror) {
223 | return callback(n,'error retrieving online google bookmarks')
224 | }
225 | chrome.runtime.sendMessage({ msg: "importMessage", start: start, n: n });
226 | let str = await res.text();
227 | let xml = (new window.DOMParser()).parseFromString(str, "text/xml");
228 | let items = xml.querySelectorAll('item');
229 | for (let i of items) {
230 | let title = i.querySelector('title').textContent;
231 | let url = i.querySelector('link').textContent;
232 | let date = i.querySelector('pubDate')? new Date(i.querySelector('pubDate').textContent) : null;
233 | if (url.indexOf('file:///') === 0) {
234 | console.error('not importing file bookmark',url)
235 | } else if (!(url > '')) {
236 | console.error('url undefined',url)
237 | }
238 | else {
239 | importedUrls.add(url);
240 | //let labels = [...i.querySelectorAll('bkmk_label')].map(a => a.textContent).join(",");
241 | //console.log(labels)
242 | let annotations = i.querySelector('bkmk_annotation')?i.querySelector('bkmk_annotation').textContent.trim():'';
243 | n++;
244 | let newTitle = title;
245 | if (annotations > '')
246 | newTitle += '#__#' + annotations;
247 | if (existingUrls[url]) {
248 | await remove(existingUrls[url].id);
249 | }
250 | await createBookmark({title:newTitle, url:url},date)
251 | }
252 | }
253 | start += items.length;
254 | if (items.length === 0)
255 | loop = false;
256 | }
257 | // recreate the ones not imported from Google Bookmarks
258 | for (let item of existing) {
259 | if (!importedUrls.has(item.url))
260 | {
261 | console.log('creating from existing',item.url)
262 | await createBookmark({title:item.title,url:item.url},new Date(item.dateAdded))
263 | }
264 | }
265 |
266 | callback(n);
267 | }*/
268 |
269 | //let getannotationscb = {};
270 | //let storeannotationscb = {};
271 |
272 |
273 | function isSignin(url)
274 | {
275 | let lowUrl = url.toLowerCase();
276 | return lowUrl.indexOf('accounts.google') !== -1 && (lowUrl.indexOf('signin') !== -1 || lowUrl.indexOf('login') !== -1);
277 | }
278 |
279 | var abortTimerId = null;
280 | var requestTimeout = 1000 * 5; // 5 seconds
281 |
282 | function yawas_getElement(xml, elementname)
283 | {
284 | var e = xml.getElementsByTagName(elementname);
285 | if (e.length == 0)
286 | e = xml.getElementsByTagName('smh:' + elementname);
287 | if (e==null)
288 | console.log('yawas_getElement null for: ' + elementname);
289 | return e;
290 | }
291 |
292 | function clearAbortTimer() {
293 | if (abortTimerId != null)
294 | {
295 | window.clearTimeout(abortTimerId);
296 | abortTimerId = null;
297 | }
298 | }
299 |
300 | async function yawas_getAnnotations_chrome_bookmarks(webUrl,cb)
301 | {
302 | let url = purifyURL(webUrl);
303 | let result = await search({url:url})
304 | //console.log(result)
305 | let annotations = '';
306 | let labels = '';
307 | result.forEach((item, i) => {
308 | let chunks = item.title.split('#__#');
309 | if (chunks.length > 1) {
310 | annotations += chunks[1];
311 | }
312 | });
313 | if (annotations.length > 0) {
314 | yawas_remapAnnotations(webUrl,annotations,labels,cb);
315 | }
316 | }
317 |
318 | function yawas_getAnnotations_chrome_storage(webUrl,cb) {
319 | var keyName = purifyURL(webUrl).hashCode();
320 | var obj = {};
321 | obj[keyName] = null;
322 | chrome.storage.sync.get(obj,function(items) {
323 | if (items && items[keyName])
324 | {
325 | yawas_remapAnnotations(webUrl,items[keyName].annotations,items[keyName].labels,cb);
326 | }
327 | });
328 | }
329 |
330 | async function yawas_getAnnotations(webUrl,cb)
331 | {
332 | //if (saveLocally)
333 | // return yawas_getAnnotations_chrome_storage(webUrl)
334 | if (saveChromeBookmarks)
335 | return await yawas_getAnnotations_chrome_bookmarks(webUrl,cb);
336 |
337 | googleSignature = null; // invalidate signature
338 |
339 | webUrl = purifyURL(webUrl);
340 | //var url = "https://www.google.com/bookmarks/find?output=rss&q=" + encodeURIComponent(webUrl);
341 | // escape fixes issue https://github.com/ldenoue/yawas/issues/11 because url had ' in it
342 | var url = "https://www.google.com/bookmarks/find?output=rss&q=" + escape(webUrl);
343 | var xhr = new XMLHttpRequest();
344 | //xhr.withCredentials = true;
345 | abortTimerId = window.setTimeout(function() {
346 | //console.error('aborted GET for url=',url);
347 | xhr.abort(); // synchronously calls onreadystatechange
348 | yawas_setStatusIcon("error");
349 | cb({error:'network error'});
350 | }, requestTimeout);
351 |
352 | xhr.open("GET",url,true);
353 | xhr.onerror = function(error) {
354 | //console.log('xhr error',error);
355 | console.log('xhr error');
356 | clearAbortTimer();
357 | }
358 |
359 | xhr.onreadystatechange = function () {
360 | if (xhr.readyState === 4) {
361 | if (xhr.status === 200)
362 | {
363 | clearAbortTimer();
364 | if (xhr.responseURL === url) {
365 | //console.log('got what we wanted, hooray!');
366 | }
367 | else {
368 | yawas_setStatusIcon("off");
369 | if (xhr.responseURL.indexOf('/ServiceLogin') !== -1)
370 | {
371 | cb({error:'logged out',signedout:true,url:xhr.responseURL});
372 | }
373 | else
374 | cb({error:'logged out',signedout:true});
375 |
376 | return;
377 | }
378 |
379 | if (xhr.responseXML === null)
380 | {
381 | yawas_setStatusIcon("error");
382 | cb({error:'no XML'});
383 | return;
384 | }
385 | var signature = yawas_getElement(xhr.responseXML,'signature'); //xhr.responseXML.getElementsByTagName('signature');
386 | var gooSignature = '';
387 | if (signature.length>0)
388 | gooSignature = signature[0].childNodes[0].nodeValue;
389 | googleSignature = gooSignature;
390 | //console.log('setting googleSignature to ' + googleSignature);
391 |
392 | yawas_setStatusIcon("on");
393 |
394 | var items = yawas_getElement(xhr.responseXML, 'item'); //xhr.responseXML.getElementsByTagName('item');
395 | if (items.length === 0)
396 | {
397 | //console.error('items.length == 0');
398 | return cb({noannotation:true});
399 | }
400 | else if (items.length >= 1)
401 | {
402 | for (var i=0;i0)
408 | webAnnotation = annotation[0].childNodes[0].nodeValue;
409 |
410 | var labels = yawas_getElement(items[i],'bkmk_label'); //items[i].getElementsByTagName('bkmk_label');
411 | var webLabels = '';
412 | if (labels.length>0)
413 | {
414 | for (var x=0;x 0)
441 | {
442 | var tab = tabs[0];
443 | //chrome.tabs.sendMessage(tab.id, json, function(response) {});
444 | const port = chrome.tabs.connect(tab.id);
445 | port.onDisconnect = function (err) { console.error('disconnected',err)};
446 | /*port.onMessage.addListener((response) => {
447 | console.error('port.onMessage response=',response);
448 | });*/
449 | port.postMessage(json);
450 | }
451 | });
452 | }
453 |
454 | String.prototype.hashCode = function() {
455 | var hash = 0, i, chr;
456 | if (this.length === 0) return hash;
457 | for (i = 0; i < this.length; i++) {
458 | chr = this.charCodeAt(i);
459 | hash = ((hash << 5) - hash) + chr;
460 | hash |= 0; // Convert to 32bit integer
461 | }
462 | return 'yawas'+hash;
463 | };
464 |
465 | function yawas_remapAnnotations(url, annotations, labels,cb)
466 | {
467 | if (annotations === null || annotations === undefined)
468 | {
469 | //console.error('yawas_remapAnnotations called without annotations',url,annotations,labels);
470 | return cb({error:'annotations===null'});
471 | }
472 | var url = purifyURL(url);
473 | cachedAnnotations[url] = annotations;
474 | cachedLabels[url] = labels;
475 | var highlights = annotationToArray(annotations);
476 | chrome.action.setBadgeText({'text':''+highlights.length});
477 | chrome.action.setTitle({title:'Yawas'});
478 | urls[url] = highlights.length;
479 | cb({annotations:highlights});
480 | }
481 |
482 | function formatAnnotation(text)
483 | {
484 | var newtext = text.replace(/“/gi,leftMark).replace(/”/gi,rightMark);
485 | //newtext = newtext.replace(/“/gi,leftMark).replace(/”/gi,rightMark);
486 | //newtext = text.replace(/<>/gi,'”');
487 | //newtext = newtext.replace(/“/gi,'“').replace(/”/gi,'”');
488 | return newtext;
489 | }
490 |
491 | function yawas_compact(webAnnotation)
492 | {
493 | var highlights = annotationToArray(webAnnotation);
494 | for (var i=0;i= 16)
501 | {
502 | sel = len + '~~' + sel.substring(0,8) + sel.substring(len-8);
503 | highlights[i].selection = sel;
504 | }
505 | }
506 | return arrayToAnnotation(highlights)
507 | }
508 |
509 | function yawas_storeHighlight(webUrl,title,highlight,occurence,couleur,pagenumber,cb)
510 | {
511 | var qurl = purifyURL(webUrl);
512 |
513 | // new version uses cache and google signature
514 | var webAnnotation = cachedAnnotations[qurl];
515 | var webLabels = cachedLabels[qurl];
516 | if (!webAnnotation)
517 | {
518 | //console.error('no webannotation cached for',webUrl,qurl);
519 | webAnnotation = '';
520 | }
521 | if (!webLabels)
522 | webLabels = '';
523 | webAnnotation = formatAnnotation(webAnnotation);
524 | if (occurence === 0)
525 | {
526 | if (pagenumber)
527 | webAnnotation += leftMark + highlight + "@" + occurence + ',' + pagenumber;
528 | else
529 | webAnnotation += leftMark + highlight;
530 | }
531 | else
532 | {
533 | webAnnotation += leftMark + highlight + "@" + occurence;
534 | if (pagenumber)
535 | webAnnotation += ',' + pagenumber;
536 | }
537 | if (couleur != 'yellow')
538 | webAnnotation += '#' + couleur;
539 | webAnnotation += rightMark + " ";
540 | let pureLen = webAnnotation.length;
541 | if (!saveChromeBookmarks && webAnnotation.length > 2048)
542 | {
543 | console.log('too long so compacting annotations',qurl,webAnnotation.length);
544 | var compacted = yawas_compact(webAnnotation);
545 | if (compacted.length > 2048)
546 | {
547 | yawas_setStatusIcon('error');
548 | return cb({toobig:true});
549 | }
550 | else
551 | {
552 | console.log('compacted format len=',compacted.length);
553 | webAnnotation = compacted;
554 | }
555 | }
556 | yawas_storeHighlightsNow(qurl, title, webLabels, webAnnotation, googleSignature, function (res){
557 | if (res.ok)
558 | {
559 | yawas_setStatusIcon('on');
560 | var nannotations = webAnnotation.split(rightMark).length-1;
561 | chrome.action.setBadgeText({'text':''+nannotations});
562 | chrome.action.setTitle({title:'Yawas'});
563 | urls[qurl] = nannotations;
564 | cachedAnnotations[qurl] = webAnnotation;
565 | return cb({addedhighlight:true,pureLen:pureLen});
566 | }
567 | else
568 | {
569 | yawas_setStatusIcon('error');
570 | return cb(res);
571 | }
572 | });
573 | }
574 |
575 | async function yawas_storeHighlightsNow(webUrl, title, labels, annotations, gooSignature, callback)
576 | {
577 | if (saveLocally)
578 | {
579 | var keyName = purifyURL(webUrl).hashCode();
580 | var obj = {};
581 | obj[keyName] = {title:title,labels:labels,annotations:annotations};
582 | chrome.storage.sync.set(obj,function() {
583 | });
584 | callback({ok:true});
585 | return;
586 | }
587 | if (saveChromeBookmarks)
588 | {
589 | let url = purifyURL(webUrl)
590 | let obj = {url: url, title: title + '#__#' + annotations};
591 | var folderName = new Date().toLocaleDateString('en-US',{year:'numeric',month:'short'})
592 | //console.log('obj=',obj);
593 | let result = await search({url:url})
594 | if (result && result.length > 0)
595 | {
596 | console.log('updating bookmark')
597 | chrome.bookmarks.update(result[0].id,obj);
598 | } else {
599 | console.log('creating bookmark')
600 | createBookmark(obj,new Date())
601 | }
602 | callback({ok:true});
603 | return;
604 | }
605 |
606 |
607 | if (gooSignature == null)
608 | {
609 | callback({error:'not signed in',signedout:true});
610 | return;
611 | }
612 | webUrl = purifyURL(webUrl);
613 | var xhr = new XMLHttpRequest();
614 | abortTimerId = window.setTimeout(function() {
615 | console.log('aborting yawas_storeHighlightsNow');
616 | xhr.abort(); // synchronously calls onreadystatechange
617 | callback({error:'timeout'});
618 | }, requestTimeout);
619 |
620 | var url = "https://www.google.com/bookmarks/mark?hl=en";
621 | xhr.open("POST", url);
622 | xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
623 | xhr.onerror = function(error) {clearAbortTimer();}
624 | xhr.onreadystatechange = function () {
625 | if (xhr.readyState == 4) {
626 | if (xhr.status == 200)
627 | {
628 | clearAbortTimer();
629 | if (xhr.responseURL === url) {
630 | //console.log('got what we wanted, hooray!');
631 | }
632 | else {
633 | callback({error:'not signed in',signedout:true});
634 | return;
635 | }
636 |
637 | var signin = xhr == null || xhr.responseText.indexOf('Sign in') != -1;
638 | if (signin)
639 | {
640 | callback({error:'not signed in',signedout:true});
641 | }
642 | else
643 | {
644 | callback({ok:true});
645 | }
646 | }
647 | else
648 | {
649 | clearAbortTimer();
650 | }
651 |
652 | }
653 | };
654 | var encoded = "sig=" + gooSignature;
655 | encoded += "&title=" + encodeURIComponent(title);
656 | encoded += "&bkmk=" + encodeURIComponent(webUrl);
657 | encoded += "&labels=" + encodeURIComponent(labels);
658 | encoded += "&annotation=" + encodeURIComponent(annotations);
659 | xhr.send(encoded);
660 | }
661 |
662 | function refreshBrowserAction(url)
663 | {
664 | var qurl = purifyURL(url);
665 | if (urls[qurl] != undefined)
666 | {
667 | chrome.action.setBadgeText({'text':''+urls[qurl]});
668 | }
669 | else
670 | chrome.action.setBadgeText({'text':'0'});
671 | chrome.action.setTitle({title:'Yawas'});
672 | }
673 |
674 | function copyTextToClipboard(text) {
675 | sendMessageActiveTab({action:'yawas_copytoclipboard',payload: text})
676 | }
677 |
678 | let googleColors = [];
679 | googleColors['yellow'] = '#FFFF66';
680 | googleColors['blue'] = '#0df';
681 | googleColors['red'] = '#ff9999';
682 | googleColors['green'] = '#99ff99';
683 | googleColors['white'] = 'transparent';
684 |
685 | function yawas_copyclipboard(url,title, html = true)
686 | {
687 | url = purifyURL(url);
688 | if (title.trim().length == 0)
689 | title = 'no title';
690 | var webAnnotation = cachedAnnotations[url];
691 | var highlights = annotationToArray(webAnnotation);
692 | if (html) {
693 | var body = '' + title + ' ';
694 | for (var i=0;i>\n';
699 | body += '' + highlights[i].selection + ' '
700 | }
701 | body += ' '
702 | copyTextToClipboard(body);
703 |
704 | } else {
705 | var body = title + '\n' + url + '\n';
706 | for (var i=0;i>\n';
711 | }
712 | copyTextToClipboard(body);
713 | }
714 | }
715 |
716 | function yawas_email(url,title)
717 | {
718 | url = purifyURL(url);
719 | if (title.trim().length == 0)
720 | title = 'no title';
721 | var webAnnotation = cachedAnnotations[url];
722 | var highlights = annotationToArray(webAnnotation);
723 | var body = title + '\n\n' + url + '\n\n';
724 | for (var i=0;i>\n';
729 | }
730 | var compose = "https://mail.google.com/mail/?extsrc=mailto&url=" + encodeURIComponent("mailto:?subject=" + title + "&body=" + body);
731 | /*var width = Math.min(screen.width-40,640);
732 | var height = Math.min(screen.height-40,480);
733 | var left = Math.floor( (screen.width - width) / 2);
734 | var top = Math.floor( (screen.height - height) / 2);
735 | window.open(compose,'email_popup','left='+left+',top='+top+',height='+height+'px,width='+width+'px,resizable=1');*/
736 | chrome.tabs.create({url:compose});
737 | }
738 |
739 | // deprecated in Chrome and does not work in Firefox
740 | /*chrome.tabs.onSelectionChanged.addListener(function(tabId, selectInfo) {
741 | chrome.tabs.query({active:true,currentWindow: true}, function(tabs) {
742 | if (tabs && tabs.length > 0 && tabs[0].url)
743 | {
744 | var tab = tabs[0];
745 | refreshBrowserAction(tab.url);
746 | }
747 | });
748 | });*/
749 |
750 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
751 | if (tab && tab.url)
752 | refreshBrowserAction(tab.url);
753 | });
754 |
755 | function arrayToAnnotation(highlights)
756 | {
757 | var annotation = '';
758 | for (var i=0;i 0)
766 | annotation += '@' + highlights[i].n;
767 | if (highlights[i].color != 'yellow')
768 | annotation += '#' + highlights[i].color;
769 | annotation += rightMark + ' ';
770 | }
771 | return annotation;
772 | }
773 |
774 | function annotationToArray(annotations)
775 | {
776 | if (!(annotations > ''))
777 | return [];
778 | if (annotations.trim().length === 0)
779 | return [];
780 | var chuncks = annotations.split(rightMark);
781 | var highlights = [];
782 | for (var i=0;i=0)
786 | {
787 | var comment = chuncks[i].substring(0,j).trim();
788 | var highlight = chuncks[i].substring(j+lenQuote);
789 | var k = highlight.lastIndexOf('@');
790 | var occurence = 0;
791 | var couleur = 'yellow';
792 | var pagenumber = null;
793 | if (k > 0)
794 | {
795 | try {
796 | var string = highlight.substring(k+1);
797 | var c = highlight.indexOf('#',k);
798 | if (c != -1)
799 | {
800 | var trail = highlight.substring(k+1,c);
801 | var chk = trail.split(',');
802 | //occurence = parseInt(highlight.substring(k+1,c));
803 | occurence = parseInt(chk[0]);
804 | if (chk.length===2)
805 | pagenumber = parseInt(chk[1]);
806 | couleur = highlight.substring(c+1);
807 | }
808 | else
809 | {
810 | //occurence = parseInt(highlight.substring(k+1));
811 | var trail = highlight.substring(k+1);
812 | var chk = trail.split(',');
813 | occurence = parseInt(chk[0]);
814 | if (chk.length===2)
815 | pagenumber = parseInt(chk[1]);
816 | }
817 | highlight = highlight.substring(0,k);
818 | } catch (eint) { occurence = 0; }
819 | }
820 | else
821 | {
822 | var c = highlight.lastIndexOf('#');
823 | if (c>0)
824 | {
825 | couleur = highlight.substring(c+1);
826 | highlight = highlight.substring(0,c);
827 | }
828 | }
829 | highlight = highlight.trim();//yawas_TrimString(highlight);
830 | var obj = {p:pagenumber,selection:highlight,n:occurence,color:couleur,comment:comment};
831 | highlights.push(obj);
832 | }
833 | }
834 | return highlights;
835 | }
836 |
837 | /*async function startImport() {
838 | importAllBookmarks(function (n,error) {
839 | chrome.runtime.sendMessage({ msg: "importMessage", n: n, error: error });
840 | });
841 | }*/
842 |
843 | function requestCallback(request, sender, sendResponse)
844 | {
845 | var tabURL = purifyURL(request.url);
846 | var tabTitle = request.title;
847 | //console.log('requestCallback',request);
848 | //if(request.msg == "startImportFunc")
849 | // startImport();
850 | if (request.fn === 'yawas_getAnnotations')
851 | {
852 | yawas_getAnnotations(request.url,function(res){
853 | signedin = !res.error;
854 | sendResponse(res);
855 | });
856 | }
857 | /*else if (request.fn === 'yawas_donate')
858 | {
859 | chrome.tabs.create({ url: donate_url });
860 | sendResponse({});
861 | }*/
862 | else if (request.fn === 'yawas_toolbar_signed_in')
863 | {
864 | signedin = true;
865 | sendResponse({});
866 | }
867 | else if (request.fn === 'addhighlight')
868 | {
869 | yawas_storeHighlight(request.url,request.title,request.selection,request.occurence,request.couleur,null,function (res){
870 | signedin = !res.error;
871 | sendResponse(res);
872 | });
873 | }
874 | else if (request.fn === 'addhighlightpdf')
875 | {
876 | yawas_storeHighlight(request.url,request.title,request.selection,request.occurence,request.couleur,request.p,function(res){
877 | sendResponse(res);
878 | });
879 | }
880 | else if (request.fn === 'emailhighlights')
881 | {
882 | yawas_email(request.url,request.title);
883 | sendResponse({});
884 | }
885 | else if (request.fn === 'copytoclipboard')
886 | {
887 | yawas_copyclipboard(request.url,request.title);
888 | sendResponse({});
889 | }
890 | else if (request.action == 'delete_highlight')
891 | delHighlightNow(request.highlightString,request.n,tabURL,tabTitle,null,function (res){
892 | sendResponse(res);
893 | });
894 | else if (request.action == 'delete_pdf_highlight')
895 | delHighlightNow(request.highlightString,request.n,request.url,request.title,request.p,function(res){
896 | sendResponse(res);
897 | });
898 | else if (request.action == 'recolor_highlight')
899 | updateHighlight(request.highlightString,request.n,request.newcolor,request.comment,tabURL,tabTitle,null,function(res){
900 | sendResponse(res);
901 | });
902 | else if (request.action == 'recolor_pdf_highlight')
903 | updateHighlight(request.highlightString,request.n,request.newcolor,'',request.url,request.title,request.p,function(res){
904 | sendResponse(res);
905 | });
906 |
907 | // important: we want to use sendResponse asynchronously sometimes (e.g. fetching annotations using XHR)
908 | return true;
909 |
910 | }
911 |
912 | function updateHighlight(fragment, occurence, newcolor, comment, url, title,pagenumber,cb)
913 | {
914 | var qurl = url;
915 | var j = qurl.lastIndexOf('/index.htm');
916 | if (j == -1)
917 | j = qurl.lastIndexOf('/index.html');
918 | if (j != -1)
919 | qurl = qurl.substring(0,j+1);
920 | webAnnotation = cachedAnnotations[qurl];
921 | if (!webAnnotation)
922 | {
923 | return cb({error:'no annotation found'});
924 | }
925 |
926 | var highlights = annotationToArray(webAnnotation);
927 | var idx = -1;
928 | for (var i=0;i 2048)
957 | return cb({error:'too long',toobig:true});
958 | yawas_storeHighlightsNow(url, title, webLabels, webAnnotation, googleSignature, function (res){
959 | if (res.ok)
960 | {
961 | cachedAnnotations[qurl] = webAnnotation;
962 |
963 | cb({highlights:highlights});
964 | }
965 | else
966 | cb(res);
967 | });
968 | }
969 |
970 | }
971 |
972 | function delHighlightNow(fragment,occurence,url,title,pagenumber,cb)
973 | {
974 | var qurl = purifyURL(url);
975 | webAnnotation = cachedAnnotations[qurl];
976 | if (!webAnnotation)
977 | {
978 | return cb({error:'no annotation found'});
979 | }
980 |
981 | var highlights = annotationToArray(webAnnotation);
982 | var idx = -1;
983 | for (var i=0;i 1)
1035 | return decodeURIComponent(comps[1])
1036 | else
1037 | return href;
1038 | }
1039 |
1040 | /*chrome.contextMenus.create({
1041 | "id" : "donate",
1042 | "title" : "Donate💰",
1043 | "type" : "normal",
1044 | "contexts" : ["selection","page"],
1045 | "onclick" : getDonateHandler()
1046 | });*/
1047 |
1048 | chrome.contextMenus.onClicked.addListener((info,tab) => {
1049 | if (info.menuItemId === 'delete')
1050 | sendMessageActiveTab({action:'yawas_delete_highlight'})
1051 | else if (info.menuItemId === 'copyclipboard') {
1052 | let url = isPDF(tab.url);
1053 | let title = tab.title;
1054 | yawas_copyclipboard(url,title);
1055 | } else if (info.menuItemId === 'email') {
1056 | let url = isPDF(tab.url);
1057 | let title = tab.title;
1058 | yawas_email(url,title);
1059 | } else if (info.menuItemId === 'search')
1060 | chrome.tabs.create({url:chrome.runtime.getURL('localsearch.html')});
1061 | else if (info.menuItemId === 'edit') {
1062 | let possiblePDFUrl = isPDF(info.pageUrl);
1063 | chrome.tabs.create({url:chrome.runtime.getURL('localedit.html?url=' + encodeURIComponent(purifyURL(possiblePDFUrl)))});
1064 | } else {
1065 | let color = info.menuItemId;
1066 | sendMessageActiveTab({action:'yawas_chrome',color:color,url:info.pageUrl});
1067 | }
1068 | })
1069 |
1070 | chrome.contextMenus.create({
1071 | "id" : "yellow",
1072 | "title" : "Yellow",// (Ctrl-Shift-Y)",
1073 | "type" : "normal",
1074 | "contexts" : ["selection"],
1075 | });
1076 | chrome.contextMenus.create({
1077 | "id" : "red",
1078 | "title" : "Red",// (Ctrl-Shift-R)",
1079 | "type" : "normal",
1080 | "contexts" : ["selection"],
1081 | });
1082 | chrome.contextMenus.create({
1083 | "id" : "blue",
1084 | "title" : "Blue",// (Ctrl-Shift-B)",
1085 | "type" : "normal",
1086 | "contexts" : ["selection"],
1087 | });
1088 | chrome.contextMenus.create({
1089 | "id" : "green",
1090 | "title" : "Green",// (Ctrl-Shift-G)",
1091 | "type" : "normal",
1092 | "contexts" : ["selection"],
1093 | });
1094 |
1095 | chrome.contextMenus.create({
1096 | "id" : "note",
1097 | "title" : "Comment",// (Ctrl-Shift-C)",
1098 | "type" : "normal",
1099 | "contexts" : ["selection"],
1100 | });
1101 |
1102 | chrome.contextMenus.create({
1103 | "id" : "delete",
1104 | "title" : "Delete",// (Ctrl-Shift-D)",
1105 | "type" : "normal",
1106 | "contexts" : ["selection"],
1107 | });
1108 |
1109 | chrome.contextMenus.create({
1110 | "id" : "copyclipboard",
1111 | "title" : "Copy",
1112 | "type" : "normal",
1113 | "contexts" : ["page"],
1114 | });
1115 |
1116 | chrome.contextMenus.create({
1117 | "id" : "email",
1118 | "title" : "Email",
1119 | "type" : "normal",
1120 | "contexts" : ["page"],
1121 | });
1122 |
1123 | chrome.contextMenus.create({
1124 | "id" : "search",
1125 | "title" : "Search",
1126 | "type" : "normal",
1127 | "contexts" : ["page"],
1128 | });
1129 |
1130 | chrome.contextMenus.create({
1131 | "id" : "edit",
1132 | "title" : "Edit",
1133 | "type" : "normal",
1134 | "contexts" : ["page"],
1135 | });
1136 |
1137 | chrome.commands.onCommand.addListener(function(command) {
1138 | if (command === 'yawas-yellow')
1139 | sendMessageActiveTab({action:'yawas_chrome',color:'yellow'});
1140 | else if (command === 'yawas-red')
1141 | sendMessageActiveTab({action:'yawas_chrome',color:'red'});
1142 | else if (command === 'yawas-blue')
1143 | sendMessageActiveTab({action:'yawas_chrome',color:'blue'});
1144 | else if (command === 'yawas-green')
1145 | sendMessageActiveTab({action:'yawas_chrome',color:'green'});
1146 | else if (command === 'yawas-delete')
1147 | sendMessageActiveTab({action:'yawas_delete_highlight'});
1148 | else if (command === 'yawas-note')
1149 | sendMessageActiveTab({action:'yawas_chrome',color:'note'});
1150 | });
1151 |
1152 | function purifyURL(href)
1153 | {
1154 | if (href && href.indexOf('https://mail.google') === 0)
1155 | return href;
1156 |
1157 | try {
1158 | var url = stripMobilizer(href);
1159 | var pos = url.indexOf('#');
1160 | if (pos > 0)
1161 | url = url.substring(0,pos);
1162 | url = url.replace(/[?&]utm_.*/,'');
1163 | url = url.replace(/[?&]WT\..*/,'');
1164 | url = url.replace(/[?&]ns_.*/,'');
1165 | url = url.replace(/[?&]rand=.*/,'');
1166 | url = url.replace(/[?&]src=.*/,'');
1167 | url = url.replace(/[?&]imm_mid=.*/,'');
1168 | url = url.replace(/[?&]cmp=.*/,'');
1169 | url = url.replace(/[?&]ncid=.*/,'');
1170 | url = url.replace(/[?&]cps=.*/,'');
1171 | url = url.replace(/[?&]mc_cid=.*/,'');
1172 | url = url.replace(/[?&]mc_eid=.*/,'');
1173 | url = url.replace(/[?&]mbid=.*/,'');
1174 | if (url.indexOf('nytimes.com')!=-1)
1175 | url = url.split('?')[0];
1176 | return url;
1177 | } catch (eurl) { return href; }
1178 | }
1179 |
--------------------------------------------------------------------------------