window.MXOBJ = MXOBJ = window.MXOBJ||{}; MXOBJ.clickableWords = {}; if (!MXOBJ.isSelectionDisabled) MXOBJ.isSelectionDisabled = function(e) {try{return e.getAttribute('selectionDisabled')==='1';} catch(e) {return false;}}; if (!MXOBJ.disableSelection) MXOBJ.disableSelection = function(e) {if(null!=e){"undefined"!=typeof e.onselectstart?(e.onselectstart_ORIG=e.onselectstart,e.onselectstart=function(){return!1}):null!=e.style&&"undefined"!=typeof e.style.MozUserSelect?(e.style.MozUserSelect_ORIG=e.style.MozUserSelect,e.style.MozUserSelect="none"):(e.onmousedown_ORIG=e.onmousedown,e.onmousedown=function(){return!1}),null!=e.style&&(e.cursor_ORIG=e.style.cursor,e.style.cursor="default");try{e.setAttribute("selectionDisabled","1")}catch(t){}}}; if (!MXOBJ.enableSelection) MXOBJ.enableSelection = function(e) {null!=e&&("undefined"!=typeof e.onselectstart?e.onselectstart=e.onselectstart_ORIG:"undefined"!=typeof e.style.MozUserSelect?e.style.MozUserSelect=e.style.MozUserSelect_ORIG:e.onmousedown=e.onmousedown_ORIG,e.style.cursor=e.cursor_ORIG,e.removeAttribute("selectionDisabled"))}; MXOBJ.attachEvent = MXOBJ.attachEvent || function(e,t,f) {if (e&&e.addEventListener)e.addEventListener(t, f, true); else e&&e.attachEvent('on'+t, f);}; if (!MXOBJ.arrayContains) MXOBJ.arrayContains = function(needle, arr) {return (arr.indexOf(needle) > -1);}; // http://stackoverflow.com/questions/7563169/detect-which-word-has-been-clicked-on-within-a-text MXOBJ.clickableWords.puncts = ['.',',','!','?',':',';']; MXOBJ.clickableWords.setOnWordClick = function(elem, callbackFunc, collapseSelection, button) { if (!elem) {return;} let parent = elem; while (parent) { if (MXOBJ.isSelectionDisabled(parent)) {MXOBJ.enableSelection(parent);} parent = parent.parentNode; } let fn = function(evt) { evt=evt||window.event; if (evt.button===2) {MXOBJ.contextMenu.disable(MXOBJ.contextMenu.isEnabled() ? 1000 : -1);} let parent = elem; let disabledSelections = []; while (parent) { if (MXOBJ.isSelectionDisabled(parent)) {disabledSelections.push(parent);MXOBJ.enableSelection(parent);} parent = parent.parentNode; } s = window.getSelection(); let node = s.anchorNode; if (node==null) {return;} let range = s.getRangeAt(0); if (range==null) {return;} while(range.toString().indexOf(' ') !== 0 && range.startOffset>0) { range.setStart(node,(range.startOffset -1)); } if (range.toString().indexOf(' ')===0) {range.setStart(node, range.startOffset + 1);} do { if (node.nodeValue==null || range.endOffset===node.nodeValue.length) {break;} range.setEnd(node,range.endOffset + 1); } while(range.toString().indexOf(' ') === -1 && range.toString().trim() !== ''); let str = range.toString().trim(); // pdf.js stuff for broken words (into multi divs) if (MXOBJ.clickableWords.isPdfNode(node)) { let actNode = node, cnt = 0; while (cnt<5 && MXOBJ.clickableWords.checkPdfNode(actNode, str, true)) { range.setEnd(actNode.parentNode.nextSibling.firstChild, actNode.parentNode.nextSibling.firstChild.nodeValue.split(' ')[0].length); actNode = actNode.parentNode.nextSibling.firstChild; str = actNode.nodeValue.trim(); cnt++; } actNode = node, cnt = 0; while (cnt<5 && MXOBJ.clickableWords.checkPdfNode(actNode, str, false)) { let startIdx = actNode.parentNode.previousSibling.firstChild.nodeValue.indexOf(' ')===-1 ? 0 : actNode.parentNode.previousSibling.firstChild.nodeValue.lastIndexOf(' '); range.setStart(actNode.parentNode.previousSibling.firstChild, startIdx); actNode = actNode.parentNode.previousSibling.firstChild; str = actNode.nodeValue.trim(); cnt++; } str = range.toString().trim(); } // /pdf.js callbackFunc.call(this, str, evt, node, range); if (collapseSelection) {try {range.collapse();} catch(err) {}} }; if (button===1 || button===3) {MXOBJ.attachEvent(elem, 'click', fn);} if (button===2 || button===3) {MXOBJ.attachEvent(elem, 'contextmenu', fn);} }; MXOBJ.clickableWords.isPdfNode = function(node) { return node && node.parentNode && node.parentNode.nodeName.toLowerCase()==='div' && node.parentNode.parentNode && node.parentNode.parentNode.nodeName.toLowerCase()==='div' && node.parentNode.parentNode.getAttribute('class')==='textLayer'; }; MXOBJ.clickableWords.checkPdfNode = function(node, str, checkNext) { // console.log('checkPdfNode checkNext: ' + checkNext + ' nodeValue: ' + node.nodeValue + ' str: ' + str); let ref = checkNext ? node.parentNode.nextSibling : node.parentNode.previousSibling; // console.log('ref: ' + ref); if (!ref || node.nodeValue.trim().length===0) {return false;} if (MXOBJ.clickableWords.tailWithPunc(node.nodeValue, !checkNext)) {return false;} let strOk = checkNext ? node.nodeValue.endsWith(str) : node.nodeValue.startsWith(str); // console.log('strOk: ' + strOk); if (!strOk) {return false;} let refValueOk = ref.nodeName.toLowerCase()==='div' && node.parentNode.style.top===ref.style.top && ref.firstChild && ref.firstChild.nodeType===3 && ref.firstChild.nodeValue.length>0; refValueOk = refValueOk && (checkNext ? node.parentNode.nextSibling.firstChild.nodeValue.charAt(0)!==' ' : node.parentNode.previousSibling.firstChild.nodeValue.charAt(node.parentNode.previousSibling.firstChild.nodeValue.length-1)!==' '); refValueOk = refValueOk && !MXOBJ.clickableWords.tailWithPunc(ref.firstChild.nodeValue, checkNext); // console.log('refValueOk: ' + refValueOk); if (!refValueOk) {return false;} let len = node.nodeValue.length; let width = node.parentNode.getBoundingClientRect().width; let oneChar = width/len; let diff = checkNext ? (ref.getBoundingClientRect().left - node.parentNode.getBoundingClientRect().right) : (node.parentNode.getBoundingClientRect().left - ref.getBoundingClientRect().right); // console.log('checkNext: ' + checkNext + ' len: ' + len + ' width: ' + width + ' oneChar: ' + oneChar + ' diff: ' + diff + ' text: ' + node.nodeValue + ' ret: ' + (diff0 ? str.charAt(starts ? 0 : str.length-1) : null; return ch && MXOBJ.arrayContains(ch, MXOBJ.clickableWords.puncts); };