diff --git a/amd/build/annotations.min.js b/amd/build/annotations.min.js index 96d5bdc..29b383a 100644 --- a/amd/build/annotations.min.js +++ b/amd/build/annotations.min.js @@ -1,10 +1,2 @@ -define("mod_margic/annotations",["exports","jquery","./highlighting"],(function(_exports,_jquery,_highlighting){var obj; -/** - * Module for the annotation functions of the margic. - * - * @module mod_margic/annotations - * @copyright 2022 coactum GmbH - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};_exports.init=function(cmid,canmakeannotations,myuserid){var edited=!1,annotations=Array(),newannotation=!1;function editAnnotation(annotationid){if(edited==annotationid)(0,_highlighting.removeAllTempHighlights)(),resetForms(),edited=!1;else if(canmakeannotations&&myuserid==annotations[annotationid].userid){(0,_highlighting.removeAllTempHighlights)(),resetForms(),edited=annotationid;var entry=annotations[annotationid].entry;(0,_jquery.default)(".annotation-box-"+annotationid).hide(),(0,_jquery.default)(".annotation-form-"+entry+' input[name="startcontainer"]').val(annotations[annotationid].startcontainer),(0,_jquery.default)(".annotation-form-"+entry+' input[name="endcontainer"]').val(annotations[annotationid].endcontainer),(0,_jquery.default)(".annotation-form-"+entry+' input[name="startoffset"]').val(annotations[annotationid].startoffset),(0,_jquery.default)(".annotation-form-"+entry+' input[name="endoffset"]').val(annotations[annotationid].endoffset),(0,_jquery.default)(".annotation-form-"+entry+' input[name="start"]').val(annotations[annotationid].start),(0,_jquery.default)(".annotation-form-"+entry+' input[name="end"]').val(annotations[annotationid].end),(0,_jquery.default)(".annotation-form-"+entry+' input[name="exact"]').val(annotations[annotationid].exact),(0,_jquery.default)(".annotation-form-"+entry+' input[name="prefix"]').val(annotations[annotationid].prefix),(0,_jquery.default)(".annotation-form-"+entry+' input[name="suffix"]').val(annotations[annotationid].suffix),(0,_jquery.default)(".annotation-form-"+entry+' input[name="annotationid"]').val(annotationid),(0,_jquery.default)(".annotation-form-"+entry+' textarea[name="text"]').val(annotations[annotationid].text),(0,_jquery.default)(".annotation-form-"+entry+" select").val(annotations[annotationid].type),(0,_jquery.default)("#annotationpreview-temp-"+entry).html(annotations[annotationid].exact.replaceAll("<","<").replaceAll(">",">")),(0,_jquery.default)("#annotationpreview-temp-"+entry).css("border-color","#"+annotations[annotationid].color),(0,_jquery.default)(".annotationarea-"+entry+" .annotation-form").insertBefore(".annotation-box-"+annotationid),(0,_jquery.default)(".annotationarea-"+entry+" .annotation-form").show(),(0,_jquery.default)(".annotationarea-"+entry+" #id_text").focus()}else(0,_jquery.default)(".annotation-box-"+annotationid).focus()}function resetForms(){(0,_jquery.default)(".annotation-form").hide(),(0,_jquery.default)('.annotation-form input[name^="annotationid"]').val(null),(0,_jquery.default)('.annotation-form input[name^="startcontainer"]').val(-1),(0,_jquery.default)('.annotation-form input[name^="endcontainer"]').val(-1),(0,_jquery.default)('.annotation-form input[name^="startoffset"]').val(-1),(0,_jquery.default)('.annotation-form input[name^="endoffset"]').val(-1),(0,_jquery.default)('.annotation-form textarea[name^="text"]').val(""),(0,_jquery.default)(".annotation-box").not(".annotation-form").show()}(0,_jquery.default)(".annotation-form div.col-md-3").removeClass("col-md-3"),(0,_jquery.default)(".annotation-form div.col-md-9").removeClass("col-md-9"),(0,_jquery.default)(".annotation-form div.form-group").removeClass("form-group"),(0,_jquery.default)(".annotation-form div.row").removeClass("row"),(0,_jquery.default)(document).on("click","#id_cancel",(function(e){e.preventDefault(),(0,_highlighting.removeAllTempHighlights)(),resetForms(),edited=!1})),(0,_jquery.default)("textarea").keypress((function(e){13==e.which&&((0,_jquery.default)(this).parents(":eq(2)").submit(),e.preventDefault())})),(0,_jquery.default)(document).on("mouseup",".originaltext",(function(){if(""!==window.getSelection().getRangeAt(0).cloneContents().textContent&&canmakeannotations){(0,_highlighting.removeAllTempHighlights)(),resetForms(),newannotation=function(root){var ranges=[window.getSelection().getRangeAt(0)];if(ranges.collapsed)return null;var annotation={target:ranges.map((function(range){return(0,_highlighting.describe)(root,range)})).map((function(selectors){return{selector:selectors}}))};return(0,_highlighting.anchor)(annotation,root),annotation}(this);var entry=this.id.replace(/entry-/,"");(0,_jquery.default)(".annotation-form-"+entry+' input[name="startcontainer"]').val(newannotation.target[0].selector[0].startContainer),(0,_jquery.default)(".annotation-form-"+entry+' input[name="endcontainer"]').val(newannotation.target[0].selector[0].endContainer),(0,_jquery.default)(".annotation-form-"+entry+' input[name="startoffset"]').val(newannotation.target[0].selector[0].startOffset),(0,_jquery.default)(".annotation-form-"+entry+' input[name="endoffset"]').val(newannotation.target[0].selector[0].endOffset),(0,_jquery.default)(".annotation-form-"+entry+' input[name="start"]').val(newannotation.target[0].selector[1].start),(0,_jquery.default)(".annotation-form-"+entry+' input[name="end"]').val(newannotation.target[0].selector[1].end),(0,_jquery.default)(".annotation-form-"+entry+' input[name="exact"]').val(newannotation.target[0].selector[2].exact),(0,_jquery.default)(".annotation-form-"+entry+' input[name="prefix"]').val(newannotation.target[0].selector[2].prefix),(0,_jquery.default)(".annotation-form-"+entry+' input[name="suffix"]').val(newannotation.target[0].selector[2].suffix),(0,_jquery.default)(".annotation-form-"+entry+" select").val(1),(0,_jquery.default)("#annotationpreview-temp-"+entry).html(newannotation.target[0].selector[2].exact.replaceAll("<","<").replaceAll(">",">")),(0,_jquery.default)(".annotationarea-"+entry+" .annotation-form").show(),(0,_jquery.default)(".annotation-form-"+entry+" #id_text").focus()}})),_jquery.default.ajax({url:"./annotations.php",data:{id:cmid,getannotations:1},success:function(response){annotations=JSON.parse(response),function(){for(var _i=0,_Object$values=Object.values(annotations);_i<_Object$values.length;_i++){var annotation=_Object$values[_i],_newannotation={annotation:annotation,target:[[{type:"RangeSelector",startContainer:annotation.startcontainer,startOffset:parseInt(annotation.startoffset),endContainer:annotation.endcontainer,endOffset:parseInt(annotation.endoffset)},{type:"TextPositionSelector",start:parseInt(annotation.start),end:parseInt(annotation.end)},{type:"TextQuoteSelector",exact:annotation.exact,prefix:annotation.prefix,suffix:annotation.suffix}]].map((function(selectors){return{selector:selectors}}))};(0,_highlighting.anchor)(_newannotation,(0,_jquery.default)("#entry-"+annotation.entry)[0])}}(),(0,_jquery.default)(".annotated").mouseenter((function(){var id=this.id.replace("annotated-","");(0,_jquery.default)(".annotation-box-"+id).addClass("hovered"),(0,_jquery.default)(".annotated-"+id).addClass("hovered")})),(0,_jquery.default)(".annotated").mouseleave((function(){var id=this.id.replace("annotated-","");(0,_jquery.default)(".annotation-box-"+id).removeClass("hovered"),(0,_jquery.default)(".annotated-"+id).removeClass("hovered")})),(0,_jquery.default)(document).on("mouseover",".annotated_temp",(function(){(0,_jquery.default)(".annotated_temp").addClass("hovered")})),(0,_jquery.default)(document).on("mouseleave",".annotated_temp",(function(){(0,_jquery.default)(".annotated_temp").removeClass("hovered")})),(0,_jquery.default)(document).on("click",".annotated",(function(){editAnnotation(this.id.replace("annotated-",""))})),(0,_jquery.default)(document).on("click",".edit-annotation",(function(){editAnnotation(this.id.replace("edit-annotation-",""))})),(0,_jquery.default)(document).on("mouseover",".hoverannotation",(function(){var id=this.id.replace("hoverannotation-","");(0,_jquery.default)(".annotated-"+id).addClass("hovered")})),(0,_jquery.default)(document).on("mouseleave",".hoverannotation",(function(){var id=this.id.replace("hoverannotation-","");(0,_jquery.default)(".annotated-"+id).removeClass("hovered")}))},complete:function(){(0,_jquery.default)("#overlay").hide()},error:function(){alert("Error fetching annotations")}})}})); - -//# sourceMappingURL=annotations.min.js.map \ No newline at end of file +define ("mod_margic/annotations",["exports","jquery","./highlighting"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var e=function(a,e,f){var j=!1,k=[],l=!1;(0,b.default)(".annotation-form div.col-md-3").removeClass("col-md-3");(0,b.default)(".annotation-form div.col-md-9").removeClass("col-md-9");(0,b.default)(".annotation-form div.form-group").removeClass("form-group");(0,b.default)(".annotation-form div.row").removeClass("row");(0,b.default)(document).on("click","#id_cancel",function(a){a.preventDefault();(0,c.removeAllTempHighlights)();i();j=!1});(0,b.default)("textarea").keypress(function(a){if(13==a.which){(0,b.default)(this).parents(":eq(2)").submit();a.preventDefault()}});(0,b.default)(document).on("mouseup",".originaltext",function(){var a=window.getSelection().getRangeAt(0);if(""!==a.cloneContents().textContent&&e){(0,c.removeAllTempHighlights)();i();l=d(this);var f=this.id.replace(/entry-/,"");(0,b.default)(".annotation-form-"+f+" input[name=\"startcontainer\"]").val(l.target[0].selector[0].startContainer);(0,b.default)(".annotation-form-"+f+" input[name=\"endcontainer\"]").val(l.target[0].selector[0].endContainer);(0,b.default)(".annotation-form-"+f+" input[name=\"startoffset\"]").val(l.target[0].selector[0].startOffset);(0,b.default)(".annotation-form-"+f+" input[name=\"endoffset\"]").val(l.target[0].selector[0].endOffset);(0,b.default)(".annotation-form-"+f+" input[name=\"start\"]").val(l.target[0].selector[1].start);(0,b.default)(".annotation-form-"+f+" input[name=\"end\"]").val(l.target[0].selector[1].end);(0,b.default)(".annotation-form-"+f+" input[name=\"exact\"]").val(l.target[0].selector[2].exact);(0,b.default)(".annotation-form-"+f+" input[name=\"prefix\"]").val(l.target[0].selector[2].prefix);(0,b.default)(".annotation-form-"+f+" input[name=\"suffix\"]").val(l.target[0].selector[2].suffix);(0,b.default)(".annotation-form-"+f+" select").val(1);(0,b.default)("#annotationpreview-temp-"+f).html(l.target[0].selector[2].exact.replaceAll("<","<").replaceAll(">",">"));(0,b.default)(".annotationarea-"+f+" .annotation-form").show();(0,b.default)(".annotation-form-"+f+" #id_text").focus()}});b.default.ajax({url:"./annotations.php",data:{id:a,getannotations:1},success:function success(a){k=JSON.parse(a);g();(0,b.default)(".annotated").mouseenter(function(){var a=this.id.replace("annotated-","");(0,b.default)(".annotation-box-"+a).addClass("hovered");(0,b.default)(".annotated-"+a).addClass("hovered")});(0,b.default)(".annotated").mouseleave(function(){var a=this.id.replace("annotated-","");(0,b.default)(".annotation-box-"+a).removeClass("hovered");(0,b.default)(".annotated-"+a).removeClass("hovered")});(0,b.default)(document).on("mouseover",".annotated_temp",function(){(0,b.default)(".annotated_temp").addClass("hovered")});(0,b.default)(document).on("mouseleave",".annotated_temp",function(){(0,b.default)(".annotated_temp").removeClass("hovered")});(0,b.default)(document).on("click",".annotated",function(){var a=this.id.replace("annotated-","");h(a)});(0,b.default)(document).on("click",".edit-annotation",function(){var a=this.id.replace("edit-annotation-","");h(a)});(0,b.default)(document).on("mouseover",".hoverannotation",function(){var a=this.id.replace("hoverannotation-","");(0,b.default)(".annotated-"+a).addClass("hovered")});(0,b.default)(document).on("mouseleave",".hoverannotation",function(){var a=this.id.replace("hoverannotation-","");(0,b.default)(".annotated-"+a).removeClass("hovered")})},complete:function complete(){(0,b.default)("#overlay").hide()},error:function error(){alert("Error fetching annotations")}});function g(){for(var a=0,d=Object.values(k);a",">"));(0,b.default)("#annotationpreview-temp-"+d).css("border-color","#"+k[a].color);(0,b.default)(".annotationarea-"+d+" .annotation-form").insertBefore(".annotation-box-"+a);(0,b.default)(".annotationarea-"+d+" .annotation-form").show();(0,b.default)(".annotationarea-"+d+" #id_text").focus()}else{(0,b.default)(".annotation-box-"+a).focus()}}function i(){(0,b.default)(".annotation-form").hide();(0,b.default)(".annotation-form input[name^=\"annotationid\"]").val(null);(0,b.default)(".annotation-form input[name^=\"startcontainer\"]").val(-1);(0,b.default)(".annotation-form input[name^=\"endcontainer\"]").val(-1);(0,b.default)(".annotation-form input[name^=\"startoffset\"]").val(-1);(0,b.default)(".annotation-form input[name^=\"endoffset\"]").val(-1);(0,b.default)(".annotation-form textarea[name^=\"text\"]").val("");(0,b.default)(".annotation-box").not(".annotation-form").show()}};a.init=e;function d(a){var b=[window.getSelection().getRangeAt(0)];if(b.collapsed){return null}var d=b.map(function(b){return(0,c.describe)(a,b)}),e=d.map(function(a){return{selector:a}}),f={target:e};(0,c.anchor)(f,a);return f}}); +//# sourceMappingURL=annotations.min.js.map diff --git a/amd/build/annotations.min.js.map b/amd/build/annotations.min.js.map index 4d2a853..2b712e9 100644 --- a/amd/build/annotations.min.js.map +++ b/amd/build/annotations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"annotations.min.js","sources":["../src/annotations.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module for the annotation functions of the margic.\n *\n * @module mod_margic/annotations\n * @copyright 2022 coactum GmbH\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport {removeAllTempHighlights, anchor, describe} from './highlighting';\n\nexport const init = (cmid, canmakeannotations, myuserid) => {\n\n var edited = false;\n var annotations = Array();\n\n var newannotation = false;\n\n // Remove col-mds from moodle form.\n $('.annotation-form div.col-md-3').removeClass('col-md-3');\n $('.annotation-form div.col-md-9').removeClass('col-md-9');\n $('.annotation-form div.form-group').removeClass('form-group');\n $('.annotation-form div.row').removeClass('row');\n\n // Onclick listener if form is canceled.\n $(document).on('click', '#id_cancel', function(e) {\n e.preventDefault();\n\n removeAllTempHighlights(); // Remove other temporary highlights.\n\n resetForms(); // Remove old form contents.\n\n edited = false;\n });\n\n // Listen for return key pressed to submit annotation form.\n $('textarea').keypress(function(e) {\n if (e.which == 13) {\n $(this).parents(':eq(2)').submit();\n e.preventDefault();\n }\n });\n\n // If user selects text for new annotation\n $(document).on('mouseup', '.originaltext', function() {\n var selectedrange = window.getSelection().getRangeAt(0);\n\n if (selectedrange.cloneContents().textContent !== '' && canmakeannotations) {\n\n removeAllTempHighlights(); // Remove other temporary highlights.\n\n resetForms(); // Reset the annotation forms.\n\n // Create new annotation.\n newannotation = createAnnotation(this);\n\n var entry = this.id.replace(/entry-/, '');\n\n // RangeSelector.\n $('.annotation-form-' + entry + ' input[name=\"startcontainer\"]').val(\n newannotation.target[0].selector[0].startContainer);\n $('.annotation-form-' + entry + ' input[name=\"endcontainer\"]').val(\n newannotation.target[0].selector[0].endContainer);\n $('.annotation-form-' + entry + ' input[name=\"startoffset\"]').val(\n newannotation.target[0].selector[0].startOffset);\n $('.annotation-form-' + entry + ' input[name=\"endoffset\"]').val(\n newannotation.target[0].selector[0].endOffset);\n\n // TextPositionSelector.\n $('.annotation-form-' + entry + ' input[name=\"start\"]').val(\n newannotation.target[0].selector[1].start);\n $('.annotation-form-' + entry + ' input[name=\"end\"]').val(\n newannotation.target[0].selector[1].end);\n\n // TextQuoteSelector.\n $('.annotation-form-' + entry + ' input[name=\"exact\"]').val(\n newannotation.target[0].selector[2].exact);\n $('.annotation-form-' + entry + ' input[name=\"prefix\"]').val(\n newannotation.target[0].selector[2].prefix);\n $('.annotation-form-' + entry + ' input[name=\"suffix\"]').val(\n newannotation.target[0].selector[2].suffix);\n\n $('.annotation-form-' + entry + ' select').val(1);\n\n // Prevent JavaScript injection (if annotated text in original entry is JavaScript code in script tags).\n $('#annotationpreview-temp-' + entry).html(\n newannotation.target[0].selector[2].exact.replaceAll('<', '<').replaceAll('>', '>'));\n\n $('.annotationarea-' + entry + ' .annotation-form').show();\n $('.annotation-form-' + entry + ' #id_text').focus();\n }\n });\n\n // Fetch and recreate annotations.\n $.ajax({\n url: './annotations.php',\n data: {'id': cmid, 'getannotations': 1},\n success: function(response) {\n annotations = JSON.parse(response);\n recreateAnnotations();\n\n // Highlight annotation and all annotated text if annotated text is hovered\n $('.annotated').mouseenter(function() {\n var id = this.id.replace('annotated-', '');\n $('.annotation-box-' + id).addClass('hovered');\n $('.annotated-' + id).addClass('hovered');\n });\n\n $('.annotated').mouseleave(function() {\n var id = this.id.replace('annotated-', '');\n $('.annotation-box-' + id).removeClass('hovered');\n $('.annotated-' + id).removeClass('hovered');\n });\n\n // Highlight whole temp annotation if part of temp annotation is hovered\n $(document).on('mouseover', '.annotated_temp', function() {\n $('.annotated_temp').addClass('hovered');\n });\n\n $(document).on('mouseleave', '.annotated_temp', function() {\n $('.annotated_temp').removeClass('hovered');\n });\n\n // Onclick listener for editing annotation.\n $(document).on('click', '.annotated', function() {\n var id = this.id.replace('annotated-', '');\n editAnnotation(id);\n });\n\n // Onclick listener for editing annotation.\n $(document).on('click', '.edit-annotation', function() {\n var id = this.id.replace('edit-annotation-', '');\n editAnnotation(id);\n });\n\n // Highlight annotation if hoverannotation button is hovered\n $(document).on('mouseover', '.hoverannotation', function() {\n var id = this.id.replace('hoverannotation-', '');\n $('.annotated-' + id).addClass('hovered');\n });\n\n $(document).on('mouseleave', '.hoverannotation', function() {\n var id = this.id.replace('hoverannotation-', '');\n $('.annotated-' + id).removeClass('hovered');\n });\n\n },\n complete: function() {\n $('#overlay').hide();\n },\n error: function() {\n alert('Error fetching annotations');\n }\n });\n\n /**\n * Recreate annotations.\n *\n */\n function recreateAnnotations() {\n\n for (let annotation of Object.values(annotations)) {\n\n const rangeSelectors = [[\n {type: \"RangeSelector\", startContainer: annotation.startcontainer, startOffset: parseInt(annotation.startoffset),\n endContainer: annotation.endcontainer, endOffset: parseInt(annotation.endoffset)},\n {type: \"TextPositionSelector\", start: parseInt(annotation.start), end: parseInt(annotation.end)},\n {type: \"TextQuoteSelector\", exact: annotation.exact, prefix: annotation.prefix, suffix: annotation.suffix}\n ]];\n\n const target = rangeSelectors.map(selectors => ({\n selector: selectors,\n }));\n\n /** @type {AnnotationData} */\n const newannotation = {\n annotation: annotation,\n target: target,\n };\n\n anchor(newannotation, $(\"#entry-\" + annotation.entry)[0]);\n }\n }\n\n /**\n * Edit annotation.\n *\n * @param {int} annotationid\n */\n function editAnnotation(annotationid) {\n\n if (edited == annotationid) {\n removeAllTempHighlights(); // Remove other temporary highlights.\n resetForms(); // Remove old form contents.\n edited = false;\n } else if (canmakeannotations && myuserid == annotations[annotationid].userid) {\n removeAllTempHighlights(); // Remove other temporary highlights.\n resetForms(); // Remove old form contents.\n\n edited = annotationid;\n\n var entry = annotations[annotationid].entry;\n\n $('.annotation-box-' + annotationid).hide(); // Hide edited annotation-box.\n\n $('.annotation-form-' + entry + ' input[name=\"startcontainer\"]').val(annotations[annotationid].startcontainer);\n $('.annotation-form-' + entry + ' input[name=\"endcontainer\"]').val(annotations[annotationid].endcontainer);\n $('.annotation-form-' + entry + ' input[name=\"startoffset\"]').val(annotations[annotationid].startoffset);\n $('.annotation-form-' + entry + ' input[name=\"endoffset\"]').val(annotations[annotationid].endoffset);\n $('.annotation-form-' + entry + ' input[name=\"start\"]').val(annotations[annotationid].start);\n $('.annotation-form-' + entry + ' input[name=\"end\"]').val(annotations[annotationid].end);\n $('.annotation-form-' + entry + ' input[name=\"exact\"]').val(annotations[annotationid].exact);\n $('.annotation-form-' + entry + ' input[name=\"prefix\"]').val(annotations[annotationid].prefix);\n $('.annotation-form-' + entry + ' input[name=\"suffix\"]').val(annotations[annotationid].suffix);\n\n $('.annotation-form-' + entry + ' input[name=\"annotationid\"]').val(annotationid);\n\n $('.annotation-form-' + entry + ' textarea[name=\"text\"]').val(annotations[annotationid].text);\n\n $('.annotation-form-' + entry + ' select').val(annotations[annotationid].type);\n\n // Prevent JavaScript injection (if annotated text in original entry is JavaScript code in script tags).\n $('#annotationpreview-temp-' + entry).html(\n annotations[annotationid].exact.replaceAll('<', '<').replaceAll('>', '>'));\n $('#annotationpreview-temp-' + entry).css('border-color', '#' + annotations[annotationid].color);\n\n $('.annotationarea-' + entry + ' .annotation-form').insertBefore('.annotation-box-' + annotationid);\n $('.annotationarea-' + entry + ' .annotation-form').show();\n $('.annotationarea-' + entry + ' #id_text').focus();\n } else {\n $('.annotation-box-' + annotationid).focus();\n }\n }\n\n /**\n * Reset all annotation forms\n */\n function resetForms() {\n $('.annotation-form').hide();\n\n $('.annotation-form input[name^=\"annotationid\"]').val(null);\n\n $('.annotation-form input[name^=\"startcontainer\"]').val(-1);\n $('.annotation-form input[name^=\"endcontainer\"]').val(-1);\n $('.annotation-form input[name^=\"startoffset\"]').val(-1);\n $('.annotation-form input[name^=\"endoffset\"]').val(-1);\n\n $('.annotation-form textarea[name^=\"text\"]').val('');\n\n $('.annotation-box').not('.annotation-form').show(); // To show again edited annotation.\n }\n};\n\n/**\n * Create a new annotation that is associated with the selected region of\n * the current document.\n *\n * @param {object} root - The root element\n * @return {object} - The new annotation\n */\nfunction createAnnotation(root) {\n const ranges = [window.getSelection().getRangeAt(0)];\n\n if (ranges.collapsed) {\n return null;\n }\n\n const rangeSelectors = ranges.map(range => describe(root, range));\n\n const target = rangeSelectors.map(selectors => ({\n selector: selectors,\n }));\n\n /** @type {AnnotationData} */\n const annotation = {\n target,\n };\n\n anchor(annotation, root);\n\n return annotation;\n}"],"names":["cmid","canmakeannotations","myuserid","edited","annotations","Array","newannotation","editAnnotation","annotationid","resetForms","userid","entry","hide","val","startcontainer","endcontainer","startoffset","endoffset","start","end","exact","prefix","suffix","text","type","html","replaceAll","css","color","insertBefore","show","focus","not","removeClass","document","on","e","preventDefault","keypress","which","this","parents","submit","window","getSelection","getRangeAt","cloneContents","textContent","root","ranges","collapsed","annotation","target","map","range","selectors","selector","createAnnotation","id","replace","startContainer","endContainer","startOffset","endOffset","ajax","url","data","success","response","JSON","parse","Object","values","parseInt","recreateAnnotations","mouseenter","addClass","mouseleave","complete","error","alert"],"mappings":"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"} \ No newline at end of file +{"version":3,"sources":["../src/annotations.js"],"names":["init","cmid","canmakeannotations","myuserid","edited","annotations","newannotation","removeClass","document","on","e","preventDefault","resetForms","keypress","which","parents","submit","selectedrange","window","getSelection","getRangeAt","cloneContents","textContent","createAnnotation","entry","id","replace","val","target","selector","startContainer","endContainer","startOffset","endOffset","start","end","exact","prefix","suffix","html","replaceAll","show","focus","$","ajax","url","data","success","response","JSON","parse","recreateAnnotations","mouseenter","addClass","mouseleave","editAnnotation","complete","hide","error","alert","Object","values","annotation","rangeSelectors","type","startcontainer","parseInt","startoffset","endcontainer","endoffset","map","selectors","annotationid","userid","text","css","color","insertBefore","not","root","ranges","collapsed","range"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module for the annotation functions of the margic.\n *\n * @module mod_margic/annotations\n * @copyright 2022 coactum GmbH\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport {removeAllTempHighlights, anchor, describe} from './highlighting';\n\nexport const init = (cmid, canmakeannotations, myuserid) => {\n\n var edited = false;\n var annotations = Array();\n\n var newannotation = false;\n\n // Remove col-mds from moodle form.\n $('.annotation-form div.col-md-3').removeClass('col-md-3');\n $('.annotation-form div.col-md-9').removeClass('col-md-9');\n $('.annotation-form div.form-group').removeClass('form-group');\n $('.annotation-form div.row').removeClass('row');\n\n // Onclick listener if form is canceled.\n $(document).on('click', '#id_cancel', function(e) {\n e.preventDefault();\n\n removeAllTempHighlights(); // Remove other temporary highlights.\n\n resetForms(); // Remove old form contents.\n\n edited = false;\n });\n\n // Listen for return key pressed to submit annotation form.\n $('textarea').keypress(function(e) {\n if (e.which == 13) {\n $(this).parents(':eq(2)').submit();\n e.preventDefault();\n }\n });\n\n // If user selects text for new annotation\n $(document).on('mouseup', '.originaltext', function() {\n var selectedrange = window.getSelection().getRangeAt(0);\n\n if (selectedrange.cloneContents().textContent !== '' && canmakeannotations) {\n\n removeAllTempHighlights(); // Remove other temporary highlights.\n\n resetForms(); // Reset the annotation forms.\n\n // Create new annotation.\n newannotation = createAnnotation(this);\n\n var entry = this.id.replace(/entry-/, '');\n\n // RangeSelector.\n $('.annotation-form-' + entry + ' input[name=\"startcontainer\"]').val(\n newannotation.target[0].selector[0].startContainer);\n $('.annotation-form-' + entry + ' input[name=\"endcontainer\"]').val(\n newannotation.target[0].selector[0].endContainer);\n $('.annotation-form-' + entry + ' input[name=\"startoffset\"]').val(\n newannotation.target[0].selector[0].startOffset);\n $('.annotation-form-' + entry + ' input[name=\"endoffset\"]').val(\n newannotation.target[0].selector[0].endOffset);\n\n // TextPositionSelector.\n $('.annotation-form-' + entry + ' input[name=\"start\"]').val(\n newannotation.target[0].selector[1].start);\n $('.annotation-form-' + entry + ' input[name=\"end\"]').val(\n newannotation.target[0].selector[1].end);\n\n // TextQuoteSelector.\n $('.annotation-form-' + entry + ' input[name=\"exact\"]').val(\n newannotation.target[0].selector[2].exact);\n $('.annotation-form-' + entry + ' input[name=\"prefix\"]').val(\n newannotation.target[0].selector[2].prefix);\n $('.annotation-form-' + entry + ' input[name=\"suffix\"]').val(\n newannotation.target[0].selector[2].suffix);\n\n $('.annotation-form-' + entry + ' select').val(1);\n\n // Prevent JavaScript injection (if annotated text in original entry is JavaScript code in script tags).\n $('#annotationpreview-temp-' + entry).html(\n newannotation.target[0].selector[2].exact.replaceAll('<', '<').replaceAll('>', '>'));\n\n $('.annotationarea-' + entry + ' .annotation-form').show();\n $('.annotation-form-' + entry + ' #id_text').focus();\n }\n });\n\n // Fetch and recreate annotations.\n $.ajax({\n url: './annotations.php',\n data: {'id': cmid, 'getannotations': 1},\n success: function(response) {\n annotations = JSON.parse(response);\n recreateAnnotations();\n\n // Highlight annotation and all annotated text if annotated text is hovered\n $('.annotated').mouseenter(function() {\n var id = this.id.replace('annotated-', '');\n $('.annotation-box-' + id).addClass('hovered');\n $('.annotated-' + id).addClass('hovered');\n });\n\n $('.annotated').mouseleave(function() {\n var id = this.id.replace('annotated-', '');\n $('.annotation-box-' + id).removeClass('hovered');\n $('.annotated-' + id).removeClass('hovered');\n });\n\n // Highlight whole temp annotation if part of temp annotation is hovered\n $(document).on('mouseover', '.annotated_temp', function() {\n $('.annotated_temp').addClass('hovered');\n });\n\n $(document).on('mouseleave', '.annotated_temp', function() {\n $('.annotated_temp').removeClass('hovered');\n });\n\n // Onclick listener for editing annotation.\n $(document).on('click', '.annotated', function() {\n var id = this.id.replace('annotated-', '');\n editAnnotation(id);\n });\n\n // Onclick listener for editing annotation.\n $(document).on('click', '.edit-annotation', function() {\n var id = this.id.replace('edit-annotation-', '');\n editAnnotation(id);\n });\n\n // Highlight annotation if hoverannotation button is hovered\n $(document).on('mouseover', '.hoverannotation', function() {\n var id = this.id.replace('hoverannotation-', '');\n $('.annotated-' + id).addClass('hovered');\n });\n\n $(document).on('mouseleave', '.hoverannotation', function() {\n var id = this.id.replace('hoverannotation-', '');\n $('.annotated-' + id).removeClass('hovered');\n });\n\n },\n complete: function() {\n $('#overlay').hide();\n },\n error: function() {\n alert('Error fetching annotations');\n }\n });\n\n /**\n * Recreate annotations.\n *\n */\n function recreateAnnotations() {\n\n for (let annotation of Object.values(annotations)) {\n\n const rangeSelectors = [[\n {type: \"RangeSelector\", startContainer: annotation.startcontainer, startOffset: parseInt(annotation.startoffset),\n endContainer: annotation.endcontainer, endOffset: parseInt(annotation.endoffset)},\n {type: \"TextPositionSelector\", start: parseInt(annotation.start), end: parseInt(annotation.end)},\n {type: \"TextQuoteSelector\", exact: annotation.exact, prefix: annotation.prefix, suffix: annotation.suffix}\n ]];\n\n const target = rangeSelectors.map(selectors => ({\n selector: selectors,\n }));\n\n /** @type {AnnotationData} */\n const newannotation = {\n annotation: annotation,\n target: target,\n };\n\n anchor(newannotation, $(\"#entry-\" + annotation.entry)[0]);\n }\n }\n\n /**\n * Edit annotation.\n *\n * @param {int} annotationid\n */\n function editAnnotation(annotationid) {\n\n if (edited == annotationid) {\n removeAllTempHighlights(); // Remove other temporary highlights.\n resetForms(); // Remove old form contents.\n edited = false;\n } else if (canmakeannotations && myuserid == annotations[annotationid].userid) {\n removeAllTempHighlights(); // Remove other temporary highlights.\n resetForms(); // Remove old form contents.\n\n edited = annotationid;\n\n var entry = annotations[annotationid].entry;\n\n $('.annotation-box-' + annotationid).hide(); // Hide edited annotation-box.\n\n $('.annotation-form-' + entry + ' input[name=\"startcontainer\"]').val(annotations[annotationid].startcontainer);\n $('.annotation-form-' + entry + ' input[name=\"endcontainer\"]').val(annotations[annotationid].endcontainer);\n $('.annotation-form-' + entry + ' input[name=\"startoffset\"]').val(annotations[annotationid].startoffset);\n $('.annotation-form-' + entry + ' input[name=\"endoffset\"]').val(annotations[annotationid].endoffset);\n $('.annotation-form-' + entry + ' input[name=\"start\"]').val(annotations[annotationid].start);\n $('.annotation-form-' + entry + ' input[name=\"end\"]').val(annotations[annotationid].end);\n $('.annotation-form-' + entry + ' input[name=\"exact\"]').val(annotations[annotationid].exact);\n $('.annotation-form-' + entry + ' input[name=\"prefix\"]').val(annotations[annotationid].prefix);\n $('.annotation-form-' + entry + ' input[name=\"suffix\"]').val(annotations[annotationid].suffix);\n\n $('.annotation-form-' + entry + ' input[name=\"annotationid\"]').val(annotationid);\n\n $('.annotation-form-' + entry + ' textarea[name=\"text\"]').val(annotations[annotationid].text);\n\n $('.annotation-form-' + entry + ' select').val(annotations[annotationid].type);\n\n // Prevent JavaScript injection (if annotated text in original entry is JavaScript code in script tags).\n $('#annotationpreview-temp-' + entry).html(\n annotations[annotationid].exact.replaceAll('<', '<').replaceAll('>', '>'));\n $('#annotationpreview-temp-' + entry).css('border-color', '#' + annotations[annotationid].color);\n\n $('.annotationarea-' + entry + ' .annotation-form').insertBefore('.annotation-box-' + annotationid);\n $('.annotationarea-' + entry + ' .annotation-form').show();\n $('.annotationarea-' + entry + ' #id_text').focus();\n } else {\n $('.annotation-box-' + annotationid).focus();\n }\n }\n\n /**\n * Reset all annotation forms\n */\n function resetForms() {\n $('.annotation-form').hide();\n\n $('.annotation-form input[name^=\"annotationid\"]').val(null);\n\n $('.annotation-form input[name^=\"startcontainer\"]').val(-1);\n $('.annotation-form input[name^=\"endcontainer\"]').val(-1);\n $('.annotation-form input[name^=\"startoffset\"]').val(-1);\n $('.annotation-form input[name^=\"endoffset\"]').val(-1);\n\n $('.annotation-form textarea[name^=\"text\"]').val('');\n\n $('.annotation-box').not('.annotation-form').show(); // To show again edited annotation.\n }\n};\n\n/**\n * Create a new annotation that is associated with the selected region of\n * the current document.\n *\n * @param {object} root - The root element\n * @return {object} - The new annotation\n */\nfunction createAnnotation(root) {\n const ranges = [window.getSelection().getRangeAt(0)];\n\n if (ranges.collapsed) {\n return null;\n }\n\n const rangeSelectors = ranges.map(range => describe(root, range));\n\n const target = rangeSelectors.map(selectors => ({\n selector: selectors,\n }));\n\n /** @type {AnnotationData} */\n const annotation = {\n target,\n };\n\n anchor(annotation, root);\n\n return annotation;\n}"],"file":"annotations.min.js"} \ No newline at end of file diff --git a/amd/build/highlighting.min.js b/amd/build/highlighting.min.js index 609d713..b982351 100644 --- a/amd/build/highlighting.min.js +++ b/amd/build/highlighting.min.js @@ -1,3 +1,2 @@ -define("mod_margic/highlighting",["exports","jquery","./types","./text-range"],(function(_exports,_jquery,_types2,_textRange){var obj;function _createForOfIteratorHelper(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(!it){if(Array.isArray(o)||(it=function(o,minLen){if(!o)return;if("string"==typeof o)return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(o);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}(o))||allowArrayLike&&o&&"number"==typeof o.length){it&&(o=it);var i=0,F=function(){};return{s:F,n:function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}},e:function(_e){throw _e},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var err,normalCompletion=!0,didErr=!1;return{s:function(){it=it.call(o)},n:function(){var step=it.next();return normalCompletion=step.done,step},e:function(_e2){didErr=!0,err=_e2},f:function(){try{normalCompletion||null==it.return||it.return()}finally{if(didErr)throw err}}}}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i1&&void 0!==arguments[1]&&arguments[1],cssClass=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"annotated",color=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"FFFF00",textNodes=wholeTextNodesInRange(range),textNodeSpans=[],prevNode=null,currentSpan=null;textNodes.forEach((function(node){prevNode&&prevNode.nextSibling===node?currentSpan.push(node):(currentSpan=[node],textNodeSpans.push(currentSpan)),prevNode=node}));var whitespace=/^\s*$/;textNodeSpans=textNodeSpans.filter((function(span){return span.some((function(node){return!whitespace.test(node.nodeValue)}))}));var highlights=[];return textNodeSpans.forEach((function(nodes){var highlightEl=document.createElement("margic-highlight");highlightEl.className=cssClass,annotationid&&(highlightEl.className+=" "+cssClass+"-"+annotationid,highlightEl.style="text-decoration:underline; text-decoration-color: #"+color,highlightEl.id=cssClass+"-"+annotationid,highlightEl.style.backgroundColor="#"+color),nodes[0].parentNode.replaceChild(highlightEl,nodes[0]),nodes.forEach((function(node){return highlightEl.appendChild(node)})),highlights.push(highlightEl)})),highlights}function wholeTextNodesInRange(range){if(range.collapsed)return[];var root=range.commonAncestorContainer;if(root.nodeType!==Node.ELEMENT_NODE&&(root=root.parentElement),!root)return[];for(var node,textNodes=[],nodeIter=root.ownerDocument.createNodeIterator(root,NodeFilter.SHOW_TEXT);node=nodeIter.nextNode();)if(isNodeInRange(range,node)){var text=node;text===range.startContainer&&range.startOffset>0?text.splitText(range.startOffset):(text===range.endContainer&&range.endOffset=0}catch(e){return!1}}function querySelector(anchor){var options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return anchor.toRange(options)}function replaceWith(node,replacements){var parent=node.parentNode;replacements.forEach((function(r){return parent.insertBefore(r,node)})),node.remove()}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.anchor=function(annotation,root){var highlight=function(anchor){var range=function(anchor){if(!anchor.range)return null;try{return anchor.range.toRange()}catch(_unused){return null}}(anchor);if(range){var highlights=[];(highlights=annotation.annotation?highlightRange(range,annotation.annotation.id,"annotated",annotation.annotation.color):highlightRange(range,!1,"annotated_temp")).forEach((function(h){h._annotation=anchor.annotation})),anchor.highlights=highlights}};annotation.target||(annotation.target=[]);var _step,anchors=annotation.target.map((function(target){if(!target.selector||!target.selector.some((function(s){return"TextQuoteSelector"===s.type})))return{annotation:annotation,target:target};var anchor;try{var range=function(root,selectors){var _step2,options=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},position=null,quote=null,range=null,_iterator2=_createForOfIteratorHelper(selectors);try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){var selector=_step2.value;switch(selector.type){case"TextPositionSelector":position=selector,options.hint=position.start;break;case"TextQuoteSelector":quote=selector;break;case"RangeSelector":range=selector}}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}var maybeAssertQuote=function(range){var _quote;if(null!==(_quote=quote)&&void 0!==_quote&&_quote.exact&&range.toString()!==quote.exact)throw new Error("quote mismatch");return range};try{if(range)return querySelector(_types2.RangeAnchor.fromSelector(root,range),options)||maybeAssertQuote}catch(error){try{if(position)return querySelector(_types2.TextPositionAnchor.fromSelector(root,position),options)||maybeAssertQuote}catch(error){try{if(quote)return querySelector(_types2.TextQuoteAnchor.fromSelector(root,quote),options)}catch(error){return!1}}}}(root,target.selector),textRange=_textRange.TextRange.fromRange(range);anchor={annotation:annotation,target:target,range:textRange}}catch(err){anchor={annotation:annotation,target:target}}return anchor})),_iterator=_createForOfIteratorHelper(anchors);try{for(_iterator.s();!(_step=_iterator.n()).done;){var _anchor2=_step.value;highlight(_anchor2)}}catch(err){_iterator.e(err)}finally{_iterator.f()}return annotation.$orphan=anchors.length>0&&anchors.every((function(anchor){return anchor.target.selector&&!anchor.range})),anchors},_exports.describe=function(root,range){for(var types=[_types2.RangeAnchor,_types2.TextPositionAnchor,_types2.TextQuoteAnchor],result=[],_i=0,_types=types;_i<_types.length;_i++){var type=_types[_i];try{var _anchor=type.fromRange(root,range);result.push(_anchor.toSelector())}catch(error){continue}}return result},_exports.removeAllTempHighlights=function(){var highlights=Array.from((0,_jquery.default)("body")[0].querySelectorAll(".annotated_temp"));void 0!==highlights&&0!=highlights.length&&function(highlights){for(var i=0;i=a.length)return{done:!0};return{done:!1,value:a[b++]}},e:function e(a){throw a},f:c}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var d,e=!0,g=!1,h;return{s:function s(){d=a[Symbol.iterator]()},n:function n(){var a=d.next();e=a.done;return a},e:function e(a){g=!0;h=a},f:function f(){try{if(!e&&null!=d.return)d.return()}finally{if(g)throw h}}}}function f(a,b){if(!a)return;if("string"==typeof a)return g(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return g(a,b)}function g(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c=a.comparePoint(b,0)&&0<=a.comparePoint(b,e)}catch(a){return!1}}function l(a){var b=1 {\n\n // Only annotations with an associated quote can currently be anchored.\n // This is because the quote is used to verify anchoring with other selector\n // types.\n if (\n !target.selector ||\n !target.selector.some(s => s.type === 'TextQuoteSelector')\n ) {\n return {annotation, target};\n }\n\n /** @type {Anchor} */\n let anchor;\n try {\n const range = htmlAnchor(root, target.selector);\n // Convert the `Range` to a `TextRange` which can be converted back to\n // a `Range` later. The `TextRange` representation allows for highlights\n // to be inserted during anchoring other annotations without \"breaking\"\n // this anchor.\n\n\n const textRange = TextRange.fromRange(range);\n\n anchor = {annotation, target, range: textRange};\n\n } catch (err) {\n\n anchor = {annotation, target};\n }\n\n return anchor;\n };\n\n /**\n * Highlight the text range that `anchor` refers to.\n *\n * @param {Anchor} anchor\n */\n const highlight = anchor => {\n\n const range = resolveAnchor(anchor);\n\n if (!range) {\n return;\n }\n\n let highlights = [];\n\n if (annotation.annotation) {\n highlights = highlightRange(range, annotation.annotation.id, 'annotated', annotation.annotation.color);\n } else {\n highlights = highlightRange(range, false, 'annotated_temp');\n }\n\n highlights.forEach(h => {\n h._annotation = anchor.annotation;\n });\n anchor.highlights = highlights;\n\n };\n\n // Remove existing anchors for this annotation.\n // this.detach(annotation, false /* notify */); // To be replaced by own method\n\n // Resolve selectors to ranges and insert highlights.\n if (!annotation.target) {\n annotation.target = [];\n }\n const anchors = annotation.target.map(locate);\n\n for (let anchor of anchors) {\n\n highlight(anchor);\n }\n\n // Set flag indicating whether anchoring succeeded. For each target,\n // anchoring is successful either if there are no selectors (ie. this is a\n // Page Note) or we successfully resolved the selectors to a range.\n annotation.$orphan =\n anchors.length > 0 &&\n anchors.every(anchor => anchor.target.selector && !anchor.range);\n\n return anchors;\n}\n\n/**\n * Resolve an anchor's associated document region to a concrete `Range`.\n *\n * This may fail if anchoring failed or if the document has been mutated since\n * the anchor was created in a way that invalidates the anchor.\n *\n * @param {Anchor} anchor\n * @return {Range|null}\n */\nfunction resolveAnchor(anchor) {\n\n if (!anchor.range) {\n return null;\n }\n try {\n return anchor.range.toRange();\n } catch {\n return null;\n }\n}\n\n/**\n * Wraps the DOM Nodes within the provided range with a highlight\n * element of the specified class and returns the highlight Elements.\n *\n * Modified for handling annotations.\n *\n * @param {Range} range - Range to be highlighted\n * @param {int} annotationid - ID of annotation\n * @param {string} cssClass - A CSS class to use for the highlight\n * @param {string} color - Color of the highlighting\n * @return {HighlightElement[]} - Elements wrapping text in `normedRange` to add a highlight effect\n */\n function highlightRange(range, annotationid = false, cssClass = 'annotated', color = 'FFFF00') {\n\n const textNodes = wholeTextNodesInRange(range);\n\n // Group text nodes into spans of adjacent nodes. If a group of text nodes are\n // adjacent, we only need to create one highlight element for the group.\n let textNodeSpans = [];\n let prevNode = null;\n let currentSpan = null;\n\n textNodes.forEach(node => {\n if (prevNode && prevNode.nextSibling === node) {\n currentSpan.push(node);\n } else {\n currentSpan = [node];\n textNodeSpans.push(currentSpan);\n }\n prevNode = node;\n });\n\n // Filter out text node spans that consist only of white space. This avoids\n // inserting highlight elements in places that can only contain a restricted\n // subset of nodes such as table rows and lists.\n const whitespace = /^\\s*$/;\n textNodeSpans = textNodeSpans.filter(span =>\n // Check for at least one text node with non-space content.\n span.some(node => !whitespace.test(node.nodeValue))\n );\n\n // Wrap each text node span with a `` element.\n const highlights = /** @type {HighlightElement[]} */ ([]);\n\n textNodeSpans.forEach(nodes => {\n const highlightEl = document.createElement('margic-highlight');\n highlightEl.className = cssClass;\n\n if (annotationid) {\n highlightEl.className += ' ' + cssClass + '-' + annotationid;\n highlightEl.style = \"text-decoration:underline; text-decoration-color: #\" + color;\n highlightEl.id = cssClass + '-' + annotationid;\n highlightEl.style.backgroundColor = '#' + color;\n }\n\n const parent = /** @type {Node} */ (nodes[0].parentNode);\n parent.replaceChild(highlightEl, nodes[0]);\n nodes.forEach(node => highlightEl.appendChild(node));\n\n highlights.push(highlightEl);\n\n });\n\n return highlights;\n}\n\n/**\n * Return text nodes which are entirely inside `range`.\n *\n * If a range starts or ends part-way through a text node, the node is split\n * and the part inside the range is returned.\n *\n * @param {Range} range\n * @return {Text[]}\n */\n function wholeTextNodesInRange(range) {\n if (range.collapsed) {\n // Exit early for an empty range to avoid an edge case that breaks the algorithm\n // below. Splitting a text node at the start of an empty range can leave the\n // range ending in the left part rather than the right part.\n return [];\n }\n\n /** @type {Node|null} */\n let root = range.commonAncestorContainer;\n if (root.nodeType !== Node.ELEMENT_NODE) {\n // If the common ancestor is not an element, set it to the parent element to\n // ensure that the loop below visits any text nodes generated by splitting\n // the common ancestor.\n //\n // Note that `parentElement` may be `null`.\n root = root.parentElement;\n }\n\n if (!root) {\n // If there is no root element then we won't be able to insert highlights,\n // so exit here.\n return [];\n }\n\n const textNodes = [];\n const nodeIter = /** @type {Document} */ (\n root.ownerDocument\n ).createNodeIterator(\n root,\n NodeFilter.SHOW_TEXT // Only return `Text` nodes.\n );\n let node;\n while ((node = nodeIter.nextNode())) {\n if (!isNodeInRange(range, node)) {\n continue;\n }\n let text = /** @type {Text} */ (node);\n\n if (text === range.startContainer && range.startOffset > 0) {\n // Split `text` where the range starts. The split will create a new `Text`\n // node which will be in the range and will be visited in the next loop iteration.\n text.splitText(range.startOffset);\n continue;\n }\n\n if (text === range.endContainer && range.endOffset < text.data.length) {\n // Split `text` where the range ends, leaving it as the part in the range.\n text.splitText(range.endOffset);\n }\n\n textNodes.push(text);\n }\n\n return textNodes;\n}\n\n/**\n * Returns true if any part of `node` lies within `range`.\n *\n * @param {Range} range\n * @param {Node} node\n * @return {bool} - If node is in range\n */\nfunction isNodeInRange(range, node) {\n try {\n const length = node.nodeValue?.length ?? node.childNodes.length;\n return (\n // Check start of node is before end of range.\n range.comparePoint(node, 0) <= 0 &&\n // Check end of node is after start of range.\n range.comparePoint(node, length) >= 0\n );\n } catch (e) {\n // `comparePoint` may fail if the `range` and `node` do not share a common\n // ancestor or `node` is a doctype.\n return false;\n }\n}\n\n/**\n * @param {RangeAnchor|TextPositionAnchor|TextQuoteAnchor} anchor\n * @param {Object} [options]\n * @return {obj} - range\n */\n function querySelector(anchor, options = {}) {\n\n return anchor.toRange(options);\n}\n\n/**\n * Anchor a set of selectors.\n *\n * This function converts a set of selectors into a document range.\n * It encapsulates the core anchoring algorithm, using the selectors alone or\n * in combination to establish the best anchor within the document.\n *\n * @param {Element} root - The root element of the anchoring context.\n * @param {Selector[]} selectors - The selectors to try.\n * @param {Object} [options]\n * @return {object} the query selector\n */\n function htmlAnchor(root, selectors, options = {}) {\n let position = null;\n let quote = null;\n let range = null;\n\n // Collect all the selectors\n for (let selector of selectors) {\n switch (selector.type) {\n case 'TextPositionSelector':\n position = selector;\n options.hint = position.start; // TextQuoteAnchor hint\n break;\n case 'TextQuoteSelector':\n quote = selector;\n break;\n case 'RangeSelector':\n range = selector;\n break;\n }\n }\n\n /**\n * Assert the quote matches the stored quote, if applicable\n * @param {Range} range\n * @return {Range} range\n */\n const maybeAssertQuote = range => {\n\n if (quote?.exact && range.toString() !== quote.exact) {\n throw new Error('quote mismatch');\n } else {\n return range;\n }\n };\n\n let queryselector = false;\n\n try {\n if (range) {\n\n let anchor = RangeAnchor.fromSelector(root, range);\n\n queryselector = querySelector(anchor, options);\n\n if (queryselector) {\n return queryselector;\n } else {\n return maybeAssertQuote;\n }\n }\n } catch (error) {\n try {\n if (position) {\n\n let anchor = TextPositionAnchor.fromSelector(root, position);\n\n queryselector = querySelector(anchor, options);\n if (queryselector) {\n return queryselector;\n } else {\n return maybeAssertQuote;\n }\n }\n } catch (error) {\n try {\n if (quote) {\n\n let anchor = TextQuoteAnchor.fromSelector(root, quote);\n\n queryselector = querySelector(anchor, options);\n\n return queryselector;\n }\n } catch (error) {\n return false;\n }\n }\n }\n}\n\n/**\n * Remove all temporary highlights under a given root element.\n */\n export function removeAllTempHighlights() {\n const highlights = Array.from($('body')[0].querySelectorAll('.annotated_temp'));\n if (highlights !== undefined && highlights.length != 0) {\n removeHighlights(highlights);\n }\n}\n\n/**\n * Remove highlights from a range previously highlighted with `highlightRange`.\n *\n * @param {HighlightElement[]} highlights - The highlight elements returned by `highlightRange`\n */\n function removeHighlights(highlights) {\n\n for (var i = 0; i < highlights.length; i++) {\n if (highlights[i].parentNode) {\n const children = Array.from(highlights[i].childNodes);\n replaceWith(highlights[i], children);\n }\n }\n}\n\n/**\n * Replace a child `node` with `replacements`.\n *\n * nb. This is like `ChildNode.replaceWith` but it works in older browsers.\n *\n * @param {ChildNode} node\n * @param {Node[]} replacements\n */\nfunction replaceWith(node, replacements) {\n const parent = /** @type {Node} */ (node.parentNode);\n\n replacements.forEach(r => parent.insertBefore(r, node));\n node.remove();\n}"],"names":["highlightRange","range","annotationid","cssClass","color","textNodes","wholeTextNodesInRange","textNodeSpans","prevNode","currentSpan","forEach","node","nextSibling","push","whitespace","filter","span","some","test","nodeValue","highlights","nodes","highlightEl","document","createElement","className","style","id","backgroundColor","parentNode","replaceChild","appendChild","collapsed","root","commonAncestorContainer","nodeType","Node","ELEMENT_NODE","parentElement","nodeIter","ownerDocument","createNodeIterator","NodeFilter","SHOW_TEXT","nextNode","isNodeInRange","text","startContainer","startOffset","splitText","endContainer","endOffset","data","length","_node$nodeValue","childNodes","comparePoint","e","querySelector","anchor","options","toRange","replaceWith","replacements","parent","r","insertBefore","remove","annotation","highlight","resolveAnchor","h","_annotation","target","anchors","map","selector","s","type","selectors","position","quote","hint","start","maybeAssertQuote","exact","toString","Error","RangeAnchor","fromSelector","error","TextPositionAnchor","TextQuoteAnchor","htmlAnchor","textRange","TextRange","fromRange","err","$orphan","every","types","result","toSelector","Array","from","querySelectorAll","undefined","i","children","removeHighlights"],"mappings":"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"} \ No newline at end of file +{"version":3,"sources":["../src/highlighting.js"],"names":["root","range","types","RangeAnchor","TextPositionAnchor","TextQuoteAnchor","result","type","anchor","fromRange","push","toSelector","error","annotation","highlight","resolveAnchor","highlights","highlightRange","id","color","forEach","h","_annotation","target","anchors","map","locate","selector","some","s","htmlAnchor","textRange","TextRange","err","$orphan","length","every","toRange","annotationid","cssClass","textNodes","wholeTextNodesInRange","textNodeSpans","prevNode","currentSpan","node","nextSibling","filter","span","test","nodeValue","nodes","highlightEl","document","createElement","className","style","backgroundColor","parent","parentNode","replaceChild","appendChild","collapsed","commonAncestorContainer","nodeType","Node","ELEMENT_NODE","parentElement","nodeIter","ownerDocument","createNodeIterator","NodeFilter","SHOW_TEXT","nextNode","isNodeInRange","text","startContainer","startOffset","splitText","endContainer","endOffset","data","childNodes","comparePoint","e","querySelector","options","selectors","position","quote","hint","start","maybeAssertQuote","exact","toString","Error","queryselector","fromSelector","removeAllTempHighlights","Array","from","querySelectorAll","removeHighlights","i","children","replaceWith","replacements","r","insertBefore","remove"],"mappings":"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","sourcesContent":["/**\n * Functions for the highlighting and anchoring of annotations.\n *\n * This code originaly is from the Hypothesis project (https://github.com/hypothesis/client)\n * which is released under the 2-Clause BSD License (https://opensource.org/licenses/BSD-2-Clause),\n * sometimes referred to as the \"Simplified BSD License\".\n */\n\nimport $ from 'jquery';\nimport {RangeAnchor, TextPositionAnchor, TextQuoteAnchor} from './types';\nimport {TextRange} from './text-range';\n\n/**\n * Get anchors for new annnotation.\n *\n * @param {Element} root\n * @param {Range} range\n * @return {object} - Array with the anchors.\n */\nexport function describe(root, range) {\n const types = [RangeAnchor, TextPositionAnchor, TextQuoteAnchor];\n const result = [];\n\n for (let type of types) {\n try {\n const anchor = type.fromRange(root, range);\n\n result.push(anchor.toSelector());\n } catch (error) {\n continue;\n }\n }\n return result;\n}\n\n/**\n * Anchor an annotation's selectors in the document.\n *\n * _Anchoring_ resolves a set of selectors to a concrete region of the document\n * which is then highlighted.\n *\n * Any existing anchors associated with `annotation` will be removed before\n * re-anchoring the annotation.\n *\n * @param {AnnotationData} annotation\n * @param {obj} root\n * @return {obj} achor object\n */\n export function anchor(annotation, root) {\n /**\n * Resolve an annotation's selectors to a concrete range.\n *\n * @param {Target} target\n * @return {obj}\n */\n const locate = target => {\n\n // Only annotations with an associated quote can currently be anchored.\n // This is because the quote is used to verify anchoring with other selector\n // types.\n if (\n !target.selector ||\n !target.selector.some(s => s.type === 'TextQuoteSelector')\n ) {\n return {annotation, target};\n }\n\n /** @type {Anchor} */\n let anchor;\n try {\n const range = htmlAnchor(root, target.selector);\n // Convert the `Range` to a `TextRange` which can be converted back to\n // a `Range` later. The `TextRange` representation allows for highlights\n // to be inserted during anchoring other annotations without \"breaking\"\n // this anchor.\n\n\n const textRange = TextRange.fromRange(range);\n\n anchor = {annotation, target, range: textRange};\n\n } catch (err) {\n\n anchor = {annotation, target};\n }\n\n return anchor;\n };\n\n /**\n * Highlight the text range that `anchor` refers to.\n *\n * @param {Anchor} anchor\n */\n const highlight = anchor => {\n\n const range = resolveAnchor(anchor);\n\n if (!range) {\n return;\n }\n\n let highlights = [];\n\n if (annotation.annotation) {\n highlights = highlightRange(range, annotation.annotation.id, 'annotated', annotation.annotation.color);\n } else {\n highlights = highlightRange(range, false, 'annotated_temp');\n }\n\n highlights.forEach(h => {\n h._annotation = anchor.annotation;\n });\n anchor.highlights = highlights;\n\n };\n\n // Remove existing anchors for this annotation.\n // this.detach(annotation, false /* notify */); // To be replaced by own method\n\n // Resolve selectors to ranges and insert highlights.\n if (!annotation.target) {\n annotation.target = [];\n }\n const anchors = annotation.target.map(locate);\n\n for (let anchor of anchors) {\n\n highlight(anchor);\n }\n\n // Set flag indicating whether anchoring succeeded. For each target,\n // anchoring is successful either if there are no selectors (ie. this is a\n // Page Note) or we successfully resolved the selectors to a range.\n annotation.$orphan =\n anchors.length > 0 &&\n anchors.every(anchor => anchor.target.selector && !anchor.range);\n\n return anchors;\n}\n\n/**\n * Resolve an anchor's associated document region to a concrete `Range`.\n *\n * This may fail if anchoring failed or if the document has been mutated since\n * the anchor was created in a way that invalidates the anchor.\n *\n * @param {Anchor} anchor\n * @return {Range|null}\n */\nfunction resolveAnchor(anchor) {\n\n if (!anchor.range) {\n return null;\n }\n try {\n return anchor.range.toRange();\n } catch {\n return null;\n }\n}\n\n/**\n * Wraps the DOM Nodes within the provided range with a highlight\n * element of the specified class and returns the highlight Elements.\n *\n * Modified for handling annotations.\n *\n * @param {Range} range - Range to be highlighted\n * @param {int} annotationid - ID of annotation\n * @param {string} cssClass - A CSS class to use for the highlight\n * @param {string} color - Color of the highlighting\n * @return {HighlightElement[]} - Elements wrapping text in `normedRange` to add a highlight effect\n */\n function highlightRange(range, annotationid = false, cssClass = 'annotated', color = 'FFFF00') {\n\n const textNodes = wholeTextNodesInRange(range);\n\n // Group text nodes into spans of adjacent nodes. If a group of text nodes are\n // adjacent, we only need to create one highlight element for the group.\n let textNodeSpans = [];\n let prevNode = null;\n let currentSpan = null;\n\n textNodes.forEach(node => {\n if (prevNode && prevNode.nextSibling === node) {\n currentSpan.push(node);\n } else {\n currentSpan = [node];\n textNodeSpans.push(currentSpan);\n }\n prevNode = node;\n });\n\n // Filter out text node spans that consist only of white space. This avoids\n // inserting highlight elements in places that can only contain a restricted\n // subset of nodes such as table rows and lists.\n const whitespace = /^\\s*$/;\n textNodeSpans = textNodeSpans.filter(span =>\n // Check for at least one text node with non-space content.\n span.some(node => !whitespace.test(node.nodeValue))\n );\n\n // Wrap each text node span with a `` element.\n const highlights = /** @type {HighlightElement[]} */ ([]);\n\n textNodeSpans.forEach(nodes => {\n const highlightEl = document.createElement('margic-highlight');\n highlightEl.className = cssClass;\n\n if (annotationid) {\n highlightEl.className += ' ' + cssClass + '-' + annotationid;\n highlightEl.style = \"text-decoration:underline; text-decoration-color: #\" + color;\n highlightEl.id = cssClass + '-' + annotationid;\n highlightEl.style.backgroundColor = '#' + color;\n }\n\n const parent = /** @type {Node} */ (nodes[0].parentNode);\n parent.replaceChild(highlightEl, nodes[0]);\n nodes.forEach(node => highlightEl.appendChild(node));\n\n highlights.push(highlightEl);\n\n });\n\n return highlights;\n}\n\n/**\n * Return text nodes which are entirely inside `range`.\n *\n * If a range starts or ends part-way through a text node, the node is split\n * and the part inside the range is returned.\n *\n * @param {Range} range\n * @return {Text[]}\n */\n function wholeTextNodesInRange(range) {\n if (range.collapsed) {\n // Exit early for an empty range to avoid an edge case that breaks the algorithm\n // below. Splitting a text node at the start of an empty range can leave the\n // range ending in the left part rather than the right part.\n return [];\n }\n\n /** @type {Node|null} */\n let root = range.commonAncestorContainer;\n if (root.nodeType !== Node.ELEMENT_NODE) {\n // If the common ancestor is not an element, set it to the parent element to\n // ensure that the loop below visits any text nodes generated by splitting\n // the common ancestor.\n //\n // Note that `parentElement` may be `null`.\n root = root.parentElement;\n }\n\n if (!root) {\n // If there is no root element then we won't be able to insert highlights,\n // so exit here.\n return [];\n }\n\n const textNodes = [];\n const nodeIter = /** @type {Document} */ (\n root.ownerDocument\n ).createNodeIterator(\n root,\n NodeFilter.SHOW_TEXT // Only return `Text` nodes.\n );\n let node;\n while ((node = nodeIter.nextNode())) {\n if (!isNodeInRange(range, node)) {\n continue;\n }\n let text = /** @type {Text} */ (node);\n\n if (text === range.startContainer && range.startOffset > 0) {\n // Split `text` where the range starts. The split will create a new `Text`\n // node which will be in the range and will be visited in the next loop iteration.\n text.splitText(range.startOffset);\n continue;\n }\n\n if (text === range.endContainer && range.endOffset < text.data.length) {\n // Split `text` where the range ends, leaving it as the part in the range.\n text.splitText(range.endOffset);\n }\n\n textNodes.push(text);\n }\n\n return textNodes;\n}\n\n/**\n * Returns true if any part of `node` lies within `range`.\n *\n * @param {Range} range\n * @param {Node} node\n * @return {bool} - If node is in range\n */\nfunction isNodeInRange(range, node) {\n try {\n const length = node.nodeValue?.length ?? node.childNodes.length;\n return (\n // Check start of node is before end of range.\n range.comparePoint(node, 0) <= 0 &&\n // Check end of node is after start of range.\n range.comparePoint(node, length) >= 0\n );\n } catch (e) {\n // `comparePoint` may fail if the `range` and `node` do not share a common\n // ancestor or `node` is a doctype.\n return false;\n }\n}\n\n/**\n * @param {RangeAnchor|TextPositionAnchor|TextQuoteAnchor} anchor\n * @param {Object} [options]\n * @return {obj} - range\n */\n function querySelector(anchor, options = {}) {\n\n return anchor.toRange(options);\n}\n\n/**\n * Anchor a set of selectors.\n *\n * This function converts a set of selectors into a document range.\n * It encapsulates the core anchoring algorithm, using the selectors alone or\n * in combination to establish the best anchor within the document.\n *\n * @param {Element} root - The root element of the anchoring context.\n * @param {Selector[]} selectors - The selectors to try.\n * @param {Object} [options]\n * @return {object} the query selector\n */\n function htmlAnchor(root, selectors, options = {}) {\n let position = null;\n let quote = null;\n let range = null;\n\n // Collect all the selectors\n for (let selector of selectors) {\n switch (selector.type) {\n case 'TextPositionSelector':\n position = selector;\n options.hint = position.start; // TextQuoteAnchor hint\n break;\n case 'TextQuoteSelector':\n quote = selector;\n break;\n case 'RangeSelector':\n range = selector;\n break;\n }\n }\n\n /**\n * Assert the quote matches the stored quote, if applicable\n * @param {Range} range\n * @return {Range} range\n */\n const maybeAssertQuote = range => {\n\n if (quote?.exact && range.toString() !== quote.exact) {\n throw new Error('quote mismatch');\n } else {\n return range;\n }\n };\n\n let queryselector = false;\n\n try {\n if (range) {\n\n let anchor = RangeAnchor.fromSelector(root, range);\n\n queryselector = querySelector(anchor, options);\n\n if (queryselector) {\n return queryselector;\n } else {\n return maybeAssertQuote;\n }\n }\n } catch (error) {\n try {\n if (position) {\n\n let anchor = TextPositionAnchor.fromSelector(root, position);\n\n queryselector = querySelector(anchor, options);\n if (queryselector) {\n return queryselector;\n } else {\n return maybeAssertQuote;\n }\n }\n } catch (error) {\n try {\n if (quote) {\n\n let anchor = TextQuoteAnchor.fromSelector(root, quote);\n\n queryselector = querySelector(anchor, options);\n\n return queryselector;\n }\n } catch (error) {\n return false;\n }\n }\n }\n}\n\n/**\n * Remove all temporary highlights under a given root element.\n */\n export function removeAllTempHighlights() {\n const highlights = Array.from($('body')[0].querySelectorAll('.annotated_temp'));\n if (highlights !== undefined && highlights.length != 0) {\n removeHighlights(highlights);\n }\n}\n\n/**\n * Remove highlights from a range previously highlighted with `highlightRange`.\n *\n * @param {HighlightElement[]} highlights - The highlight elements returned by `highlightRange`\n */\n function removeHighlights(highlights) {\n\n for (var i = 0; i < highlights.length; i++) {\n if (highlights[i].parentNode) {\n const children = Array.from(highlights[i].childNodes);\n replaceWith(highlights[i], children);\n }\n }\n}\n\n/**\n * Replace a child `node` with `replacements`.\n *\n * nb. This is like `ChildNode.replaceWith` but it works in older browsers.\n *\n * @param {ChildNode} node\n * @param {Node[]} replacements\n */\nfunction replaceWith(node, replacements) {\n const parent = /** @type {Node} */ (node.parentNode);\n\n replacements.forEach(r => parent.insertBefore(r, node));\n node.remove();\n}"],"file":"highlighting.min.js"} \ No newline at end of file diff --git a/amd/build/match-quote.min.js b/amd/build/match-quote.min.js index b9b83aa..137aa42 100644 --- a/amd/build/match-quote.min.js +++ b/amd/build/match-quote.min.js @@ -1,3 +1,2 @@ -define("mod_margic/match-quote",["exports","./string-match"],(function(_exports,_stringMatch){var obj;function search(text,str,maxErrors){for(var matchPos=0,exactMatches=[];-1!==matchPos;)-1!==(matchPos=text.indexOf(str,matchPos))&&(exactMatches.push({start:matchPos,end:matchPos+str.length,errors:0}),matchPos+=1);return exactMatches.length>0?exactMatches:(0,_stringMatch.default)(text,str,maxErrors)}function textMatchScore(text,str){return 0===str.length||0===text.length?0:1-search(text,str,str.length)[0].errors/str.length}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.matchQuote=function(text,quote){var context=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(0===quote.length)return null;var maxErrors=Math.min(256,quote.length/2),matches=search(text,quote,maxErrors);if(0===matches.length)return null;var scoreMatch=function(match){var quoteScore=1-match.errors/quote.length,prefixScore=context.prefix?textMatchScore(text.slice(Math.max(0,match.start-context.prefix.length),match.start),context.prefix):1,suffixScore=context.suffix?textMatchScore(text.slice(match.end,match.end+context.suffix.length),context.suffix):1,posScore=1;"number"==typeof context.hint&&(posScore=1-Math.abs(match.start-context.hint)/text.length);return(50*quoteScore+20*prefixScore+20*suffixScore+2*posScore)/92},scoredMatches=matches.map((function(m){return{start:m.start,end:m.end,score:scoreMatch(m)}}));return scoredMatches.sort((function(a,b){return b.score-a.score})),scoredMatches[0]},_stringMatch=(obj=_stringMatch)&&obj.__esModule?obj:{default:obj}})); - -//# sourceMappingURL=match-quote.min.js.map \ No newline at end of file +define ("mod_margic/match-quote",["exports","./string-match"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.matchQuote=function(a,b){var e=2 0) {\n return exactMatches;\n }\n\n // If there are no exact matches, do a more expensive search for matches\n // with errors.\n return approxSearch(text, str, maxErrors);\n}\n\n/**\n * Compute a score between 0 and 1.0 for the similarity between `text` and `str`.\n *\n * @param {string} text\n * @param {string} str\n * @return {int}\n */\nfunction textMatchScore(text, str) {\n // `search` will return no matches if either the text or pattern is empty,\n // otherwise it will return at least one match if the max allowed error count\n // is at least `str.length`.\n if (str.length === 0 || text.length === 0) {\n return 0.0;\n }\n\n const matches = search(text, str, str.length);\n\n // Prettier-ignore.\n return 1 - (matches[0].errors / str.length);\n}\n\n/**\n * Find the best approximate match for `quote` in `text`.\n *\n * Returns `null` if no match exceeding the minimum quality threshold was found.\n *\n * @param {string} text - Document text to search\n * @param {string} quote - String to find within `text`\n * @param {Object} context -\n * Context in which the quote originally appeared. This is used to choose the\n * best match.\n * @param {string} [context.prefix] - Expected text before the quote\n * @param {string} [context.suffix] - Expected text after the quote\n * @param {number} [context.hint] - Expected offset of match within text\n * @return {Match|null}\n */\nexport function matchQuote(text, quote, context = {}) {\n if (quote.length === 0) {\n return null;\n }\n\n // Choose the maximum number of errors to allow for the initial search.\n // This choice involves a tradeoff between:\n //\n // - Recall (proportion of \"good\" matches found)\n // - Precision (proportion of matches found which are \"good\")\n // - Cost of the initial search and of processing the candidate matches [1]\n //\n // [1] Specifically, the expected-time complexity of the initial search is\n // `O((maxErrors / 32) * text.length)`. See `approx-string-match` docs.\n const maxErrors = Math.min(256, quote.length / 2);\n\n // Find closest matches for `quote` in `text` based on edit distance.\n const matches = search(text, quote, maxErrors);\n\n if (matches.length === 0) {\n return null;\n }\n\n /**\n * Compute a score between 0 and 1.0 for a match candidate.\n *\n * @param {StringMatch} match\n * @return {int}\n */\n const scoreMatch = match => {\n const quoteWeight = 50; // Similarity of matched text to quote.\n const prefixWeight = 20; // Similarity of text before matched text to `context.prefix`.\n const suffixWeight = 20; // Similarity of text after matched text to `context.suffix`.\n const posWeight = 2; // Proximity to expected location. Used as a tie-breaker.\n\n const quoteScore = 1 - match.errors / quote.length;\n\n const prefixScore = context.prefix\n ? textMatchScore(\n text.slice(\n Math.max(0, match.start - context.prefix.length),\n match.start\n ),\n context.prefix\n )\n : 1.0;\n const suffixScore = context.suffix\n ? textMatchScore(\n text.slice(match.end, match.end + context.suffix.length),\n context.suffix\n )\n : 1.0;\n\n let posScore = 1.0;\n if (typeof context.hint === 'number') {\n const offset = Math.abs(match.start - context.hint);\n posScore = 1.0 - offset / text.length;\n }\n\n const rawScore =\n quoteWeight * quoteScore +\n prefixWeight * prefixScore +\n suffixWeight * suffixScore +\n posWeight * posScore;\n const maxScore = quoteWeight + prefixWeight + suffixWeight + posWeight;\n const normalizedScore = rawScore / maxScore;\n\n return normalizedScore;\n };\n\n // Rank matches based on similarity of actual and expected surrounding text\n // and actual/expected offset in the document text.\n const scoredMatches = matches.map(m => ({\n start: m.start,\n end: m.end,\n score: scoreMatch(m),\n }));\n\n // Choose match with highest score.\n scoredMatches.sort((a, b) => b.score - a.score);\n return scoredMatches[0];\n}\n"],"names":["search","text","str","maxErrors","matchPos","exactMatches","indexOf","push","start","end","length","errors","textMatchScore","quote","context","Math","min","matches","scoreMatch","match","quoteScore","prefixScore","prefix","slice","max","suffixScore","suffix","posScore","hint","abs","quoteWeight","scoredMatches","map","m","score","sort","a","b"],"mappings":"+GA+BSA,OAAOC,KAAMC,IAAKC,mBAGrBC,SAAW,EACXC,aAAe,IACE,IAAdD,WAEa,KADlBA,SAAWH,KAAKK,QAAQJ,IAAKE,aAE3BC,aAAaE,KAAK,CAChBC,MAAOJ,SACPK,IAAKL,SAAWF,IAAIQ,OACpBC,OAAQ,IAEVP,UAAY,UAGZC,aAAaK,OAAS,EACjBL,cAKF,wBAAaJ,KAAMC,IAAKC,oBAUxBS,eAAeX,KAAMC,YAIT,IAAfA,IAAIQ,QAAgC,IAAhBT,KAAKS,OACpB,EAMF,EAHSV,OAAOC,KAAMC,IAAKA,IAAIQ,QAGlB,GAAGC,OAAST,IAAIQ,4FAkBXT,KAAMY,WAAOC,+DAAU,MAC3B,IAAjBD,MAAMH,cACD,SAYHP,UAAYY,KAAKC,IAAI,IAAKH,MAAMH,OAAS,GAGzCO,QAAUjB,OAAOC,KAAMY,MAAOV,cAEb,IAAnBc,QAAQP,cACH,SASHQ,WAAa,SAAAC,WAMXC,WAAa,EAAID,MAAMR,OAASE,MAAMH,OAEtCW,YAAcP,QAAQQ,OACxBV,eACEX,KAAKsB,MACHR,KAAKS,IAAI,EAAGL,MAAMX,MAAQM,QAAQQ,OAAOZ,QACzCS,MAAMX,OAERM,QAAQQ,QAEV,EACEG,YAAcX,QAAQY,OACxBd,eACEX,KAAKsB,MAAMJ,MAAMV,IAAKU,MAAMV,IAAMK,QAAQY,OAAOhB,QACjDI,QAAQY,QAEV,EAEAC,SAAW,EACa,iBAAjBb,QAAQc,OAEjBD,SAAW,EADIZ,KAAKc,IAAIV,MAAMX,MAAQM,QAAQc,MACpB3B,KAAKS,eA1Bb,GA8BJU,WA7BK,GA8BJC,YA7BI,GA8BJI,YA7BC,EA8BJE,UACGG,IAQbC,cAAgBd,QAAQe,KAAI,SAAAC,SAAM,CACtCzB,MAAOyB,EAAEzB,MACTC,IAAKwB,EAAExB,IACPyB,MAAOhB,WAAWe,cAIpBF,cAAcI,MAAK,SAACC,EAAGC,UAAMA,EAAEH,MAAQE,EAAEF,SAClCH,cAAc"} \ No newline at end of file +{"version":3,"sources":["../src/match-quote.js"],"names":["text","quote","context","length","maxErrors","Math","min","matches","search","scoreMatch","match","prefixWeight","suffixWeight","posWeight","quoteScore","errors","prefixScore","prefix","textMatchScore","slice","max","start","suffixScore","suffix","end","posScore","hint","offset","abs","rawScore","scoredMatches","map","m","score","sort","a","b","str","matchPos","exactMatches","indexOf","push"],"mappings":"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","sourcesContent":["/**\n * Functions for quote matching for the annotations and highlighting.\n *\n * This code originaly is from the Hypothesis project (https://github.com/hypothesis/client)\n * which is released under the 2-Clause BSD License (https://opensource.org/licenses/BSD-2-Clause),\n * sometimes referred to as the \"Simplified BSD License\".\n */\n\nimport approxSearch from './string-match';\n\n/**\n * @typedef {import('approx-string-match').Match} StringMatch\n */\n\n/**\n * @typedef Match\n * @prop {number} start - Start offset of match in text\n * @prop {number} end - End offset of match in text\n * @prop {number} score -\n * Score for the match between 0 and 1.0, where 1.0 indicates a perfect match\n * for the quote and context.\n */\n\n/**\n * Find the best approximate matches for `str` in `text` allowing up to `maxErrors` errors.\n *\n * @param {string} text\n * @param {string} str\n * @param {number} maxErrors\n * @return {StringMatch[]}\n */\nfunction search(text, str, maxErrors) {\n // Do a fast search for exact matches. The `approx-string-match` library\n // doesn't currently incorporate this optimization itself.\n let matchPos = 0;\n let exactMatches = [];\n while (matchPos !== -1) {\n matchPos = text.indexOf(str, matchPos);\n if (matchPos !== -1) {\n exactMatches.push({\n start: matchPos,\n end: matchPos + str.length,\n errors: 0,\n });\n matchPos += 1;\n }\n }\n if (exactMatches.length > 0) {\n return exactMatches;\n }\n\n // If there are no exact matches, do a more expensive search for matches\n // with errors.\n return approxSearch(text, str, maxErrors);\n}\n\n/**\n * Compute a score between 0 and 1.0 for the similarity between `text` and `str`.\n *\n * @param {string} text\n * @param {string} str\n * @return {int}\n */\nfunction textMatchScore(text, str) {\n // `search` will return no matches if either the text or pattern is empty,\n // otherwise it will return at least one match if the max allowed error count\n // is at least `str.length`.\n if (str.length === 0 || text.length === 0) {\n return 0.0;\n }\n\n const matches = search(text, str, str.length);\n\n // Prettier-ignore.\n return 1 - (matches[0].errors / str.length);\n}\n\n/**\n * Find the best approximate match for `quote` in `text`.\n *\n * Returns `null` if no match exceeding the minimum quality threshold was found.\n *\n * @param {string} text - Document text to search\n * @param {string} quote - String to find within `text`\n * @param {Object} context -\n * Context in which the quote originally appeared. This is used to choose the\n * best match.\n * @param {string} [context.prefix] - Expected text before the quote\n * @param {string} [context.suffix] - Expected text after the quote\n * @param {number} [context.hint] - Expected offset of match within text\n * @return {Match|null}\n */\nexport function matchQuote(text, quote, context = {}) {\n if (quote.length === 0) {\n return null;\n }\n\n // Choose the maximum number of errors to allow for the initial search.\n // This choice involves a tradeoff between:\n //\n // - Recall (proportion of \"good\" matches found)\n // - Precision (proportion of matches found which are \"good\")\n // - Cost of the initial search and of processing the candidate matches [1]\n //\n // [1] Specifically, the expected-time complexity of the initial search is\n // `O((maxErrors / 32) * text.length)`. See `approx-string-match` docs.\n const maxErrors = Math.min(256, quote.length / 2);\n\n // Find closest matches for `quote` in `text` based on edit distance.\n const matches = search(text, quote, maxErrors);\n\n if (matches.length === 0) {\n return null;\n }\n\n /**\n * Compute a score between 0 and 1.0 for a match candidate.\n *\n * @param {StringMatch} match\n * @return {int}\n */\n const scoreMatch = match => {\n const quoteWeight = 50; // Similarity of matched text to quote.\n const prefixWeight = 20; // Similarity of text before matched text to `context.prefix`.\n const suffixWeight = 20; // Similarity of text after matched text to `context.suffix`.\n const posWeight = 2; // Proximity to expected location. Used as a tie-breaker.\n\n const quoteScore = 1 - match.errors / quote.length;\n\n const prefixScore = context.prefix\n ? textMatchScore(\n text.slice(\n Math.max(0, match.start - context.prefix.length),\n match.start\n ),\n context.prefix\n )\n : 1.0;\n const suffixScore = context.suffix\n ? textMatchScore(\n text.slice(match.end, match.end + context.suffix.length),\n context.suffix\n )\n : 1.0;\n\n let posScore = 1.0;\n if (typeof context.hint === 'number') {\n const offset = Math.abs(match.start - context.hint);\n posScore = 1.0 - offset / text.length;\n }\n\n const rawScore =\n quoteWeight * quoteScore +\n prefixWeight * prefixScore +\n suffixWeight * suffixScore +\n posWeight * posScore;\n const maxScore = quoteWeight + prefixWeight + suffixWeight + posWeight;\n const normalizedScore = rawScore / maxScore;\n\n return normalizedScore;\n };\n\n // Rank matches based on similarity of actual and expected surrounding text\n // and actual/expected offset in the document text.\n const scoredMatches = matches.map(m => ({\n start: m.start,\n end: m.end,\n score: scoreMatch(m),\n }));\n\n // Choose match with highest score.\n scoredMatches.sort((a, b) => b.score - a.score);\n return scoredMatches[0];\n}\n"],"file":"match-quote.min.js"} \ No newline at end of file diff --git a/amd/build/string-match.min.js b/amd/build/string-match.min.js index 1b442cf..b00b852 100644 --- a/amd/build/string-match.min.js +++ b/amd/build/string-match.min.js @@ -1,3 +1,2 @@ -define("mod_margic/string-match",["exports"],(function(_exports){function reverse(s){return s.split("").reverse().join("")}function oneIfNotZero(n){return(n|-n)>>31&1}function advanceBlock(ctx,peq,b,hIn){var pV=ctx.P[b],mV=ctx.M[b],hInIsNegative=hIn>>>31,eq=peq[b]|hInIsNegative,xV=eq|mV,xH=(eq&pV)+pV^pV|eq,pH=mV|~(xH|pV),mH=pV&xH,hOut=oneIfNotZero(pH&ctx.lastRowMask[b])-oneIfNotZero(mH&ctx.lastRowMask[b]);return pH<<=1,mH<<=1,pV=(mH|=hInIsNegative)|~(xV|(pH|=oneIfNotZero(hIn)-hInIsNegative)),mV=pH&xV,ctx.P[b]=pV,ctx.M[b]=mV,hOut}function findMatchEnds(text,pattern,maxErrors){if(0===pattern.length)return[];maxErrors=Math.min(maxErrors,pattern.length);var matches=[],w=32,bMax=Math.ceil(pattern.length/w)-1,ctx={P:new Uint32Array(bMax+1),M:new Uint32Array(bMax+1),lastRowMask:new Uint32Array(bMax+1)};ctx.lastRowMask.fill(1<<31),ctx.lastRowMask[bMax]=1<<(pattern.length-1)%w;for(var emptyPeq=new Uint32Array(bMax+1),peq=new Map,asciiPeq=[],i=0;i<256;i++)asciiPeq.push(emptyPeq);for(var c=0;c=pattern.length))pattern.charCodeAt(idx)===val&&(charPeq[b]|=1<0&&score[y]>=maxErrors+w;)y-=1;y===bMax&&score[y]<=maxErrors&&(score[y]>31}function e(a,c,e,b){var f=a.P[e],g=a.M[e],h=b>>>31,i=c[e]|h,j=i|g,k=(i&f)+f^f|i,l=g|~(k|f),m=f&k,n=d(l&a.lastRowMask[e])-d(m&a.lastRowMask[e]);l<<=1;m<<=1;m|=h;l|=d(b)-h;f=m|~(j|l);g=l&j;a.P[e]=f;a.M[e]=g;return n}function f(a,d,f){if(0===d.length){return[]}f=Math.min(f,d.length);var g=[],h=32,k=Math.ceil(d.length/h)-1,l={P:new Uint32Array(k+1),M:new Uint32Array(k+1),lastRowMask:new Uint32Array(k+1)};l.lastRowMask.fill(-2147483648);l.lastRowMask[k]=1<<(d.length-1)%h;for(var m=new Uint32Array(k+1),n=new Map,o=[],p=0;256>p;p++){o.push(m)}for(var z=0,c;z=d.length){continue}var C=d.charCodeAt(r)===c;if(C){A[B]|=1<w)){q+=1;l.P[q]=-1;l.M[q]=0;var j=void 0;if(q===k){var F=d.length%h;j=0==F?h:F}else{j=h}s[q]=s[q-1]+j-w+e(l,v,q,w)}else{while(0=f+h){q-=1}}if(q===k&&s[q]<=f){if(s[q] {\n // Find start of each match by reversing the pattern and matching segment\n // of text and searching for an approx match with the same number of\n // errors.\n const minStart = Math.max(0, m.end - pattern.length - m.errors);\n const textRev = reverse(text.slice(minStart, m.end));\n\n // If there are multiple possible start points, choose the one that\n // maximizes the length of the match.\n const start = findMatchEnds(textRev, patRev, m.errors).reduce((min, rm) => {\n if (m.end - rm.end < min) {\n return m.end - rm.end;\n }\n return min;\n }, m.end);\n\n return {\n start,\n end: m.end,\n errors: m.errors,\n };\n });\n }\n\n /**\n * Internal context used when calculating blocks of a column.\n */\n // interface Context {\n // /**\n // * Bit-arrays of positive vertical deltas.\n // *\n // * ie. `P[b][i]` is set if the vertical delta for the i'th row in the b'th\n // * block is positive.\n // */\n // P: Uint32Array;\n // /** Bit-arrays of negative vertical deltas. */\n // M: Uint32Array;\n // /** Bit masks with a single bit set indicating the last row in each block. */\n // lastRowMask: Uint32Array;\n // }\n\n /**\n * Return 1 if a number is non-zero or zero otherwise, without using\n * conditional operators.\n *\n * This should get inlined into `advanceBlock` below by the JIT.\n *\n * Adapted from https://stackoverflow.com/a/3912218/434243\n * @param {int} n\n * @return {bool}\n */\n function oneIfNotZero(n) {\n return ((n | -n) >> 31) & 1;\n }\n\n /**\n * Block calculation step of the algorithm.\n *\n * From Fig 8. on p. 408 of [1], additionally optimized to replace conditional\n * checks with bitwise operations as per Section 4.2.3 of [2].\n *\n * @param {obj} ctx - The pattern context object\n * @param {array} peq - The `peq` array for the current character (`ctx.peq.get(ch)`)\n * @param {int} b - The block level\n * @param {obj} hIn - Horizontal input delta ∈ {1,0,-1}\n * @return {obj} Horizontal output delta ∈ {1,0,-1}\n */\n function advanceBlock(ctx, peq, b, hIn) {\n let pV = ctx.P[b];\n let mV = ctx.M[b];\n const hInIsNegative = hIn >>> 31; // 1 if hIn < 0 or 0 otherwise.\n const eq = peq[b] | hInIsNegative;\n\n // Step 1: Compute horizontal deltas.\n const xV = eq | mV;\n const xH = (((eq & pV) + pV) ^ pV) | eq;\n\n let pH = mV | ~(xH | pV);\n let mH = pV & xH;\n\n // Step 2: Update score (value of last row of this block).\n const hOut =\n oneIfNotZero(pH & ctx.lastRowMask[b]) -\n oneIfNotZero(mH & ctx.lastRowMask[b]);\n\n // Step 3: Update vertical deltas for use when processing next char.\n pH <<= 1;\n mH <<= 1;\n\n mH |= hInIsNegative;\n pH |= oneIfNotZero(hIn) - hInIsNegative; // Set pH[0] if hIn > 0.\n\n pV = mH | ~(xV | pH);\n mV = pH & xV;\n\n ctx.P[b] = pV;\n ctx.M[b] = mV;\n\n return hOut;\n }\n\n /**\n * Find the ends and error counts for matches of `pattern` in `text`.\n *\n * Only the matches with the lowest error count are reported. Other matches\n * with error counts <= maxErrors are discarded.\n *\n * This is the block-based search algorithm from Fig. 9 on p.410 of [1].\n *\n * @param {string} text\n * @param {string} pattern\n * @param {array} maxErrors\n * @return {obj} Matches with the `start` property set.\n */\n function findMatchEnds(text, pattern, maxErrors) {\n if (pattern.length === 0) {\n return [];\n }\n\n // Clamp error count so we can rely on the `maxErrors` and `pattern.length`\n // rows being in the same block below.\n maxErrors = Math.min(maxErrors, pattern.length);\n\n const matches = [];\n\n // Word size.\n const w = 32;\n\n // Index of maximum block level.\n const bMax = Math.ceil(pattern.length / w) - 1;\n\n // Context used across block calculations.\n const ctx = {\n P: new Uint32Array(bMax + 1),\n M: new Uint32Array(bMax + 1),\n lastRowMask: new Uint32Array(bMax + 1),\n };\n ctx.lastRowMask.fill(1 << 31);\n ctx.lastRowMask[bMax] = 1 << (pattern.length - 1) % w;\n\n // Dummy \"peq\" array for chars in the text which do not occur in the pattern.\n const emptyPeq = new Uint32Array(bMax + 1);\n\n // Map of UTF-16 character code to bit vector indicating positions in the\n // pattern that equal that character.\n const peq = new Map();\n\n // Version of `peq` that only stores mappings for small characters. This\n // allows faster lookups when iterating through the text because a simple\n // array lookup can be done instead of a hash table lookup.\n const asciiPeq = [];\n for (let i = 0; i < 256; i++) {\n asciiPeq.push(emptyPeq);\n }\n\n // Calculate `ctx.peq` - a map of character values to bitmasks indicating\n // positions of that character within the pattern, where each bit represents\n // a position in the pattern.\n for (let c = 0; c < pattern.length; c += 1) {\n const val = pattern.charCodeAt(c);\n if (peq.has(val)) {\n // Duplicate char in pattern.\n continue;\n }\n\n const charPeq = new Uint32Array(bMax + 1);\n peq.set(val, charPeq);\n if (val < asciiPeq.length) {\n asciiPeq[val] = charPeq;\n }\n\n for (let b = 0; b <= bMax; b += 1) {\n charPeq[b] = 0;\n\n // Set all the bits where the pattern matches the current char (ch).\n // For indexes beyond the end of the pattern, always set the bit as if the\n // pattern contained a wildcard char in that position.\n for (let r = 0; r < w; r += 1) {\n const idx = b * w + r;\n if (idx >= pattern.length) {\n continue;\n }\n\n const match = pattern.charCodeAt(idx) === val;\n if (match) {\n charPeq[b] |= 1 << r;\n }\n }\n }\n }\n\n // Index of last-active block level in the column.\n let y = Math.max(0, Math.ceil(maxErrors / w) - 1);\n\n // Initialize maximum error count at bottom of each block.\n const score = new Uint32Array(bMax + 1);\n for (let b = 0; b <= y; b += 1) {\n score[b] = (b + 1) * w;\n }\n score[bMax] = pattern.length;\n\n // Initialize vertical deltas for each block.\n for (let b = 0; b <= y; b += 1) {\n ctx.P[b] = ~0;\n ctx.M[b] = 0;\n }\n\n // Process each char of the text, computing the error count for `w` chars of\n // the pattern at a time.\n for (let j = 0; j < text.length; j += 1) {\n // Lookup the bitmask representing the positions of the current char from\n // the text within the pattern.\n const charCode = text.charCodeAt(j);\n let charPeq;\n\n if (charCode < asciiPeq.length) {\n // Fast array lookup.\n charPeq = asciiPeq[charCode];\n } else {\n // Slower hash table lookup.\n charPeq = peq.get(charCode);\n if (typeof charPeq === \"undefined\") {\n charPeq = emptyPeq;\n }\n }\n\n // Calculate error count for blocks that we definitely have to process for\n // this column.\n let carry = 0;\n for (let b = 0; b <= y; b += 1) {\n carry = advanceBlock(ctx, charPeq, b, carry);\n score[b] += carry;\n }\n\n // Check if we also need to compute an additional block, or if we can reduce\n // the number of blocks processed for the next column.\n if (\n score[y] - carry <= maxErrors &&\n y < bMax &&\n (charPeq[y + 1] & 1 || carry < 0)\n ) {\n // Error count for bottom block is under threshold, increase the number of\n // blocks processed for this column & next by 1.\n y += 1;\n\n ctx.P[y] = ~0;\n ctx.M[y] = 0;\n\n let maxBlockScore;\n if (y === bMax) {\n const remainder = pattern.length % w;\n maxBlockScore = remainder === 0 ? w : remainder;\n } else {\n maxBlockScore = w;\n }\n\n score[y] =\n score[y - 1] +\n maxBlockScore -\n carry +\n advanceBlock(ctx, charPeq, y, carry);\n } else {\n // Error count for bottom block exceeds threshold, reduce the number of\n // blocks processed for the next column.\n while (y > 0 && score[y] >= maxErrors + w) {\n y -= 1;\n }\n }\n\n // If error count is under threshold, report a match.\n if (y === bMax && score[y] <= maxErrors) {\n if (score[y] < maxErrors) {\n // Discard any earlier, worse matches.\n matches.splice(0, matches.length);\n }\n\n matches.push({\n start: -1,\n end: j + 1,\n errors: score[y],\n });\n\n // Because `search` only reports the matches with the lowest error count,\n // we can \"ratchet down\" the max error threshold whenever a match is\n // encountered and thereby save a small amount of work for the remainder\n // of the text.\n maxErrors = score[y];\n }\n }\n\n return matches;\n }\n\n /**\n * Search for matches for `pattern` in `text` allowing up to `maxErrors` errors.\n *\n * Returns the start, and end positions and error counts for each lowest-cost\n * match. Only the \"best\" matches are returned.\n * @param {string} text\n * @param {string} pattern\n * @param {array} maxErrors\n * @return {obj} Matches with the `start` property set.\n */\n export default function search(\n text,\n pattern,\n maxErrors\n ) {\n const matches = findMatchEnds(text, pattern, maxErrors);\n return findMatchStarts(text, pattern, matches);\n }"],"names":["reverse","s","split","join","oneIfNotZero","n","advanceBlock","ctx","peq","b","hIn","pV","P","mV","M","hInIsNegative","eq","xV","xH","pH","mH","hOut","lastRowMask","findMatchEnds","text","pattern","maxErrors","length","Math","min","matches","w","bMax","ceil","Uint32Array","fill","emptyPeq","Map","asciiPeq","i","push","c","val","charCodeAt","has","charPeq","set","r","idx","y","max","score","j","charCode","get","carry","maxBlockScore","remainder","splice","start","end","errors","patRev","map","m","minStart","slice","reduce","rm","findMatchStarts"],"mappings":"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"} \ No newline at end of file +{"version":3,"sources":["../src/string-match.js"],"names":["text","pattern","maxErrors","matches","findMatchEnds","findMatchStarts","reverse","s","split","join","patRev","map","m","minStart","Math","max","end","length","errors","textRev","slice","start","reduce","min","rm","oneIfNotZero","n","advanceBlock","ctx","peq","b","hIn","pV","P","mV","M","hInIsNegative","eq","xV","xH","pH","mH","hOut","lastRowMask","w","bMax","ceil","Uint32Array","fill","emptyPeq","Map","asciiPeq","i","push","c","val","charCodeAt","has","charPeq","set","r","idx","match","y","score","j","charCode","get","carry","maxBlockScore","remainder","splice"],"mappings":"kIA2UiB,SACbA,CADa,CAEbC,CAFa,CAGbC,CAHa,CAIb,CACA,GAAMC,CAAAA,CAAO,CAAGC,CAAa,CAACJ,CAAD,CAAOC,CAAP,CAAgBC,CAAhB,CAA7B,CACA,MAAOG,CAAAA,CAAe,CAACL,CAAD,CAAOC,CAAP,CAAgBE,CAAhB,CACvB,C,CAtUD,QAASG,CAAAA,CAAT,CAAiBC,CAAjB,CAAoB,CAClB,MAAOA,CAAAA,CAAC,CAACC,KAAF,CAAQ,EAAR,EAAYF,OAAZ,GAAsBG,IAAtB,CAA2B,EAA3B,CACR,CAWD,QAASJ,CAAAA,CAAT,CAAyBL,CAAzB,CAA+BC,CAA/B,CAAwCE,CAAxC,CAAiD,CAC/C,GAAMO,CAAAA,CAAM,CAAGJ,CAAO,CAACL,CAAD,CAAtB,CAEA,MAAOE,CAAAA,CAAO,CAACQ,GAAR,CAAY,SAACC,CAAD,CAAO,IAIlBC,CAAAA,CAAQ,CAAGC,IAAI,CAACC,GAAL,CAAS,CAAT,CAAYH,CAAC,CAACI,GAAF,CAAQf,CAAO,CAACgB,MAAhB,CAAyBL,CAAC,CAACM,MAAvC,CAJO,CAKlBC,CAAO,CAAGb,CAAO,CAACN,CAAI,CAACoB,KAAL,CAAWP,CAAX,CAAqBD,CAAC,CAACI,GAAvB,CAAD,CALC,CASlBK,CAAK,CAAGjB,CAAa,CAACe,CAAD,CAAUT,CAAV,CAAkBE,CAAC,CAACM,MAApB,CAAb,CAAyCI,MAAzC,CAAgD,SAACC,CAAD,CAAMC,CAAN,CAAa,CACzE,GAAIZ,CAAC,CAACI,GAAF,CAAQQ,CAAE,CAACR,GAAX,CAAiBO,CAArB,CAA0B,CACxB,MAAOX,CAAAA,CAAC,CAACI,GAAF,CAAQQ,CAAE,CAACR,GACnB,CACD,MAAOO,CAAAA,CACR,CALa,CAKXX,CAAC,CAACI,GALS,CATU,CAgBxB,MAAO,CACLK,KAAK,CAALA,CADK,CAELL,GAAG,CAAEJ,CAAC,CAACI,GAFF,CAGLE,MAAM,CAAEN,CAAC,CAACM,MAHL,CAKR,CArBM,CAsBR,CA6BD,QAASO,CAAAA,CAAT,CAAsBC,CAAtB,CAAyB,CACvB,MAA0B,EAAnB,CAAC,CAACA,CAAC,CAAG,CAACA,CAAN,GAAY,EACrB,CAcD,QAASC,CAAAA,CAAT,CAAsBC,CAAtB,CAA2BC,CAA3B,CAAgCC,CAAhC,CAAmCC,CAAnC,CAAwC,IAClCC,CAAAA,CAAE,CAAGJ,CAAG,CAACK,CAAJ,CAAMH,CAAN,CAD6B,CAElCI,CAAE,CAAGN,CAAG,CAACO,CAAJ,CAAML,CAAN,CAF6B,CAGhCM,CAAa,CAAGL,CAAG,GAAK,EAHQ,CAIhCM,CAAE,CAAGR,CAAG,CAACC,CAAD,CAAH,CAASM,CAJkB,CAOhCE,CAAE,CAAGD,CAAE,CAAGH,CAPsB,CAQhCK,CAAE,CAAK,CAACF,CAAE,CAAGL,CAAN,EAAYA,CAAb,CAAmBA,CAApB,CAA0BK,CARC,CAUlCG,CAAE,CAAGN,CAAE,CAAG,EAAEK,CAAE,CAAGP,CAAP,CAVwB,CAWlCS,CAAE,CAAGT,CAAE,CAAGO,CAXwB,CAchCG,CAAI,CACRjB,CAAY,CAACe,CAAE,CAAGZ,CAAG,CAACe,WAAJ,CAAgBb,CAAhB,CAAN,CAAZ,CACAL,CAAY,CAACgB,CAAE,CAAGb,CAAG,CAACe,WAAJ,CAAgBb,CAAhB,CAAN,CAhBwB,CAmBtCU,CAAE,GAAK,CAAP,CACAC,CAAE,GAAK,CAAP,CAEAA,CAAE,EAAIL,CAAN,CACAI,CAAE,EAAIf,CAAY,CAACM,CAAD,CAAZ,CAAoBK,CAA1B,CAEAJ,CAAE,CAAGS,CAAE,CAAG,EAAEH,CAAE,CAAGE,CAAP,CAAV,CACAN,CAAE,CAAGM,CAAE,CAAGF,CAAV,CAEAV,CAAG,CAACK,CAAJ,CAAMH,CAAN,EAAWE,CAAX,CACAJ,CAAG,CAACO,CAAJ,CAAML,CAAN,EAAWI,CAAX,CAEA,MAAOQ,CAAAA,CACR,CAeD,QAAStC,CAAAA,CAAT,CAAuBJ,CAAvB,CAA6BC,CAA7B,CAAsCC,CAAtC,CAAiD,CAC/C,GAAuB,CAAnB,GAAAD,CAAO,CAACgB,MAAZ,CAA0B,CACxB,MAAO,EACR,CAIDf,CAAS,CAAGY,IAAI,CAACS,GAAL,CAASrB,CAAT,CAAoBD,CAAO,CAACgB,MAA5B,CAAZ,CAP+C,GASzCd,CAAAA,CAAO,CAAG,EAT+B,CAYzCyC,CAAC,CAAG,EAZqC,CAezCC,CAAI,CAAG/B,IAAI,CAACgC,IAAL,CAAU7C,CAAO,CAACgB,MAAR,CAAiB2B,CAA3B,EAAgC,CAfE,CAkBzChB,CAAG,CAAG,CACVK,CAAC,CAAE,GAAIc,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CADO,CAEVV,CAAC,CAAE,GAAIY,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CAFO,CAGVF,WAAW,CAAE,GAAII,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CAHH,CAlBmC,CAuB/CjB,CAAG,CAACe,WAAJ,CAAgBK,IAAhB,cACApB,CAAG,CAACe,WAAJ,CAAgBE,CAAhB,EAAwB,GAAK,CAAC5C,CAAO,CAACgB,MAAR,CAAiB,CAAlB,EAAuB2B,CAApD,CAaA,OAVMK,CAAAA,CAAQ,CAAG,GAAIF,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CAUjB,CANMhB,CAAG,CAAG,GAAIqB,CAAAA,GAMhB,CADMC,CAAQ,CAAG,EACjB,CAASC,CAAC,CAAG,CAAb,CAAoB,GAAJ,CAAAA,CAAhB,CAAyBA,CAAC,EAA1B,CAA8B,CAC5BD,CAAQ,CAACE,IAAT,CAAcJ,CAAd,CACD,CAKD,IAAK,GAAIK,CAAAA,CAAC,CAAG,CAAR,CACGC,CADR,CAAgBD,CAAC,CAAGrD,CAAO,CAACgB,MAA5B,CAAoCqC,CAAC,EAAI,CAAzC,CAA4C,CACpCC,CADoC,CAC9BtD,CAAO,CAACuD,UAAR,CAAmBF,CAAnB,CAD8B,CAE1C,GAAIzB,CAAG,CAAC4B,GAAJ,CAAQF,CAAR,CAAJ,CAAkB,CAEhB,QACD,CAED,GAAMG,CAAAA,CAAO,CAAG,GAAIX,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CAAhB,CACAhB,CAAG,CAAC8B,GAAJ,CAAQJ,CAAR,CAAaG,CAAb,EACA,GAAIH,CAAG,CAAGJ,CAAQ,CAAClC,MAAnB,CAA2B,CACzBkC,CAAQ,CAACI,CAAD,CAAR,CAAgBG,CACjB,CAED,IAAK,GAAI5B,CAAAA,CAAC,CAAG,CAAb,CAAgBA,CAAC,EAAIe,CAArB,CAA2Bf,CAAC,EAAI,CAAhC,CAAmC,CACjC4B,CAAO,CAAC5B,CAAD,CAAP,CAAa,CAAb,CAKA,IAAK,GAAI8B,CAAAA,CAAC,CAAG,CAAR,CACGC,CADR,CAAgBD,CAAC,CAAGhB,CAApB,CAAuBgB,CAAC,EAAI,CAA5B,CAA+B,CACvBC,CADuB,CACjB/B,CAAC,CAAGc,CAAJ,CAAQgB,CADS,CAE7B,GAAIC,CAAG,EAAI5D,CAAO,CAACgB,MAAnB,CAA2B,CACzB,QACD,CAED,GAAM6C,CAAAA,CAAK,CAAG7D,CAAO,CAACuD,UAAR,CAAmBK,CAAnB,IAA4BN,CAA1C,CACA,GAAIO,CAAJ,CAAW,CACTJ,CAAO,CAAC5B,CAAD,CAAP,EAAc,GAAK8B,CACpB,CACF,CACF,CACF,CAOD,OAJIG,CAAAA,CAAC,CAAGjD,IAAI,CAACC,GAAL,CAAS,CAAT,CAAYD,IAAI,CAACgC,IAAL,CAAU5C,CAAS,CAAG0C,CAAtB,EAA2B,CAAvC,CAIR,CADMoB,CAAK,CAAG,GAAIjB,CAAAA,WAAJ,CAAgBF,CAAI,CAAG,CAAvB,CACd,CAASf,CAAC,CAAG,CAAb,CAAgBA,CAAC,EAAIiC,CAArB,CAAwBjC,CAAC,EAAI,CAA7B,CAAgC,CAC9BkC,CAAK,CAAClC,CAAD,CAAL,CAAW,CAACA,CAAC,CAAG,CAAL,EAAUc,CACtB,CACDoB,CAAK,CAACnB,CAAD,CAAL,CAAc5C,CAAO,CAACgB,MAAtB,CAGA,IAAK,GAAIa,CAAAA,CAAC,CAAG,CAAb,CAAgBA,CAAC,EAAIiC,CAArB,CAAwBjC,CAAC,EAAI,CAA7B,CAAgC,CAC9BF,CAAG,CAACK,CAAJ,CAAMH,CAAN,KACAF,CAAG,CAACO,CAAJ,CAAML,CAAN,EAAW,CACZ,CAID,IAAK,GAAImC,CAAAA,CAAC,CAAG,CAAb,CAAgBA,CAAC,CAAGjE,CAAI,CAACiB,MAAzB,CAAiCgD,CAAC,EAAI,CAAtC,CAAyC,IAGjCC,CAAAA,CAAQ,CAAGlE,CAAI,CAACwD,UAAL,CAAgBS,CAAhB,CAHsB,CAInCP,CAAO,OAJ4B,CAMvC,GAAIQ,CAAQ,CAAGf,CAAQ,CAAClC,MAAxB,CAAgC,CAE9ByC,CAAO,CAAGP,CAAQ,CAACe,CAAD,CACnB,CAHD,IAGO,CAELR,CAAO,CAAG7B,CAAG,CAACsC,GAAJ,CAAQD,CAAR,CAAV,CACA,GAAuB,WAAnB,QAAOR,CAAAA,CAAX,CAAoC,CAClCA,CAAO,CAAGT,CACX,CACF,CAKD,OADImB,CAAAA,CAAK,CAAG,CACZ,CAAStC,CAAC,CAAG,CAAb,CAAgBA,CAAC,EAAIiC,CAArB,CAAwBjC,CAAC,EAAI,CAA7B,CAAgC,CAC9BsC,CAAK,CAAGzC,CAAY,CAACC,CAAD,CAAM8B,CAAN,CAAe5B,CAAf,CAAkBsC,CAAlB,CAApB,CACAJ,CAAK,CAAClC,CAAD,CAAL,EAAYsC,CACb,CAID,GACEJ,CAAK,CAACD,CAAD,CAAL,CAAWK,CAAX,EAAoBlE,CAApB,EACA6D,CAAC,CAAGlB,CADJ,GAEkB,CAAjB,CAAAa,CAAO,CAACK,CAAC,CAAG,CAAL,CAAP,EAA8B,CAAR,CAAAK,CAFvB,CADF,CAIE,CAGAL,CAAC,EAAI,CAAL,CAEAnC,CAAG,CAACK,CAAJ,CAAM8B,CAAN,KACAnC,CAAG,CAACO,CAAJ,CAAM4B,CAAN,EAAW,CAAX,CAEA,GAAIM,CAAAA,CAAa,OAAjB,CACA,GAAIN,CAAC,GAAKlB,CAAV,CAAgB,CACd,GAAMyB,CAAAA,CAAS,CAAGrE,CAAO,CAACgB,MAAR,CAAiB2B,CAAnC,CACAyB,CAAa,CAAiB,CAAd,EAAAC,CAAS,CAAS1B,CAAT,CAAa0B,CACvC,CAHD,IAGO,CACLD,CAAa,CAAGzB,CACjB,CAEDoB,CAAK,CAACD,CAAD,CAAL,CACEC,CAAK,CAACD,CAAC,CAAG,CAAL,CAAL,CACAM,CADA,CAEAD,CAFA,CAGAzC,CAAY,CAACC,CAAD,CAAM8B,CAAN,CAAeK,CAAf,CAAkBK,CAAlB,CACf,CAzBD,IAyBO,CAGL,MAAW,CAAJ,CAAAL,CAAC,EAAQC,CAAK,CAACD,CAAD,CAAL,EAAY7D,CAAS,CAAG0C,CAAxC,CAA2C,CACzCmB,CAAC,EAAI,CACN,CACF,CAGD,GAAIA,CAAC,GAAKlB,CAAN,EAAcmB,CAAK,CAACD,CAAD,CAAL,EAAY7D,CAA9B,CAAyC,CACvC,GAAI8D,CAAK,CAACD,CAAD,CAAL,CAAW7D,CAAf,CAA0B,CAExBC,CAAO,CAACoE,MAAR,CAAe,CAAf,CAAkBpE,CAAO,CAACc,MAA1B,CACD,CAEDd,CAAO,CAACkD,IAAR,CAAa,CACXhC,KAAK,CAAE,CAAC,CADG,CAEXL,GAAG,CAAEiD,CAAC,CAAG,CAFE,CAGX/C,MAAM,CAAE8C,CAAK,CAACD,CAAD,CAHF,CAAb,EAUA7D,CAAS,CAAG8D,CAAK,CAACD,CAAD,CAClB,CACF,CAED,MAAO5D,CAAAA,CACR,C","sourcesContent":["/**\n * Functions for string matching used by the other methods.\n *\n * This code originaly is from the approx-string-match project (https://github.com/robertknight/approx-string-match-js)\n * by Robert Knight wich is released under the MIT License (https://opensource.org/licenses/MIT).\n */\n\n/**\n * Represents a match returned by a call to `search`.\n * @param {string} s - Document text to search\n * @return {string}\n */\n function reverse(s) {\n return s.split(\"\").reverse().join(\"\");\n }\n\n /**\n * Given the ends of approximate matches for `pattern` in `text`, find\n * the start of the matches.\n *\n * @param {string} text\n * @param {string} pattern\n * @param {array} matches\n * @return {obj} Matches with the `start` property set.\n */\n function findMatchStarts(text, pattern, matches) {\n const patRev = reverse(pattern);\n\n return matches.map((m) => {\n // Find start of each match by reversing the pattern and matching segment\n // of text and searching for an approx match with the same number of\n // errors.\n const minStart = Math.max(0, m.end - pattern.length - m.errors);\n const textRev = reverse(text.slice(minStart, m.end));\n\n // If there are multiple possible start points, choose the one that\n // maximizes the length of the match.\n const start = findMatchEnds(textRev, patRev, m.errors).reduce((min, rm) => {\n if (m.end - rm.end < min) {\n return m.end - rm.end;\n }\n return min;\n }, m.end);\n\n return {\n start,\n end: m.end,\n errors: m.errors,\n };\n });\n }\n\n /**\n * Internal context used when calculating blocks of a column.\n */\n // interface Context {\n // /**\n // * Bit-arrays of positive vertical deltas.\n // *\n // * ie. `P[b][i]` is set if the vertical delta for the i'th row in the b'th\n // * block is positive.\n // */\n // P: Uint32Array;\n // /** Bit-arrays of negative vertical deltas. */\n // M: Uint32Array;\n // /** Bit masks with a single bit set indicating the last row in each block. */\n // lastRowMask: Uint32Array;\n // }\n\n /**\n * Return 1 if a number is non-zero or zero otherwise, without using\n * conditional operators.\n *\n * This should get inlined into `advanceBlock` below by the JIT.\n *\n * Adapted from https://stackoverflow.com/a/3912218/434243\n * @param {int} n\n * @return {bool}\n */\n function oneIfNotZero(n) {\n return ((n | -n) >> 31) & 1;\n }\n\n /**\n * Block calculation step of the algorithm.\n *\n * From Fig 8. on p. 408 of [1], additionally optimized to replace conditional\n * checks with bitwise operations as per Section 4.2.3 of [2].\n *\n * @param {obj} ctx - The pattern context object\n * @param {array} peq - The `peq` array for the current character (`ctx.peq.get(ch)`)\n * @param {int} b - The block level\n * @param {obj} hIn - Horizontal input delta ∈ {1,0,-1}\n * @return {obj} Horizontal output delta ∈ {1,0,-1}\n */\n function advanceBlock(ctx, peq, b, hIn) {\n let pV = ctx.P[b];\n let mV = ctx.M[b];\n const hInIsNegative = hIn >>> 31; // 1 if hIn < 0 or 0 otherwise.\n const eq = peq[b] | hInIsNegative;\n\n // Step 1: Compute horizontal deltas.\n const xV = eq | mV;\n const xH = (((eq & pV) + pV) ^ pV) | eq;\n\n let pH = mV | ~(xH | pV);\n let mH = pV & xH;\n\n // Step 2: Update score (value of last row of this block).\n const hOut =\n oneIfNotZero(pH & ctx.lastRowMask[b]) -\n oneIfNotZero(mH & ctx.lastRowMask[b]);\n\n // Step 3: Update vertical deltas for use when processing next char.\n pH <<= 1;\n mH <<= 1;\n\n mH |= hInIsNegative;\n pH |= oneIfNotZero(hIn) - hInIsNegative; // Set pH[0] if hIn > 0.\n\n pV = mH | ~(xV | pH);\n mV = pH & xV;\n\n ctx.P[b] = pV;\n ctx.M[b] = mV;\n\n return hOut;\n }\n\n /**\n * Find the ends and error counts for matches of `pattern` in `text`.\n *\n * Only the matches with the lowest error count are reported. Other matches\n * with error counts <= maxErrors are discarded.\n *\n * This is the block-based search algorithm from Fig. 9 on p.410 of [1].\n *\n * @param {string} text\n * @param {string} pattern\n * @param {array} maxErrors\n * @return {obj} Matches with the `start` property set.\n */\n function findMatchEnds(text, pattern, maxErrors) {\n if (pattern.length === 0) {\n return [];\n }\n\n // Clamp error count so we can rely on the `maxErrors` and `pattern.length`\n // rows being in the same block below.\n maxErrors = Math.min(maxErrors, pattern.length);\n\n const matches = [];\n\n // Word size.\n const w = 32;\n\n // Index of maximum block level.\n const bMax = Math.ceil(pattern.length / w) - 1;\n\n // Context used across block calculations.\n const ctx = {\n P: new Uint32Array(bMax + 1),\n M: new Uint32Array(bMax + 1),\n lastRowMask: new Uint32Array(bMax + 1),\n };\n ctx.lastRowMask.fill(1 << 31);\n ctx.lastRowMask[bMax] = 1 << (pattern.length - 1) % w;\n\n // Dummy \"peq\" array for chars in the text which do not occur in the pattern.\n const emptyPeq = new Uint32Array(bMax + 1);\n\n // Map of UTF-16 character code to bit vector indicating positions in the\n // pattern that equal that character.\n const peq = new Map();\n\n // Version of `peq` that only stores mappings for small characters. This\n // allows faster lookups when iterating through the text because a simple\n // array lookup can be done instead of a hash table lookup.\n const asciiPeq = [];\n for (let i = 0; i < 256; i++) {\n asciiPeq.push(emptyPeq);\n }\n\n // Calculate `ctx.peq` - a map of character values to bitmasks indicating\n // positions of that character within the pattern, where each bit represents\n // a position in the pattern.\n for (let c = 0; c < pattern.length; c += 1) {\n const val = pattern.charCodeAt(c);\n if (peq.has(val)) {\n // Duplicate char in pattern.\n continue;\n }\n\n const charPeq = new Uint32Array(bMax + 1);\n peq.set(val, charPeq);\n if (val < asciiPeq.length) {\n asciiPeq[val] = charPeq;\n }\n\n for (let b = 0; b <= bMax; b += 1) {\n charPeq[b] = 0;\n\n // Set all the bits where the pattern matches the current char (ch).\n // For indexes beyond the end of the pattern, always set the bit as if the\n // pattern contained a wildcard char in that position.\n for (let r = 0; r < w; r += 1) {\n const idx = b * w + r;\n if (idx >= pattern.length) {\n continue;\n }\n\n const match = pattern.charCodeAt(idx) === val;\n if (match) {\n charPeq[b] |= 1 << r;\n }\n }\n }\n }\n\n // Index of last-active block level in the column.\n let y = Math.max(0, Math.ceil(maxErrors / w) - 1);\n\n // Initialize maximum error count at bottom of each block.\n const score = new Uint32Array(bMax + 1);\n for (let b = 0; b <= y; b += 1) {\n score[b] = (b + 1) * w;\n }\n score[bMax] = pattern.length;\n\n // Initialize vertical deltas for each block.\n for (let b = 0; b <= y; b += 1) {\n ctx.P[b] = ~0;\n ctx.M[b] = 0;\n }\n\n // Process each char of the text, computing the error count for `w` chars of\n // the pattern at a time.\n for (let j = 0; j < text.length; j += 1) {\n // Lookup the bitmask representing the positions of the current char from\n // the text within the pattern.\n const charCode = text.charCodeAt(j);\n let charPeq;\n\n if (charCode < asciiPeq.length) {\n // Fast array lookup.\n charPeq = asciiPeq[charCode];\n } else {\n // Slower hash table lookup.\n charPeq = peq.get(charCode);\n if (typeof charPeq === \"undefined\") {\n charPeq = emptyPeq;\n }\n }\n\n // Calculate error count for blocks that we definitely have to process for\n // this column.\n let carry = 0;\n for (let b = 0; b <= y; b += 1) {\n carry = advanceBlock(ctx, charPeq, b, carry);\n score[b] += carry;\n }\n\n // Check if we also need to compute an additional block, or if we can reduce\n // the number of blocks processed for the next column.\n if (\n score[y] - carry <= maxErrors &&\n y < bMax &&\n (charPeq[y + 1] & 1 || carry < 0)\n ) {\n // Error count for bottom block is under threshold, increase the number of\n // blocks processed for this column & next by 1.\n y += 1;\n\n ctx.P[y] = ~0;\n ctx.M[y] = 0;\n\n let maxBlockScore;\n if (y === bMax) {\n const remainder = pattern.length % w;\n maxBlockScore = remainder === 0 ? w : remainder;\n } else {\n maxBlockScore = w;\n }\n\n score[y] =\n score[y - 1] +\n maxBlockScore -\n carry +\n advanceBlock(ctx, charPeq, y, carry);\n } else {\n // Error count for bottom block exceeds threshold, reduce the number of\n // blocks processed for the next column.\n while (y > 0 && score[y] >= maxErrors + w) {\n y -= 1;\n }\n }\n\n // If error count is under threshold, report a match.\n if (y === bMax && score[y] <= maxErrors) {\n if (score[y] < maxErrors) {\n // Discard any earlier, worse matches.\n matches.splice(0, matches.length);\n }\n\n matches.push({\n start: -1,\n end: j + 1,\n errors: score[y],\n });\n\n // Because `search` only reports the matches with the lowest error count,\n // we can \"ratchet down\" the max error threshold whenever a match is\n // encountered and thereby save a small amount of work for the remainder\n // of the text.\n maxErrors = score[y];\n }\n }\n\n return matches;\n }\n\n /**\n * Search for matches for `pattern` in `text` allowing up to `maxErrors` errors.\n *\n * Returns the start, and end positions and error counts for each lowest-cost\n * match. Only the \"best\" matches are returned.\n * @param {string} text\n * @param {string} pattern\n * @param {array} maxErrors\n * @return {obj} Matches with the `start` property set.\n */\n export default function search(\n text,\n pattern,\n maxErrors\n ) {\n const matches = findMatchEnds(text, pattern, maxErrors);\n return findMatchStarts(text, pattern, matches);\n }"],"file":"string-match.min.js"} \ No newline at end of file diff --git a/amd/build/text-range.min.js b/amd/build/text-range.min.js index 5c6929d..8dc1810 100644 --- a/amd/build/text-range.min.js +++ b/amd/build/text-range.min.js @@ -1,3 +1,2 @@ -define("mod_margic/text-range",["exports"],(function(_exports){function _slicedToArray(arr,i){return function(arr){if(Array.isArray(arr))return arr}(arr)||function(arr,i){var _i=null==arr?null:"undefined"!=typeof Symbol&&arr[Symbol.iterator]||arr["@@iterator"];if(null==_i)return;var _s,_e,_arr=[],_n=!0,_d=!1;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done)&&(_arr.push(_s.value),!i||_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{_n||null==_i.return||_i.return()}finally{if(_d)throw _e}}return _arr}(arr,i)||function(o,minLen){if(!o)return;if("string"==typeof o)return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(o);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}(arr,i)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i1?_len-1:0),_key=1;_key<_len;_key++)offsets[_key-1]=arguments[_key];for(var textNode,nextOffset=offsets.shift(),nodeIter=element.ownerDocument.createNodeIterator(element,NodeFilter.SHOW_TEXT),results=[],currentNode=nodeIter.nextNode(),length=0;void 0!==nextOffset&¤tNode;)length+(textNode=currentNode).data.length>nextOffset?(results.push({node:textNode,offset:nextOffset-length}),nextOffset=offsets.shift()):(currentNode=nodeIter.nextNode(),length+=textNode.data.length);for(;void 0!==nextOffset&&length===nextOffset;)results.push({node:textNode,offset:textNode.data.length}),nextOffset=offsets.shift();if(void 0!==nextOffset)throw new RangeError("Offset exceeds text length");return results}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.TextRange=_exports.TextPosition=_exports.RESOLVE_FORWARDS=_exports.RESOLVE_BACKWARDS=void 0;_exports.RESOLVE_FORWARDS=1;_exports.RESOLVE_BACKWARDS=2;var TextPosition=function(){function TextPosition(element,offset){if(_classCallCheck(this,TextPosition),offset<0)throw new Error("Offset is invalid");this.element=element,this.offset=offset}return _createClass(TextPosition,[{key:"relativeTo",value:function(parent){if(!parent.contains(this.element))throw new Error("Parent is not an ancestor of current element");for(var el=this.element,offset=this.offset;el!==parent;)offset+=previousSiblingsTextLength(el),el=el.parentElement;return new TextPosition(el,offset)}},{key:"resolve",value:function(){var options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};try{return resolveOffsets(this.element,this.offset)[0]}catch(err){if(0===this.offset&&void 0!==options.direction){var tw=document.createTreeWalker(this.element.getRootNode(),NodeFilter.SHOW_TEXT);tw.currentNode=this.element;var forwards=1===options.direction,text=forwards?tw.nextNode():tw.previousNode();if(!text)throw err;return{node:text,offset:forwards?0:text.data.length}}throw err}}}],[{key:"fromCharOffset",value:function(node,offset){switch(node.nodeType){case Node.TEXT_NODE:return TextPosition.fromPoint(node,offset);case Node.ELEMENT_NODE:return new TextPosition(node,offset);default:throw new Error("Node is not an element or text node")}}},{key:"fromPoint",value:function(node,offset){switch(node.nodeType){case Node.TEXT_NODE:if(offset<0||offset>node.data.length)throw new Error("Text node offset is out of range");if(!node.parentElement)throw new Error("Text node has no parent");var textOffset=previousSiblingsTextLength(node)+offset;return new TextPosition(node.parentElement,textOffset);case Node.ELEMENT_NODE:if(offset<0||offset>node.childNodes.length)throw new Error("Child node offset is out of range");for(var _textOffset=0,i=0;ia.length)b=a.length;for(var c=0,d=Array(b);ce){g.push({node:i,offset:e-j});e=c.shift()}else{h=f.nextNode();j+=i.data.length}}while(e!==void 0&&j===e){g.push({node:i,offset:i.data.length});e=c.shift()}if(e!==void 0){throw new RangeError("Offset exceeds text length")}return g}a.RESOLVE_FORWARDS=1;a.RESOLVE_BACKWARDS=2;var n=function(){function a(b,c){h(this,a);if(0>c){throw new Error("Offset is invalid")}this.element=b;this.offset=c}j(a,[{key:"relativeTo",value:function relativeTo(b){if(!b.contains(this.element)){throw new Error("Parent is not an ancestor of current element")}var c=this.element,d=this.offset;while(c!==b){d+=l(c);c=c.parentElement}return new a(c,d)}},{key:"resolve",value:function resolve(){var a=0c||c>b.data.length){throw new Error("Text node offset is out of range")}if(!b.parentElement){throw new Error("Text node has no parent")}var f=l(b)+c;return new a(b.parentElement,f)}case Node.ELEMENT_NODE:{if(0>c||c>b.childNodes.length){throw new Error("Child node offset is out of range")}for(var d=0,e=0;e nextOffset) {\n results.push({node: textNode, offset: nextOffset - length});\n nextOffset = offsets.shift();\n } else {\n currentNode = nodeIter.nextNode();\n length += textNode.data.length;\n }\n }\n\n // Boundary case.\n while (nextOffset !== undefined && length === nextOffset) {\n results.push({node: textNode, offset: textNode.data.length});\n nextOffset = offsets.shift();\n }\n\n if (nextOffset !== undefined) {\n throw new RangeError('Offset exceeds text length');\n }\n\n return results;\n}\n\nexport let RESOLVE_FORWARDS = 1;\nexport let RESOLVE_BACKWARDS = 2;\n\n/**\n * Represents an offset within the text content of an element.\n *\n * This position can be resolved to a specific descendant node in the current\n * DOM subtree of the element using the `resolve` method.\n */\nexport class TextPosition {\n /**\n * Construct a `TextPosition` that refers to the text position `offset` within\n * the text content of `element`.\n *\n * @param {Element} element\n * @param {number} offset\n */\n constructor(element, offset) {\n if (offset < 0) {\n throw new Error('Offset is invalid');\n }\n\n /** Element that `offset` is relative to. */\n this.element = element;\n\n /** Character offset from the start of the element's `textContent`. */\n this.offset = offset;\n }\n\n /**\n * Return a copy of this position with offset relative to a given ancestor\n * element.\n *\n * @param {Element} parent - Ancestor of `this.element`\n * @return {TextPosition}\n */\n relativeTo(parent) {\n if (!parent.contains(this.element)) {\n throw new Error('Parent is not an ancestor of current element');\n }\n\n let el = this.element;\n let offset = this.offset;\n while (el !== parent) {\n offset += previousSiblingsTextLength(el);\n el = /** @type {Element} */ (el.parentElement);\n }\n\n return new TextPosition(el, offset);\n }\n\n /**\n * Resolve the position to a specific text node and offset within that node.\n *\n * Throws if `this.offset` exceeds the length of the element's text. In the\n * case where the element has no text and `this.offset` is 0, the `direction`\n * option determines what happens.\n *\n * Offsets at the boundary between two nodes are resolved to the start of the\n * node that begins at the boundary.\n *\n * @param {Object} [options]\n * @param {RESOLVE_FORWARDS|RESOLVE_BACKWARDS} [options.direction] -\n * Specifies in which direction to search for the nearest text node if\n * `this.offset` is `0` and `this.element` has no text. If not specified\n * an error is thrown.\n * @return {{ node: Text, offset: number }}\n * @throws {RangeError}\n */\n resolve(options = {}) {\n try {\n return resolveOffsets(this.element, this.offset)[0];\n } catch (err) {\n if (this.offset === 0 && options.direction !== undefined) {\n const tw = document.createTreeWalker(\n this.element.getRootNode(),\n NodeFilter.SHOW_TEXT\n );\n tw.currentNode = this.element;\n const forwards = options.direction === RESOLVE_FORWARDS;\n const text = /** @type {Text|null} */ (\n forwards ? tw.nextNode() : tw.previousNode()\n );\n if (!text) {\n throw err;\n }\n return {node: text, offset: forwards ? 0 : text.data.length};\n } else {\n throw err;\n }\n }\n }\n\n /**\n * Construct a `TextPosition` that refers to the `offset`th character within\n * `node`.\n *\n * @param {Node} node\n * @param {number} offset\n * @return {TextPosition}\n */\n static fromCharOffset(node, offset) {\n switch (node.nodeType) {\n case Node.TEXT_NODE:\n return TextPosition.fromPoint(node, offset);\n case Node.ELEMENT_NODE:\n return new TextPosition(/** @type {Element} */ (node), offset);\n default:\n throw new Error('Node is not an element or text node');\n }\n }\n\n /**\n * Construct a `TextPosition` representing the range start or end point (node, offset).\n *\n * @param {Node} node - Text or Element node\n * @param {number} offset - Offset within the node.\n * @return {TextPosition}\n */\n static fromPoint(node, offset) {\n\n switch (node.nodeType) {\n case Node.TEXT_NODE: {\n if (offset < 0 || offset > /** @type {Text} */ (node).data.length) {\n throw new Error('Text node offset is out of range');\n }\n\n if (!node.parentElement) {\n throw new Error('Text node has no parent');\n }\n\n // Get the offset from the start of the parent element.\n const textOffset = previousSiblingsTextLength(node) + offset;\n\n return new TextPosition(node.parentElement, textOffset);\n }\n case Node.ELEMENT_NODE: {\n if (offset < 0 || offset > node.childNodes.length) {\n throw new Error('Child node offset is out of range');\n }\n\n // Get the text length before the `offset`th child of element.\n let textOffset = 0;\n for (let i = 0; i < offset; i++) {\n textOffset += nodeTextLength(node.childNodes[i]);\n }\n\n return new TextPosition(/** @type {Element} */ (node), textOffset);\n }\n default:\n throw new Error('Point is not in an element or text node');\n }\n }\n}\n\n/**\n * Represents a region of a document as a (start, end) pair of `TextPosition` points.\n *\n * Representing a range in this way allows for changes in the DOM content of the\n * range which don't affect its text content, without affecting the text content\n * of the range itself.\n */\nexport class TextRange {\n /**\n * Construct an immutable `TextRange` from a `start` and `end` point.\n *\n * @param {TextPosition} start\n * @param {TextPosition} end\n */\n constructor(start, end) {\n this.start = start;\n this.end = end;\n }\n\n /**\n * Return a copy of this range with start and end positions relative to a\n * given ancestor. See `TextPosition.relativeTo`.\n *\n * @param {Element} element\n * @return {Range}\n */\n relativeTo(element) {\n return new TextRange(\n this.start.relativeTo(element),\n this.end.relativeTo(element)\n );\n }\n\n /**\n * Resolve the `TextRange` to a DOM range.\n *\n * The resulting DOM Range will always start and end in a `Text` node.\n * Hence `TextRange.fromRange(range).toRange()` can be used to \"shrink\" a\n * range to the text it contains.\n *\n * May throw if the `start` or `end` positions cannot be resolved to a range.\n *\n * @return {Range}\n */\n toRange() {\n let start;\n let end;\n\n if (\n this.start.element === this.end.element &&\n this.start.offset <= this.end.offset\n ) {\n // Fast path for start and end points in same element.\n [start, end] = resolveOffsets(\n this.start.element,\n this.start.offset,\n this.end.offset\n );\n } else {\n start = this.start.resolve({direction: RESOLVE_FORWARDS});\n end = this.end.resolve({direction: RESOLVE_BACKWARDS});\n }\n\n const range = new Range();\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n return range;\n }\n\n /**\n * Convert an existing DOM `Range` to a `TextRange`\n *\n * @param {Range} range\n * @return {TextRange}\n */\n static fromRange(range) {\n const start = TextPosition.fromPoint(\n range.startContainer,\n range.startOffset\n );\n const end = TextPosition.fromPoint(range.endContainer, range.endOffset);\n return new TextRange(start, end);\n }\n\n /**\n * Return a `TextRange` from the `start`th to `end`th characters in `root`.\n *\n * @param {Element} root\n * @param {number} start\n * @param {number} end\n * @return {Range}\n */\n static fromOffsets(root, start, end) {\n return new TextRange(\n new TextPosition(root, start),\n new TextPosition(root, end)\n );\n }\n}\n"],"names":["nodeTextLength","node","nodeType","Node","ELEMENT_NODE","TEXT_NODE","textContent","length","previousSiblingsTextLength","sibling","previousSibling","resolveOffsets","element","offsets","textNode","nextOffset","shift","nodeIter","ownerDocument","createNodeIterator","NodeFilter","SHOW_TEXT","results","currentNode","nextNode","undefined","data","push","offset","RangeError","TextPosition","Error","parent","contains","this","el","parentElement","options","err","direction","tw","document","createTreeWalker","getRootNode","forwards","text","previousNode","fromPoint","textOffset","childNodes","i","TextRange","start","end","relativeTo","resolve","range","Range","setStart","setEnd","startContainer","startOffset","endContainer","endOffset","root"],"mappings":"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"} \ No newline at end of file +{"version":3,"sources":["../src/text-range.js"],"names":["nodeTextLength","node","nodeType","Node","ELEMENT_NODE","TEXT_NODE","textContent","length","previousSiblingsTextLength","sibling","previousSibling","resolveOffsets","element","offsets","nextOffset","shift","nodeIter","ownerDocument","createNodeIterator","NodeFilter","SHOW_TEXT","results","currentNode","nextNode","textNode","data","push","offset","RangeError","TextPosition","Error","parent","contains","el","parentElement","options","err","direction","tw","document","createTreeWalker","getRootNode","forwards","text","previousNode","fromPoint","textOffset","childNodes","i","TextRange","start","end","relativeTo","resolve","range","Range","setStart","setEnd","startContainer","startOffset","endContainer","endOffset","root"],"mappings":"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","sourcesContent":["/**\n * Functions for handling text-ranges used by the other methods.\n *\n * This code originaly is from the Hypothesis project (https://github.com/hypothesis/client)\n * which is released under the 2-Clause BSD License (https://opensource.org/licenses/BSD-2-Clause),\n * sometimes referred to as the \"Simplified BSD License\".\n */\n\n/**\n * Return the combined length of text nodes contained in `node`.\n *\n * @param {Node} node\n * @return {string}\n */\nfunction nodeTextLength(node) {\n switch (node.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.TEXT_NODE:\n // Nb. `textContent` excludes text in comments and processing instructions\n // when called on a parent element, so we don't need to subtract that here.\n\n return /** @type {string} */ (node.textContent).length;\n default:\n return 0;\n }\n}\n\n/**\n * Return the total length of the text of all previous siblings of `node`.\n *\n * @param {Node} node\n * @return {int}\n */\nfunction previousSiblingsTextLength(node) {\n let sibling = node.previousSibling;\n let length = 0;\n\n while (sibling) {\n length += nodeTextLength(sibling);\n sibling = sibling.previousSibling;\n }\n\n return length;\n}\n\n/**\n * Resolve one or more character offsets within an element to (text node, position)\n * pairs.\n *\n * @param {Element} element\n * @param {number[]} offsets - Offsets, which must be sorted in ascending order\n * @return {{ node: Text, offset: number }[]}\n */\nfunction resolveOffsets(element, ...offsets) {\n\n let nextOffset = offsets.shift();\n const nodeIter = /** @type {Document} */ (\n element.ownerDocument\n ).createNodeIterator(element, NodeFilter.SHOW_TEXT);\n const results = [];\n\n let currentNode = nodeIter.nextNode();\n let textNode;\n let length = 0;\n\n // Find the text node containing the `nextOffset`th character from the start\n // of `element`.\n while (nextOffset !== undefined && currentNode) {\n textNode = /** @type {Text} */ (currentNode);\n\n if (length + textNode.data.length > nextOffset) {\n results.push({node: textNode, offset: nextOffset - length});\n nextOffset = offsets.shift();\n } else {\n currentNode = nodeIter.nextNode();\n length += textNode.data.length;\n }\n }\n\n // Boundary case.\n while (nextOffset !== undefined && length === nextOffset) {\n results.push({node: textNode, offset: textNode.data.length});\n nextOffset = offsets.shift();\n }\n\n if (nextOffset !== undefined) {\n throw new RangeError('Offset exceeds text length');\n }\n\n return results;\n}\n\nexport let RESOLVE_FORWARDS = 1;\nexport let RESOLVE_BACKWARDS = 2;\n\n/**\n * Represents an offset within the text content of an element.\n *\n * This position can be resolved to a specific descendant node in the current\n * DOM subtree of the element using the `resolve` method.\n */\nexport class TextPosition {\n /**\n * Construct a `TextPosition` that refers to the text position `offset` within\n * the text content of `element`.\n *\n * @param {Element} element\n * @param {number} offset\n */\n constructor(element, offset) {\n if (offset < 0) {\n throw new Error('Offset is invalid');\n }\n\n /** Element that `offset` is relative to. */\n this.element = element;\n\n /** Character offset from the start of the element's `textContent`. */\n this.offset = offset;\n }\n\n /**\n * Return a copy of this position with offset relative to a given ancestor\n * element.\n *\n * @param {Element} parent - Ancestor of `this.element`\n * @return {TextPosition}\n */\n relativeTo(parent) {\n if (!parent.contains(this.element)) {\n throw new Error('Parent is not an ancestor of current element');\n }\n\n let el = this.element;\n let offset = this.offset;\n while (el !== parent) {\n offset += previousSiblingsTextLength(el);\n el = /** @type {Element} */ (el.parentElement);\n }\n\n return new TextPosition(el, offset);\n }\n\n /**\n * Resolve the position to a specific text node and offset within that node.\n *\n * Throws if `this.offset` exceeds the length of the element's text. In the\n * case where the element has no text and `this.offset` is 0, the `direction`\n * option determines what happens.\n *\n * Offsets at the boundary between two nodes are resolved to the start of the\n * node that begins at the boundary.\n *\n * @param {Object} [options]\n * @param {RESOLVE_FORWARDS|RESOLVE_BACKWARDS} [options.direction] -\n * Specifies in which direction to search for the nearest text node if\n * `this.offset` is `0` and `this.element` has no text. If not specified\n * an error is thrown.\n * @return {{ node: Text, offset: number }}\n * @throws {RangeError}\n */\n resolve(options = {}) {\n try {\n return resolveOffsets(this.element, this.offset)[0];\n } catch (err) {\n if (this.offset === 0 && options.direction !== undefined) {\n const tw = document.createTreeWalker(\n this.element.getRootNode(),\n NodeFilter.SHOW_TEXT\n );\n tw.currentNode = this.element;\n const forwards = options.direction === RESOLVE_FORWARDS;\n const text = /** @type {Text|null} */ (\n forwards ? tw.nextNode() : tw.previousNode()\n );\n if (!text) {\n throw err;\n }\n return {node: text, offset: forwards ? 0 : text.data.length};\n } else {\n throw err;\n }\n }\n }\n\n /**\n * Construct a `TextPosition` that refers to the `offset`th character within\n * `node`.\n *\n * @param {Node} node\n * @param {number} offset\n * @return {TextPosition}\n */\n static fromCharOffset(node, offset) {\n switch (node.nodeType) {\n case Node.TEXT_NODE:\n return TextPosition.fromPoint(node, offset);\n case Node.ELEMENT_NODE:\n return new TextPosition(/** @type {Element} */ (node), offset);\n default:\n throw new Error('Node is not an element or text node');\n }\n }\n\n /**\n * Construct a `TextPosition` representing the range start or end point (node, offset).\n *\n * @param {Node} node - Text or Element node\n * @param {number} offset - Offset within the node.\n * @return {TextPosition}\n */\n static fromPoint(node, offset) {\n\n switch (node.nodeType) {\n case Node.TEXT_NODE: {\n if (offset < 0 || offset > /** @type {Text} */ (node).data.length) {\n throw new Error('Text node offset is out of range');\n }\n\n if (!node.parentElement) {\n throw new Error('Text node has no parent');\n }\n\n // Get the offset from the start of the parent element.\n const textOffset = previousSiblingsTextLength(node) + offset;\n\n return new TextPosition(node.parentElement, textOffset);\n }\n case Node.ELEMENT_NODE: {\n if (offset < 0 || offset > node.childNodes.length) {\n throw new Error('Child node offset is out of range');\n }\n\n // Get the text length before the `offset`th child of element.\n let textOffset = 0;\n for (let i = 0; i < offset; i++) {\n textOffset += nodeTextLength(node.childNodes[i]);\n }\n\n return new TextPosition(/** @type {Element} */ (node), textOffset);\n }\n default:\n throw new Error('Point is not in an element or text node');\n }\n }\n}\n\n/**\n * Represents a region of a document as a (start, end) pair of `TextPosition` points.\n *\n * Representing a range in this way allows for changes in the DOM content of the\n * range which don't affect its text content, without affecting the text content\n * of the range itself.\n */\nexport class TextRange {\n /**\n * Construct an immutable `TextRange` from a `start` and `end` point.\n *\n * @param {TextPosition} start\n * @param {TextPosition} end\n */\n constructor(start, end) {\n this.start = start;\n this.end = end;\n }\n\n /**\n * Return a copy of this range with start and end positions relative to a\n * given ancestor. See `TextPosition.relativeTo`.\n *\n * @param {Element} element\n * @return {Range}\n */\n relativeTo(element) {\n return new TextRange(\n this.start.relativeTo(element),\n this.end.relativeTo(element)\n );\n }\n\n /**\n * Resolve the `TextRange` to a DOM range.\n *\n * The resulting DOM Range will always start and end in a `Text` node.\n * Hence `TextRange.fromRange(range).toRange()` can be used to \"shrink\" a\n * range to the text it contains.\n *\n * May throw if the `start` or `end` positions cannot be resolved to a range.\n *\n * @return {Range}\n */\n toRange() {\n let start;\n let end;\n\n if (\n this.start.element === this.end.element &&\n this.start.offset <= this.end.offset\n ) {\n // Fast path for start and end points in same element.\n [start, end] = resolveOffsets(\n this.start.element,\n this.start.offset,\n this.end.offset\n );\n } else {\n start = this.start.resolve({direction: RESOLVE_FORWARDS});\n end = this.end.resolve({direction: RESOLVE_BACKWARDS});\n }\n\n const range = new Range();\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n return range;\n }\n\n /**\n * Convert an existing DOM `Range` to a `TextRange`\n *\n * @param {Range} range\n * @return {TextRange}\n */\n static fromRange(range) {\n const start = TextPosition.fromPoint(\n range.startContainer,\n range.startOffset\n );\n const end = TextPosition.fromPoint(range.endContainer, range.endOffset);\n return new TextRange(start, end);\n }\n\n /**\n * Return a `TextRange` from the `start`th to `end`th characters in `root`.\n *\n * @param {Element} root\n * @param {number} start\n * @param {number} end\n * @return {Range}\n */\n static fromOffsets(root, start, end) {\n return new TextRange(\n new TextPosition(root, start),\n new TextPosition(root, end)\n );\n }\n}\n"],"file":"text-range.min.js"} \ No newline at end of file diff --git a/amd/build/types.min.js b/amd/build/types.min.js index 8fb957e..aeaaedf 100644 --- a/amd/build/types.min.js +++ b/amd/build/types.min.js @@ -1,3 +1,2 @@ -define("mod_margic/types",["exports","./match-quote","./text-range","./xpath"],(function(_exports,_matchQuote,_textRange,_xpath){function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter((function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable}))),keys.push.apply(keys,symbols)}return keys}function _objectSpread(target){for(var i=1;i2&&void 0!==arguments[2]?arguments[2]:{};_classCallCheck(this,TextQuoteAnchor),this.root=root,this.exact=exact,this.context=context}return _createClass(TextQuoteAnchor,[{key:"toSelector",value:function(){return{type:"TextQuoteSelector",exact:this.exact,prefix:this.context.prefix,suffix:this.context.suffix}}},{key:"toRange",value:function(){var options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.toPositionAnchor(options).toRange()}},{key:"toPositionAnchor",value:function(){var options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},text=this.root.textContent,match=(0,_matchQuote.matchQuote)(text,this.exact,_objectSpread(_objectSpread({},this.context),{},{hint:options.hint}));if(!match)throw new Error("Quote not found");return new TextPositionAnchor(this.root,match.start,match.end)}}],[{key:"fromRange",value:function(root,range){var text=root.textContent,textRange=_textRange.TextRange.fromRange(range).relativeTo(root),start=textRange.start.offset,end=textRange.end.offset;return new TextQuoteAnchor(root,text.slice(start,end),{prefix:text.slice(Math.max(0,start-32),start),suffix:text.slice(end,Math.min(text.length,end+32))})}},{key:"fromSelector",value:function(root,selector){var prefix=selector.prefix,suffix=selector.suffix;return new TextQuoteAnchor(root,selector.exact,{prefix:prefix,suffix:suffix})}}]),TextQuoteAnchor}();_exports.TextQuoteAnchor=TextQuoteAnchor})); - -//# sourceMappingURL=types.min.js.map \ No newline at end of file +define ("mod_margic/types",["exports","./match-quote","./text-range","./xpath"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.TextQuoteAnchor=a.TextPositionAnchor=a.RangeAnchor=void 0;function e(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);if(b)d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable});c.push.apply(c,d)}return c}function f(a){for(var b=1,c;b=o.length?{done:!0}:{done:!1,value:o[i++]}},e:function(_e){throw _e},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var err,normalCompletion=!0,didErr=!1;return{s:function(){it=it.call(o)},n:function(){var step=it.next();return normalCompletion=step.done,step},e:function(_e2){didErr=!0,err=_e2},f:function(){try{normalCompletion||null==it.return||it.return()}finally{if(didErr)throw err}}}}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i1&&void 0!==arguments[1]?arguments[1]:document.body;try{return evaluateSimpleXPath(xpath,root)}catch(err){return document.evaluate("."+xpath,root,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}},_exports.xpathFromNode=function(node,root){var xpath="",elem=node;for(;elem!==root;){if(!elem)throw new Error("Node is not a descendant of root");xpath=getPathSegment(elem)+"/"+xpath,elem=elem.parentNode}return xpath=(xpath="/"+xpath).replace(/\/$/,"")}})); - -//# sourceMappingURL=xpath.min.js.map \ No newline at end of file +define ("mod_margic/xpath",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.xpathFromNode=function(a,b){var c="",d=a;while(d!==b){if(!d){throw new Error("Node is not a descendant of root")}c=g(d)+"/"+c;d=d.parentNode}c="/"+c;c=c.replace(/\/$/,"");return c};a.nodeFromXPath=function(a){var b=1=a.length)return{done:!0};return{done:!1,value:a[b++]}},e:function e(a){throw a},f:d}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var e,f=!0,g=!1,h;return{s:function s(){e=a[Symbol.iterator]()},n:function n(){var a=e.next();f=a.done;return a},e:function e(a){g=!0;h=a},f:function f(){try{if(!f&&null!=e.return)e.return()}finally{if(g)throw h}}}}function c(a,b){if(!a)return;if("string"==typeof a)return d(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return d(a,b)}function d(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);cl){return null}}else{k=j;l=0}var o=h(f,k,l);if(!o){return null}f=o}}catch(a){g.e(a)}finally{g.f()}return f}}); +//# sourceMappingURL=xpath.min.js.map diff --git a/amd/build/xpath.min.js.map b/amd/build/xpath.min.js.map index 2b3207f..f81002d 100644 --- a/amd/build/xpath.min.js.map +++ b/amd/build/xpath.min.js.map @@ -1 +1 @@ -{"version":3,"file":"xpath.min.js","sources":["../src/xpath.js"],"sourcesContent":["/**\n * XPATH and DOM functions used for anchoring and highlighting.\n *\n * This code originaly is from the Hypothesis project (https://github.com/hypothesis/client)\n * which is released under the 2-Clause BSD License (https://opensource.org/licenses/BSD-2-Clause),\n * sometimes referred to as the \"Simplified BSD License\".\n */\n\n/**\n * Get the node name for use in generating an xpath expression.\n *\n * @param {Node} node\n * @return {string} - Name of the node\n */\nfunction getNodeName(node) {\n const nodeName = node.nodeName.toLowerCase();\n let result = nodeName;\n if (nodeName === '#text') {\n result = 'text()';\n }\n return result;\n}\n\n/**\n * Get the index of the node as it appears in its parent's child list\n *\n * @param {Node} node\n * @return {int} - Position of the node\n */\nfunction getNodePosition(node) {\n let pos = 0;\n /** @type {Node|null} */\n let tmp = node;\n while (tmp) {\n if (tmp.nodeName === node.nodeName) {\n pos += 1;\n }\n tmp = tmp.previousSibling;\n }\n return pos;\n}\n\n/**\n * Get the path segments to the node\n *\n * @param {Node} node\n * @return {array} - Path segments\n */\nfunction getPathSegment(node) {\n const name = getNodeName(node);\n const pos = getNodePosition(node);\n return `${name}[${pos}]`;\n}\n\n/**\n * A simple XPath generator which can generate XPaths of the form\n * /tag[index]/tag[index].\n *\n * @param {Node} node - The node to generate a path to\n * @param {Node} root - Root node to which the returned path is relative\n * @return {string} - The xpath of a node\n */\nexport function xpathFromNode(node, root) {\n let xpath = '';\n\n /** @type {Node|null} */\n let elem = node;\n while (elem !== root) {\n if (!elem) {\n throw new Error('Node is not a descendant of root');\n }\n xpath = getPathSegment(elem) + '/' + xpath;\n elem = elem.parentNode;\n }\n xpath = '/' + xpath;\n xpath = xpath.replace(/\\/$/, ''); // Remove trailing slash\n\n return xpath;\n}\n\n/**\n * Return the `index`'th immediate child of `element` whose tag name is\n * `nodeName` (case insensitive).\n *\n * @param {Element} element\n * @param {string} nodeName\n * @param {number} index\n * @return {Element} - The child element or null\n */\nfunction nthChildOfType(element, nodeName, index) {\n nodeName = nodeName.toUpperCase();\n\n let matchIndex = -1;\n for (let i = 0; i < element.children.length; i++) {\n const child = element.children[i];\n if (child.nodeName.toUpperCase() === nodeName) {\n ++matchIndex;\n if (matchIndex === index) {\n return child;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Evaluate a _simple XPath_ relative to a `root` element and return the\n * matching element.\n *\n * A _simple XPath_ is a sequence of one or more `/tagName[index]` strings.\n *\n * Unlike `document.evaluate` this function:\n *\n * - Only supports simple XPaths\n * - Is not affected by the document's _type_ (HTML or XML/XHTML)\n * - Ignores element namespaces when matching element names in the XPath against\n * elements in the DOM tree\n * - Is case insensitive for all elements, not just HTML elements\n *\n * The matching element is returned or `null` if no such element is found.\n * An error is thrown if `xpath` is not a simple XPath.\n *\n * @param {string} xpath\n * @param {Element} root\n * @return {Element|null}\n */\nfunction evaluateSimpleXPath(xpath, root) {\n const isSimpleXPath =\n xpath.match(/^(\\/[A-Za-z0-9-]+(\\[[0-9]+\\])?)+$/) !== null;\n if (!isSimpleXPath) {\n throw new Error('Expression is not a simple XPath');\n }\n\n const segments = xpath.split('/');\n let element = root;\n\n // Remove leading empty segment. The regex above validates that the XPath\n // has at least two segments, with the first being empty and the others non-empty.\n segments.shift();\n\n for (let segment of segments) {\n let elementName;\n let elementIndex;\n\n const separatorPos = segment.indexOf('[');\n if (separatorPos !== -1) {\n elementName = segment.slice(0, separatorPos);\n\n const indexStr = segment.slice(separatorPos + 1, segment.indexOf(']'));\n elementIndex = parseInt(indexStr) - 1;\n if (elementIndex < 0) {\n return null;\n }\n } else {\n elementName = segment;\n elementIndex = 0;\n }\n\n const child = nthChildOfType(element, elementName, elementIndex);\n if (!child) {\n return null;\n }\n\n element = child;\n }\n\n return element;\n}\n\n/**\n * Finds an element node using an XPath relative to `root`\n *\n * Example:\n * node = nodeFromXPath('/main/article[1]/p[3]', document.body)\n *\n * @param {string} xpath\n * @param {Element} [root]\n * @return {Node|null}\n */\nexport function nodeFromXPath(xpath, root = document.body) {\n try {\n return evaluateSimpleXPath(xpath, root);\n } catch (err) {\n return document.evaluate(\n '.' + xpath,\n root,\n\n // Nb. The `namespaceResolver` and `result` arguments are optional in the spec but required in Edge Legacy.\n null /* NamespaceResolver */,\n XPathResult.FIRST_ORDERED_NODE_TYPE,\n null /* Result */\n ).singleNodeValue;\n }\n}\n"],"names":["getPathSegment","node","name","nodeName","toLowerCase","result","getNodeName","pos","tmp","previousSibling","getNodePosition","nthChildOfType","element","index","toUpperCase","matchIndex","i","children","length","child","evaluateSimpleXPath","xpath","root","match","Error","segments","split","shift","segment","elementName","elementIndex","separatorPos","indexOf","slice","indexStr","parseInt","document","body","err","evaluate","XPathResult","FIRST_ORDERED_NODE_TYPE","singleNodeValue","elem","parentNode","replace"],"mappings":"i0CAgDSA,eAAeC,UAChBC,cAnCaD,UACbE,SAAWF,KAAKE,SAASC,cAC3BC,OAASF,eACI,UAAbA,WACFE,OAAS,UAEJA,OA6BMC,CAAYL,MACnBM,aArBiBN,cACnBM,IAAM,EAENC,IAAMP,KACHO,KACDA,IAAIL,WAAaF,KAAKE,WACxBI,KAAO,GAETC,IAAMA,IAAIC,uBAELF,IAWKG,CAAgBT,sBAClBC,iBAAQK,kBAsCXI,eAAeC,QAAST,SAAUU,OACzCV,SAAWA,SAASW,sBAEhBC,YAAc,EACTC,EAAI,EAAGA,EAAIJ,QAAQK,SAASC,OAAQF,IAAK,KAC1CG,MAAQP,QAAQK,SAASD,MAC3BG,MAAMhB,SAASW,gBAAkBX,YACjCY,aACiBF,aACVM,aAKN,cAwBAC,oBAAoBC,MAAOC,WAEqB,OAArDD,MAAME,MAAM,4CAEN,IAAIC,MAAM,wCAGZC,SAAWJ,MAAMK,MAAM,KACzBd,QAAUU,KAIdG,SAASE,uDAEWF,6DAAU,KAArBG,oBACHC,mBACAC,oBAEEC,aAAeH,QAAQI,QAAQ,SACf,IAAlBD,aAAqB,CACvBF,YAAcD,QAAQK,MAAM,EAAGF,kBAEzBG,SAAWN,QAAQK,MAAMF,aAAe,EAAGH,QAAQI,QAAQ,UACjEF,aAAeK,SAASD,UAAY,GACjB,SACV,UAGTL,YAAcD,QACdE,aAAe,MAGXX,MAAQR,eAAeC,QAASiB,YAAaC,kBAC9CX,aACI,KAGTP,QAAUO,gEAGLP,gGAaqBS,WAAOC,4DAAOc,SAASC,gBAE1CjB,oBAAoBC,MAAOC,MAClC,MAAOgB,YACAF,SAASG,SACd,IAAMlB,MACNC,KAGA,KACAkB,YAAYC,wBACZ,MACAC,kDAlIwBzC,KAAMqB,UAC9BD,MAAQ,GAGRsB,KAAO1C,UACJ0C,OAASrB,MAAM,KACfqB,WACG,IAAInB,MAAM,oCAElBH,MAAQrB,eAAe2C,MAAQ,IAAMtB,MACrCsB,KAAOA,KAAKC,kBAGdvB,OADAA,MAAQ,IAAMA,OACAwB,QAAQ,MAAO"} \ No newline at end of file +{"version":3,"sources":["../src/xpath.js"],"names":["node","root","xpath","elem","Error","getPathSegment","parentNode","replace","document","body","evaluateSimpleXPath","err","evaluate","XPathResult","FIRST_ORDERED_NODE_TYPE","singleNodeValue","getNodeName","nodeName","toLowerCase","result","getNodePosition","pos","tmp","previousSibling","name","nthChildOfType","element","index","toUpperCase","matchIndex","i","child","children","length","isSimpleXPath","match","segments","split","shift","segment","elementName","elementIndex","separatorPos","indexOf","slice","indexStr","parseInt"],"mappings":"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","sourcesContent":["/**\n * XPATH and DOM functions used for anchoring and highlighting.\n *\n * This code originaly is from the Hypothesis project (https://github.com/hypothesis/client)\n * which is released under the 2-Clause BSD License (https://opensource.org/licenses/BSD-2-Clause),\n * sometimes referred to as the \"Simplified BSD License\".\n */\n\n/**\n * Get the node name for use in generating an xpath expression.\n *\n * @param {Node} node\n * @return {string} - Name of the node\n */\nfunction getNodeName(node) {\n const nodeName = node.nodeName.toLowerCase();\n let result = nodeName;\n if (nodeName === '#text') {\n result = 'text()';\n }\n return result;\n}\n\n/**\n * Get the index of the node as it appears in its parent's child list\n *\n * @param {Node} node\n * @return {int} - Position of the node\n */\nfunction getNodePosition(node) {\n let pos = 0;\n /** @type {Node|null} */\n let tmp = node;\n while (tmp) {\n if (tmp.nodeName === node.nodeName) {\n pos += 1;\n }\n tmp = tmp.previousSibling;\n }\n return pos;\n}\n\n/**\n * Get the path segments to the node\n *\n * @param {Node} node\n * @return {array} - Path segments\n */\nfunction getPathSegment(node) {\n const name = getNodeName(node);\n const pos = getNodePosition(node);\n return `${name}[${pos}]`;\n}\n\n/**\n * A simple XPath generator which can generate XPaths of the form\n * /tag[index]/tag[index].\n *\n * @param {Node} node - The node to generate a path to\n * @param {Node} root - Root node to which the returned path is relative\n * @return {string} - The xpath of a node\n */\nexport function xpathFromNode(node, root) {\n let xpath = '';\n\n /** @type {Node|null} */\n let elem = node;\n while (elem !== root) {\n if (!elem) {\n throw new Error('Node is not a descendant of root');\n }\n xpath = getPathSegment(elem) + '/' + xpath;\n elem = elem.parentNode;\n }\n xpath = '/' + xpath;\n xpath = xpath.replace(/\\/$/, ''); // Remove trailing slash\n\n return xpath;\n}\n\n/**\n * Return the `index`'th immediate child of `element` whose tag name is\n * `nodeName` (case insensitive).\n *\n * @param {Element} element\n * @param {string} nodeName\n * @param {number} index\n * @return {Element} - The child element or null\n */\nfunction nthChildOfType(element, nodeName, index) {\n nodeName = nodeName.toUpperCase();\n\n let matchIndex = -1;\n for (let i = 0; i < element.children.length; i++) {\n const child = element.children[i];\n if (child.nodeName.toUpperCase() === nodeName) {\n ++matchIndex;\n if (matchIndex === index) {\n return child;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Evaluate a _simple XPath_ relative to a `root` element and return the\n * matching element.\n *\n * A _simple XPath_ is a sequence of one or more `/tagName[index]` strings.\n *\n * Unlike `document.evaluate` this function:\n *\n * - Only supports simple XPaths\n * - Is not affected by the document's _type_ (HTML or XML/XHTML)\n * - Ignores element namespaces when matching element names in the XPath against\n * elements in the DOM tree\n * - Is case insensitive for all elements, not just HTML elements\n *\n * The matching element is returned or `null` if no such element is found.\n * An error is thrown if `xpath` is not a simple XPath.\n *\n * @param {string} xpath\n * @param {Element} root\n * @return {Element|null}\n */\nfunction evaluateSimpleXPath(xpath, root) {\n const isSimpleXPath =\n xpath.match(/^(\\/[A-Za-z0-9-]+(\\[[0-9]+\\])?)+$/) !== null;\n if (!isSimpleXPath) {\n throw new Error('Expression is not a simple XPath');\n }\n\n const segments = xpath.split('/');\n let element = root;\n\n // Remove leading empty segment. The regex above validates that the XPath\n // has at least two segments, with the first being empty and the others non-empty.\n segments.shift();\n\n for (let segment of segments) {\n let elementName;\n let elementIndex;\n\n const separatorPos = segment.indexOf('[');\n if (separatorPos !== -1) {\n elementName = segment.slice(0, separatorPos);\n\n const indexStr = segment.slice(separatorPos + 1, segment.indexOf(']'));\n elementIndex = parseInt(indexStr) - 1;\n if (elementIndex < 0) {\n return null;\n }\n } else {\n elementName = segment;\n elementIndex = 0;\n }\n\n const child = nthChildOfType(element, elementName, elementIndex);\n if (!child) {\n return null;\n }\n\n element = child;\n }\n\n return element;\n}\n\n/**\n * Finds an element node using an XPath relative to `root`\n *\n * Example:\n * node = nodeFromXPath('/main/article[1]/p[3]', document.body)\n *\n * @param {string} xpath\n * @param {Element} [root]\n * @return {Node|null}\n */\nexport function nodeFromXPath(xpath, root = document.body) {\n try {\n return evaluateSimpleXPath(xpath, root);\n } catch (err) {\n return document.evaluate(\n '.' + xpath,\n root,\n\n // Nb. The `namespaceResolver` and `result` arguments are optional in the spec but required in Edge Legacy.\n null /* NamespaceResolver */,\n XPathResult.FIRST_ORDERED_NODE_TYPE,\n null /* Result */\n ).singleNodeValue;\n }\n}\n"],"file":"xpath.min.js"} \ No newline at end of file diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml new file mode 100644 index 0000000..eb93765 --- /dev/null +++ b/thirdpartylibs.xml @@ -0,0 +1,10 @@ + + + + amd/src/string-match.js + approx-string-match-js + MIT + 2.0.0 + + + diff --git a/version.php b/version.php index 04da367..6a30344 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'mod_margic'; -$plugin->release = '1.2.2'; // User-friendly version number. -$plugin->version = 2022091200; // The current module version (Date: YYYYMMDDXX). +$plugin->release = '1.2.3'; // User-friendly version number. +$plugin->version = 2022091900; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2020061507; // Requires Moodle 3.9. $plugin->maturity = MATURITY_STABLE;