[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
05122024
/
htdocs
/
e-learning
/
assets
/
comp
/
ckeditor
/
plugins
/
ckeditor_wiris
/
core
/
[
Home
]
File: core.js
var _wrs_popupWindow; wrs_addEvent(window, 'message', function (e) { if (e.source = _wrs_popupWindow && typeof e.wrs_processed == 'undefined') { e.wrs_processed = true; var postVariable = {}; postVariable.id = e.data.id; if (e.data.hasOwnProperty('methodName')) { var object = (e.data.objectName == null) ? this : window[e.data.objectName]; postVariable.value = object[e.data.methodName].apply(object, e.data.arguments); } else { var postVariables = {}; e.data.varNames.forEach(function(varName){ postVariables[varName] = window[varName]; }); postVariable.value = postVariables; } if (typeof(e.source) != 'undefined') { // Avoid sent message when popupWindows has been closed. e.source.postMessage(postVariable, _wrs_conf_path); } } }); // Vars. var _wrs_currentPath = window.location.toString().substr(0, window.location.toString().lastIndexOf('/') + 1); var _wrs_editMode = typeof _wrs_editMode != 'undefined' ? _wrs_editMode : undefined; var _wrs_isNewElement = typeof _wrs_isNewElement != 'undefined' ? _wrs_isNewElement : true; var _wrs_temporalImage; var _wrs_temporalFocusElement; var _wrs_androidRange; var _wrs_iosRange; // We need a variable to send device properties to editor.js on modal mode. var _wrs_deviceProperties = {} // Dragable options. var _wrs_dragDataObject; var _wrs_dragObject; // LaTex client cache. var _wrs_int_LatexCache = {}; var _wrs_xmlCharacters = { 'tagOpener': '<', // Hex: \x3C. 'tagCloser': '>', // Hex: \x3E. 'doubleQuote': '"', // Hex: \x22. 'ampersand': '&', // Hex: \x26. 'quote': '\'' // Hex: \x27. }; var _wrs_safeXmlCharacters = { 'tagOpener': '«', // Hex: \xAB. 'tagCloser': '»', // Hex: \xBB. 'doubleQuote': '¨', // Hex: \xA8. 'ampersand': '§', // Hex: \xA7. 'quote': '`', // Hex: \x60. 'realDoubleQuote': '¨' }; var _wrs_safeXmlCharactersEntities = { 'tagOpener': '«', 'tagCloser': '»', 'doubleQuote': '¨', 'realDoubleQuote': '"' } var _wrs_safeBadBlackboardCharacters = { 'ltElement': '«mo»<«/mo»', 'gtElement': '«mo»>«/mo»', 'ampElement': '«mo»&«/mo»' } var _wrs_safeGoodBlackboardCharacters = { 'ltElement': '«mo»§lt;«/mo»', 'gtElement': '«mo»§gt;«/mo»', 'ampElement': '«mo»§amp;«/mo»' } var _wrs_staticNodeLengths = { 'IMG': 1, 'BR': 1 } // Backwards compatibily. if (!(window._wrs_conf_imageClassName)) { _wrs_conf_imageClassName = 'Wirisformula'; } if (!(window._wrs_conf_CASClassName)) { _wrs_conf_CASClassName = 'Wiriscas'; } // Mutation observers to avoid wiris image formulas class be removed. if (typeof MutationObserver != 'undefined') { var wrs_observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.oldValue == _wrs_conf_imageClassName && mutation.attributeName == 'class' && mutation.target.className.indexOf(_wrs_conf_imageClassName) == -1 ) { mutation.target.className = _wrs_conf_imageClassName; } }); }); var wrs_observer_config = { attributes: true, attributeOldValue:true }; } // Plugin listeners for custom callbacks. This variable // can be setted by the user using wrs_addPluginListener. var wrs_pluginListeners = []; /** * Adds element events. * @param {object} target Target * @param {function} doubleClickHandler Function to run when user double clicks the element * @param {function} mousedownHandler Function to run when user mousedowns the element * @param {function} mouseupHandler Function to run when user mouseups the element * @ignore */ function wrs_addElementEvents(target, doubleClickHandler, mousedownHandler, mouseupHandler) { if (doubleClickHandler) { wrs_addEvent(target, 'dblclick', function (event) { var realEvent = (event) ? event : window.event; var element = realEvent.srcElement ? realEvent.srcElement : realEvent.target; doubleClickHandler(target, element, realEvent); }); } if (mousedownHandler) { wrs_addEvent(target, 'mousedown', function (event) { var realEvent = (event) ? event : window.event; var element = realEvent.srcElement ? realEvent.srcElement : realEvent.target; _wrs_temporalFocusElement = element; mousedownHandler(target, element, realEvent); }); } if (mouseupHandler) { wrs_addEvent(target, 'mouseup', function (event) { var realEvent = (event) ? event : window.event; var element = realEvent.srcElement ? realEvent.srcElement : realEvent.target; mouseupHandler(target, element, realEvent); }); } } /** * Cross-browser addEventListener/attachEvent function. * @param {object} element Element target * @param {event} event Event * @param {function} func Function to run * @ignore */ function wrs_addEvent(element, event, func) { if (element.addEventListener) { element.addEventListener(event, func, true); } else if (element.attachEvent) { element.attachEvent('on' + event, func); } } /** * Adds iframe events. * @param {object} iframe Target * @param {function} doubleClickHandler Function to run when user double clicks the iframe * @param {function} mousedownHandler Function to run when user mousedowns the iframe * @param {function} mouseupHandler Function to run when user mouseups the iframe * @ignore */ function wrs_addIframeEvents(iframe, doubleClickHandler, mousedownHandler, mouseupHandler) { wrs_initSetSize(); wrs_addElementEvents(iframe.contentWindow.document, function (target, element, event) { doubleClickHandler(iframe, element, event); }, function (target, element, event) { mousedownHandler(iframe, element, event); }, function (target, element, event) { mouseupHandler(iframe, element, event); } ); } /** * Adds textarea events. * @param {object} textarea Target * @param {function} clickHandler Function to run when user clicks the textarea. * @ignore */ function wrs_addTextareaEvents(textarea, clickHandler) { if (clickHandler) { wrs_addEvent(textarea, 'click', function (event) { var realEvent = (event) ? event : window.event; clickHandler(textarea, realEvent); }); } } /** * Converts applet code to img object. * @param {object} creator Object with "createElement" method * @param {string} appletCode Applet code * @param {string} image Base 64 image stream * @param {int} imageWidth Image width * @param {int} imageHeight Image height * @return object img object. * @ignore */ function wrs_appletCodeToImgObject(creator, appletCode, image, imageWidth, imageHeight) { var imageSrc = wrs_createImageCASSrc(image); var imgObject = creator.createElement('img'); imgObject.src = imageSrc; imgObject.align = 'middle'; imgObject.width = imageWidth; imgObject.height = imageHeight; imgObject.setAttribute(_wrs_conf_CASMathmlAttribute, wrs_mathmlEncode(appletCode)); imgObject.className = _wrs_conf_CASClassName; return imgObject; } /** * Checks if a determined array contains a determined element. * @param {array} stack * @param {object} element * @return bool * @ignore */ function wrs_arrayContains(stack, element) { for (var i = stack.length - 1; i >= 0; --i) { if (stack[i] === element) { return i; } } return -1; } /** * Checks if an element contains a class. * @param {object} element * @param {string} className * @return bool * @ignore */ function wrs_containsClass(element, className) { if (!('className' in element)){ return false; } var currentClasses = element.className.split(' '); for (var i = currentClasses.length - 1; i >= 0; --i) { if (currentClasses[i] == className) { return true; } } return false; } /** * Converts old xmlinitialtext attribute (with «») to the correct one(with §lt;§gt;) * @param {string} text String containtg safeXml characters * @return {string} String with the safeXml charaters parsed. * @ignore */ function wrs_convertOldXmlinitialtextAttribute(text){ // Used to fix a bug with Cas imported from Moodle 1.9 to Moodle 2.x. // This could be removed in future. var val = 'value='; var xitpos = text.indexOf('xmlinitialtext'); var valpos = text.indexOf(val, xitpos); var quote = text.charAt(valpos + val.length); var startquote = valpos + val.length + 1; var endquote = text.indexOf(quote, startquote); var value = text.substring(startquote, endquote); var newvalue = value.split('«').join('§lt;'); newvalue = newvalue.split('»').join('§gt;'); newvalue = newvalue.split('&').join('§'); newvalue = newvalue.split('¨').join('§quot;'); text = text.split(value).join(newvalue); return text; } /** * Cross-browser solution for creating new elements. * * It fixes some browser bugs. * * @param {string} elementName The tag name of the wished element. * @param {object} attributes An object where each key is a wished attribute name and each value is its value. * @param {object} creator Optional param. If supplied, this function will use the "createElement" method from this param. Else, "document" will be used. * @return {object} The DOM element with the specified attributes assignated. * @ignore */ function wrs_createElement(elementName, attributes, creator) { if (attributes === undefined) { attributes = {}; } if (creator === undefined) { creator = document; } var element; /* * Internet Explorer fix: * If you create a new object dynamically, you can't set a non-standard attribute. * For example, you can't set the "src" attribute on an "applet" object. * Other browsers will throw an exception and will run the standard code. */ try { var html = '<' + elementName; for (var attributeName in attributes) { html += ' ' + attributeName + '="' + wrs_htmlentities(attributes[attributeName]) + '"'; } html += '>'; element = creator.createElement(html); } catch (e) { element = creator.createElement(elementName); for (var attributeName in attributes) { element.setAttribute(attributeName, attributes[attributeName]); } } return element; } /** * Cross-browser httpRequest creation. * @return {object} httpRequest request object. * @ignore */ function wrs_createHttpRequest() { if (_wrs_currentPath.substr(0, 7) == 'file://') { throw 'Cross site scripting is only allowed for HTTP.'; } if (typeof XMLHttpRequest != 'undefined') { return new XMLHttpRequest(); } try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (oc) { } } return false; } /** * Gets CAS image src with AJAX. * @param {string} image Base 64 image stream * @return {string} CAS image src. * @ignore */ function wrs_createImageCASSrc(image, appletCode) { var data = { 'image': image, 'mml': appletCode }; return wrs_getContent(_wrs_conf_createcasimagePath, data); } /** * Gets formula image src with AJAX. * @param {mathml} Mathml code. * @param {object} data wiris properties object. * @return string Image src. * @ignore */ function wrs_createImageSrc(mathml, data) { // Full base64 method (edit & save). if (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'default') { data['base64'] = true; } var result = wrs_getContent(_wrs_conf_createimagePath, data); if (result.indexOf('@BASE@') != -1) { // Replacing '@BASE@' with the base URL of createimage. var baseParts = _wrs_conf_createimagePath.split('/'); baseParts.pop(); result = result.split('@BASE@').join(baseParts.join('/')); } return result; } function wrs_createShowImageSrc(mathml, data, language) { var dataMd5 = [] var renderParams = 'mml,color,centerbaseline,zoom,dpi,fontSize,fontFamily,defaultStretchy,backgroundColor,format'; var renderParamsArray = renderParams.split(','); for (var key in renderParamsArray) { var param = renderParamsArray[key]; if (typeof data[param] != 'undefined') { dataMd5[param] = data[param]; } } // Data variables to get. var dataObject = {}; for (var key in data) { // We don't need mathml in this request we try to get cached so we only need the formula md5 calculated before. if (key != 'mml') { dataObject[key] = data[key]; } } dataObject.formula = com.wiris.js.JsPluginTools.md5encode(wrs_propertiesToString(dataMd5)); dataObject.lang = (typeof language == 'undefined') ? 'en' : language; var result = wrs_getContent(_wrs_conf_showimagePath + '?' + wrs_httpBuildQuery(dataObject)); return result; } /** * Creates new object using its html code. * @param {string} objectCode html code * @return {object} html object. * @ignore */ function wrs_createObject(objectCode, creator) { if (creator === undefined) { creator = document; } // Internet Explorer can't include "param" tag when is setting an innerHTML property. objectCode = objectCode.split('<applet ').join('<span wirisObject="WirisApplet" ').split('<APPLET ').join('<span wirisObject="WirisApplet" '); // It is a 'span' because 'span' objects can contain 'br' nodes. objectCode = objectCode.split('</applet>').join('</span>').split('</APPLET>').join('</span>'); objectCode = objectCode.split('<param ').join('<br wirisObject="WirisParam" ').split('<PARAM ').join('<br wirisObject="WirisParam" '); // It is a 'br' because 'br' can't contain nodes. objectCode = objectCode.split('</param>').join('</br>').split('</PARAM>').join('</br>'); var container = wrs_createElement('div', {}, creator); container.innerHTML = objectCode; function recursiveParamsFix(object) { if (object.getAttribute && object.getAttribute('wirisObject') == 'WirisParam') { var attributesParsed = {}; for (var i = 0; i < object.attributes.length; ++i) { if (object.attributes[i].nodeValue !== null) { attributesParsed[object.attributes[i].nodeName] = object.attributes[i].nodeValue; } } var param = wrs_createElement('param', attributesParsed, creator); // IE fix. if (param.NAME) { param.name = param.NAME; param.value = param.VALUE; } param.removeAttribute('wirisObject'); object.parentNode.replaceChild(param, object); } else if (object.getAttribute && object.getAttribute('wirisObject') == 'WirisApplet') { var attributesParsed = {}; for (var i = 0; i < object.attributes.length; ++i) { if (object.attributes[i].nodeValue !== null) { attributesParsed[object.attributes[i].nodeName] = object.attributes[i].nodeValue; } } var applet = wrs_createElement('applet', attributesParsed, creator); applet.removeAttribute('wirisObject'); for (var i = 0; i < object.childNodes.length; ++i) { recursiveParamsFix(object.childNodes[i]); if (object.childNodes[i].nodeName.toLowerCase() == 'param') { applet.appendChild(object.childNodes[i]); --i; // When we insert the object child into the applet, object loses one child. } } object.parentNode.replaceChild(applet, object); } else { for (var i = 0; i < object.childNodes.length; ++i) { recursiveParamsFix(object.childNodes[i]); } } } recursiveParamsFix(container); return container.firstChild; } /** * Converts an object to its HTML code. * @param {object} object DOM object.. * @return {string} HTML code. * @ignore */ function wrs_createObjectCode(object) { if (object.nodeType == 1) { // ELEMENT_NODE. var output = '<' + object.tagName; for (var i = 0; i < object.attributes.length; ++i) { if (object.attributes[i].specified) { output += ' ' + object.attributes[i].name + '="' + wrs_htmlentities(object.attributes[i].value) + '"'; } } if (object.childNodes.length > 0) { output += '>'; for (var i = 0; i < object.childNodes.length; ++i) { output += wrs_createObjectCode(object.childNodes[i]); } output += '</' + object.tagName + '>'; } else if (object.nodeName == 'DIV' || object.nodeName == 'SCRIPT') { output += '></' + object.tagName + '>'; } else { output += '/>'; } return output; } if (object.nodeType == 3) { // TEXT_NODE. return wrs_htmlentities(object.nodeValue); } return ''; } /** * Parses end HTML code. The end HTML code is HTML code with embedded images or LaTeX formulas created with the WIRIS editor. <br> * By default this method converts the formula images and LaTeX strings in MathML. <br> * If image mode is enabled the images will not be converted into MathML. For further information see {@link http://www.wiris.com/plugins/docs/full-mathml-mode}. * @param {string} code String to be parsed. * @param {object} wirisProperties Extra attributes for the formula. * @param {string} language Language for the formula. * @return {string} */ function wrs_endParse(code, wirisProperties, language) { code = wrs_endParseEditMode(code, wirisProperties, language); return wrs_endParseSaveMode(code); } function wrs_regexpIndexOf(input, regexp, start) { var index = input.substring(start || 0).search(regexp); return (index >= 0) ? (index + (start || 0)) : index; } /** * Parses end HTML code depending on the edit mode. * @param {string} code HTML code to be parsed. * @param {object} wirisProperties Extra formula attributes. * @param {string} language Language for the formula. * @return {string} * @ignore */ function wrs_endParseEditMode(code, wirisProperties, language) { // Converting LaTeX to images. if (window._wrs_conf_parseModes !== undefined && wrs_arrayContains(_wrs_conf_parseModes, 'latex') != -1) { var output = ''; var endPosition = 0; var startPosition = code.indexOf('$$'); while (startPosition != -1) { output += code.substring(endPosition, startPosition); endPosition = code.indexOf('$$', startPosition + 2); if (endPosition != -1) { var latex = code.substring(startPosition + 2, endPosition); if (latex.indexOf('<') == -1) { latex = wrs_htmlentitiesDecode(latex); var mathml = wrs_getMathMLFromLatex(latex, true); var imgObject = wrs_mathmlToImgObject(document, mathml, wirisProperties, language); output += wrs_createObjectCode(imgObject); endPosition += 2; } else { output += '$$'; endPosition = startPosition + 2; } } else { output += '$$'; endPosition = startPosition + 2; } startPosition = code.indexOf('$$', endPosition); } output += code.substring(endPosition, code.length); code = output; } if (window._wrs_conf_defaultEditMode && _wrs_conf_defaultEditMode == 'iframes') { // Converting iframes to images. var output = ''; var pattern = ' class="' + _wrs_conf_imageClassName + '"'; var formulaPosition = code.indexOf(pattern); var endPosition = 0; while (formulaPosition != -1) { // Looking for the actual startPosition. startPosition = formulaPosition; var i = formulaPosition; var startTagFound = false; while (i >= 0 && !startTagFound) { // Going backwards until the start tag '<' is found. var character = code.charAt(i); if (character == '"' || character == '\'') { var characterNextPosition = code.lastIndexOf(character, i); i = (characterNextPosition == -1) ? -1 : characterNextPosition; } else if (character == '<') { startPosition = i; startTagFound = true; } else if (character == '>') { i = -1; // Break: we are inside a text node. } --i; } // Appending the previous code. output += code.substring(endPosition, startPosition); // Looking for the endPosition. if (startTagFound) { i = formulaPosition; var counter = 1; while (i < code.length && counter > 0) { var character = code.charAt(i); if (character == '"' || character == '\'') { var characterNextPosition = code.indexOf(character, i); i = (characterNextPosition == -1) ? code.length : characterNextPosition; } else if (character == '<') { if (i + 1 < code.length && code.charAt(i + 1) == '/') { --counter; if (counter == 0) { endPosition = code.indexOf('>', i) + 1; if (endPosition == -1) { // End tag stripped. counter = -1; // to be != 0 and to break the loop. } } } else { ++counter; } } else if (character == '>' && code.charAt(i - 1) == '/') { --counter; if (counter == 0) { endPosition = i + 1; } } ++i; } if (counter == 0) { var formulaTagCode = code.substring(startPosition, endPosition); var formulaTagObject = wrs_createObject(formulaTagCode); var mathml = formulaTagObject.getAttribute(_wrs_conf_imageMathmlAttribute); if (mathml == null) { mathml = formulaTagObject.getAttribute('alt'); } var imgObject = wrs_mathmlToImgObject(document, mathml, wirisProperties, language); output += wrs_createObjectCode(imgObject); } else { // Start tag found but no end tag found. No process is done. A character is appended to avoid infinite loop in the next search. output += code.charAt(formulaPosition); endPosition = formulaPosition + 1; } } else { // No start tag is found. No process is done. A character is appended to avoid infinite loop in the next search. output += code.charAt(formulaPosition); endPosition = formulaPosition + 1; } formulaPosition = code.indexOf(pattern, endPosition); } output += code.substring(endPosition, code.length); code = output; } return code; } /** * Parses end HTML code depending on the save mode. * @param {string} code HTML code * @return {string} * @ignore */ function wrs_endParseSaveMode(code) { var output = ''; var convertToXml = false; var convertToSafeXml = false; if (window._wrs_conf_saveMode) { if (_wrs_conf_saveMode == 'safeXml') { convertToXml = true; convertToSafeXml = true; } else if (_wrs_conf_saveMode == 'xml') { convertToXml = true; } } if (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'image') { code = wrs_codeImgTransform(code, 'img264'); } else if (convertToXml || convertToSafeXml) { code = wrs_codeImgTransform(code, 'img2mathml'); } return code; } /** * Fires an element event. * @param {object} element element where event should be fired. * @param {string} event event to fire. * @ignore */ function wrs_fireEvent(element, event) { if (document.createEvent){ var eventObject = document.createEvent('HTMLEvents'); eventObject.initEvent(event, true, true); return !element.dispatchEvent(eventObject); } var eventObject = document.createEventObject(); return element.fireEvent('on' + event, eventObject) } /** * Gets the formula mathml or CAS appletCode using its image hash code. * @param {string} variableName Variable to send on POST query to the server. * @param {string} imageHashCode image hash code. * @return {string} Corresponding mathml code. * @ignore */ function wrs_getCode(variableName, imageHashCode) { var data = {}; data[variableName] = imageHashCode; return wrs_getContent(_wrs_conf_getmathmlPath, data); } /** * Gets the content from an URL. * @param {string} url target URL. * @param {object} postVariables post variables. Null if a GET query should be done. * @return {string} content of the target URL. * @ignore */ function wrs_getContent(url, postVariables) { try { var httpRequest = wrs_createHttpRequest(); if (httpRequest) { if (typeof postVariables === undefined || typeof postVariables == 'undefined') { httpRequest.open('GET', url, false); } else if (url.substr(0, 1) == '/' || url.substr(0, 7) == 'http://' || url.substr(0, 8) == 'https://') { httpRequest.open('POST', url, false); } else { httpRequest.open('POST', _wrs_currentPath + url, false); } if (postVariables !== undefined) { httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=UTF-8'); httpRequest.send(wrs_httpBuildQuery(postVariables)); } else { httpRequest.send(null); } return httpRequest.responseText; } alert('Your browser is not compatible with AJAX technology. Please, use the latest version of Mozilla Firefox.'); } catch (e) { } return ''; } /** * Generates the innerHTML of an element. * @param {object} element target element. * @return {string} innertHTML of the target element. * @ignore */ function wrs_getInnerHTML(element) { var innerHTML = ''; for (var i = 0; i < element.childNodes.length; ++i) { innerHTML += wrs_createObjectCode(element.childNodes[i]); } return innerHTML; } /** * Converts MathML to LaTeX. * @param {string} mathml MathML String * @return {string} MathML corresponding LaTeX. * @ignore */ function wrs_getLatexFromMathML(mathml) { var data = { 'service': 'mathml2latex', 'mml': mathml }; return wrs_getContent(_wrs_conf_servicePath, data); } /** * Extracts the latex of a determined position in a text. * @param {string} textNode test to extract LaTeX * @param {int} caretPosition starting position to find LaTeX. * @return {object} An object with 3 keys: 'latex', 'start' and 'end'. Null if latex is not found. * @ignore */ function wrs_getLatexFromTextNode(textNode, caretPosition) { // Looking for the first textNode. var startNode = textNode; while (startNode.previousSibling && startNode.previousSibling.nodeType == 3) { // TEXT_NODE. startNode = startNode.previousSibling; } // Finding latex. function getNextLatexPosition(currentNode, currentPosition) { var position = currentNode.nodeValue.indexOf('$$', currentPosition); while (position == -1) { currentNode = currentNode.nextSibling; if (!currentNode || currentNode.nodeType != 3) { // TEXT_NODE. return null; // Not found. } position = currentNode.nodeValue.indexOf('$$'); } return { 'node': currentNode, 'position': position }; } function isPrevious(node, position, endNode, endPosition) { if (node == endNode) { return (position <= endPosition); } while (node && node != endNode) { node = node.nextSibling; } return (node == endNode); } var start; var end = { 'node': startNode, 'position': 0 }; do { var start = getNextLatexPosition(end.node, end.position); if (start == null || isPrevious(textNode, caretPosition, start.node, start.position)) { return null; } var end = getNextLatexPosition(start.node, start.position + 2); if (end == null) { return null; } end.position += 2; } while (isPrevious(end.node, end.position, textNode, caretPosition)); // Isolating latex. var latex; if (start.node == end.node) { latex = start.node.nodeValue.substring(start.position + 2, end.position - 2); } else { latex = start.node.nodeValue.substring(start.position + 2, start.node.nodeValue.length); var currentNode = start.node; do { currentNode = currentNode.nextSibling; if (currentNode == end.node) { latex += end.node.nodeValue.substring(0, end.position - 2); } else { latex += currentNode.nodeValue; } } while (currentNode != end.node); } return { 'latex': latex, 'startNode': start.node, 'startPosition': start.position, 'endNode': end.node, 'endPosition': end.position }; } /** * Converts LaTeX to MathML. * @param {string} latex String * @param {bool} includeLatexOnSemantics If true LaTeX would me included into MathML semantics. * @return {string} converted mathML * @ignore */ function wrs_getMathMLFromLatex(latex, includeLatexOnSemantics) { if (_wrs_int_LatexCache.hasOwnProperty(latex)) { return _wrs_int_LatexCache[latex]; } var data = { 'service': 'latex2mathml', 'latex': latex }; if (includeLatexOnSemantics) { data['saveLatex'] = ''; } var mathML = wrs_getContent(_wrs_conf_servicePath, data); return mathML.split("\r").join('').split("\n").join(' '); } /** * Gets the node length in characters. * @param {object} node HTML node. * @return {int} node length * @ignore */ function wrs_getNodeLength(node) { if (node.nodeType == 3) { // TEXT_NODE. return node.nodeValue.length; } if (node.nodeType == 1) { // ELEMENT_NODE. var length = _wrs_staticNodeLengths[node.nodeName.toUpperCase()]; if (length === undefined) { length = 0; } for (var i = 0; i < node.childNodes.length; ++i) { length += wrs_getNodeLength(node.childNodes[i]); } return length; } return 0; } /** * Parses the query string and returns it as a Hash table. * @param {object} windowObject a window object with a query string. * @return {object} a hash table containing the query string. * @ignore */ function wrs_getQueryParams(windowObject) { var data = {}; var start = windowObject.location.search.indexOf('?'); start = (start == -1) ? 0 : start + 1; var queryStringParts = windowObject.location.search.substr(start).split('&'); for (var i = 0; i < queryStringParts.length; ++i) { var paramParts = queryStringParts[i].split('=', 2); data[paramParts[0]] = wrs_urldecode(paramParts[1]); } return data; } /** * Gets the selected node or text. * If the caret is on a text node, concatenates it with all the previous and next text nodes. * @param {object} target The editable element * @param {boolean} isIframe Specifies if the target is an iframe or not * @param {forceGetSelection} If true, ignores IE system to get the current selection and uses window.getSelection() * @return {object} An object with the 'node' key setted if the item is an element or the keys 'node' and 'caretPosition' if the element is text * @ignore */ function wrs_getSelectedItem(target, isIframe, forceGetSelection) { var windowTarget; if (isIframe) { windowTarget = target.contentWindow; windowTarget.focus(); } else { windowTarget = window; target.focus(); } if (document.selection && !forceGetSelection) { var range = windowTarget.document.selection.createRange(); if (range.parentElement) { if (range.htmlText.length > 0) { if (range.text.length == 0) { return wrs_getSelectedItem(target, isIframe, true); } return null; } windowTarget.document.execCommand('InsertImage', false, '#'); var temporalObject = range.parentElement(); if (temporalObject.nodeName.toUpperCase() != 'IMG') { // IE9 fix: parentElement() does not return the IMG node, returns the parent DIV node. In IE < 9, pasteHTML does not work well. range.pasteHTML('<span id="wrs_openEditorWindow_temporalObject"></span>'); temporalObject = windowTarget.document.getElementById('wrs_openEditorWindow_temporalObject'); } var node; var caretPosition; if (temporalObject.nextSibling && temporalObject.nextSibling.nodeType == 3) { // TEXT_NODE. node = temporalObject.nextSibling; caretPosition = 0; } else if (temporalObject.previousSibling && temporalObject.previousSibling.nodeType == 3) { // TEXT_NODE. node = temporalObject.previousSibling; caretPosition = node.nodeValue.length; } else { node = windowTarget.document.createTextNode(''); temporalObject.parentNode.insertBefore(node, temporalObject); caretPosition = 0; } temporalObject.parentNode.removeChild(temporalObject); return { 'node': node, 'caretPosition': caretPosition }; } if (range.length > 1) { return null; } return { 'node': range.item(0) }; } if (windowTarget.getSelection) { var selection = windowTarget.getSelection(); try { var range = selection.getRangeAt(0); } catch (e) { var range = windowTarget.document.createRange(); } var node = range.startContainer; if (node.nodeType == 3) { // TEXT_NODE. if (range.startOffset != range.endOffset) { return null; } return { 'node': node, 'caretPosition': range.startOffset }; } if (node != range.endContainer) { return null; } if (node.nodeType == 1) { // ELEMENT_NODE. var position = range.startOffset; if (node.childNodes[position]) { return { 'node': node.childNodes[position] }; } } } return null; } /** * Converts the HTML of a image into the output code that WIRIS must return. * By default returns the mathml stored on data-mahml attribute (if imgCode is a formula) * or the Wiriscas attribute of a WIRIS applet. * @param {string} imgCode the html code from a formula or a CAS image. * @param {bool} convertToXml True if the image should be converted to xml. * @param {bool} convertToSafeXml True if the image should be conerte to safeXmll * @return {string} the Xml or safeXml of a WIRIS image. * @ignore */ function wrs_getWIRISImageOutput(imgCode, convertToXml, convertToSafeXml) { var imgObject = wrs_createObject(imgCode); if (imgObject) { if (imgObject.className == _wrs_conf_imageClassName) { if (!convertToXml) { return imgCode; } var xmlCode = imgObject.getAttribute(_wrs_conf_imageMathmlAttribute); if (xmlCode == null) { xmlCode = imgObject.getAttribute('alt'); } if (!convertToSafeXml) { xmlCode = wrs_mathmlDecode(xmlCode); } return xmlCode; } else if (imgObject.className == _wrs_conf_CASClassName) { var appletCode = imgObject.getAttribute(_wrs_conf_CASMathmlAttribute); appletCode = wrs_mathmlDecode(appletCode); var appletObject = wrs_createObject(appletCode); appletObject.setAttribute('src', imgObject.src); var object = appletObject; var appletCodeToBeInserted = wrs_createObjectCode(appletObject); if (convertToSafeXml) { appletCodeToBeInserted = wrs_mathmlEncode(appletCodeToBeInserted); } return appletCodeToBeInserted; } } return imgCode; } /** * Parses a text and replaces all HTML special characters by their entities. * @param {string} input Text to be paresed. * @return {string} the input text with all their special characters replaced by their entities. * @ignore */ function wrs_htmlentities(input) { return input.split('&').join('&').split('<').join('<').split('>').join('>').split('"').join('"'); } /** * Parses a text and replaces all the HTML entities by their characters. * @param {string} input Text to be parsed * @return {string} The input text with all their entities replaced by characters. * @ignore */ function wrs_htmlentitiesDecode(input) { return input.split('"').join('"').split('>').join('>').split('<').join('<').split('&').join('&'); } /** * Converts a hash to a HTTP query. * @param {hash} properties A key-value Hash * @return {string} A HTTP query containing all the key value pairs with all the shpecial characters replaced by their entities. * @ignore */ function wrs_httpBuildQuery(properties) { var result = ''; for (i in properties) { if (properties[i] != null) { result += wrs_urlencode(i) + '=' + wrs_urlencode(properties[i]) + '&'; } } // Deleting last '&' empty character. if (result.substring(result.length - 1) == '&') { result = result.substring(0, result.length - 1); } return result; } /** * Parses initial HTML code. If the HTML contains data generated by WIRIS, this data would be converted as following: * <pre> * MathML code: Image containing the corresponding MathML formulas. * MathML code with LaTeX annotation : LaTeX. * </pre> * @param {string} code HTML code with data generated by WIRIS plugin. * @param {string} language Language for the formula. * @return {string} HTML code with the WIRIS data converted into LaTeX and images. */ /* Note: The code inside this function has been inverted. If you invert again the code then you cannot use correctly LaTeX in Moodle. */ function wrs_initParse(code, language) { wrs_initSetSize(); if (window._wrs_conf_saveMode) { _wrs_parseXml = _wrs_conf_saveMode == 'safeXml'|| _wrs_conf_saveMode == 'xml'; if (window._wrs_conf_parseModes !== undefined) { _wrs_parseXml = _wrs_parseXml || wrs_arrayContains(_wrs_conf_parseModes, 'xml') != -1; } } code = wrs_initParseSaveMode(code, language); return wrs_initParseEditMode(code); } /** * Parses initial HTML code into iframes. * @param {object} windowTarget Target object window. * @ignore */ function wrs_initParseImgToIframes(windowTarget) { if (window._wrs_conf_defaultEditMode && _wrs_conf_defaultEditMode == 'iframes') { var imgList = windowTarget.document.getElementsByTagName('img'); var i = 0; while (i < imgList.length) { if (imgList[i].className == _wrs_conf_imageClassName) { var mathml = imgList[i].getAttribute(_wrs_conf_imageMathmlAttribute); if (mathml == null) { mathml = imgList[i].getAttribute('alt'); } var iframe = wrs_mathmlToIframeObject(windowTarget, wrs_mathmlDecode(mathml)); imgList[i].parentNode.replaceChild(iframe, imgList[i]); } else { ++i; } } } } /** * Parses initial HTML code depending on the edit mode. * @param {string} code HTML code. * @return {string} parsed HTML code. * @ignore */ function wrs_initParseEditMode(code) { if (window._wrs_conf_parseModes !== undefined && wrs_arrayContains(_wrs_conf_parseModes, 'latex') != -1) { var imgList = wrs_getElementsByNameFromString(code, 'img', true); var token = 'encoding="LaTeX">'; var carry = 0; // While replacing images with latex, the indexes of the found images changes respecting the original code, so this carry is needed. for (var i = 0; i < imgList.length; ++i) { var imgCode = code.substring(imgList[i].start + carry, imgList[i].end + carry); if (imgCode.indexOf(' class="' + _wrs_conf_imageClassName + '"') != -1) { var mathmlStartToken = ' ' + _wrs_conf_imageMathmlAttribute + '="'; var mathmlStart = imgCode.indexOf(mathmlStartToken); if (mathmlStart == -1) { mathmlStartToken = ' alt="'; mathmlStart = imgCode.indexOf(mathmlStartToken); } if (mathmlStart != -1) { mathmlStart += mathmlStartToken.length; var mathmlEnd = imgCode.indexOf('"', mathmlStart); var mathml = wrs_mathmlDecode(imgCode.substring(mathmlStart, mathmlEnd)); var latexStartPosition = mathml.indexOf(token); if (latexStartPosition != -1) { latexStartPosition += token.length; var latexEndPosition = mathml.indexOf('</annotation>', latexStartPosition); var latex = mathml.substring(latexStartPosition, latexEndPosition); var replaceText = '$$' + wrs_htmlentitiesDecode(latex) + '$$'; code = code.substring(0, imgList[i].start + carry) + replaceText + code.substring(imgList[i].end + carry); carry += replaceText.length - (imgList[i].end - imgList[i].start); } } } } } return code; } /** * Parses initial HTML code depending on the save mode. * @param {string} code HTML code to be parsed * @param {string} language Language for the formula. * @return {string} HTML code parsed. * @ignore */ function wrs_initParseSaveMode(code, language) { if (window._wrs_conf_saveMode) { if (_wrs_parseXml) { // Converting XML to tags. code = wrs_parseMathmlToLatex(code, _wrs_safeXmlCharacters); code = wrs_parseMathmlToLatex(code, _wrs_xmlCharacters); // Safe XML and XML must be parsed regardeless of save mode. // Order is important here, safeXml must be parsed first in order to avoid conflicts with data-mathml img attribute. code = wrs_parseSafeAppletsToObjects(code); code = wrs_parseMathmlToImg(code, _wrs_safeXmlCharacters, language); code = wrs_parseMathmlToImg(code, _wrs_xmlCharacters, language); } if (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'image') { code = wrs_codeImgTransform(code, 'base642showimage'); } } var appletList = wrs_getElementsByNameFromString(code, 'applet', false); var carry = 0; // While replacing applets with images, the indexes of the found applets changes respecting the original code, so this carry is needed. for (var i = 0; i < appletList.length; ++i) { var appletCode = code.substring(appletList[i].start + carry, appletList[i].end + carry); // The second control in the if is used to find WIRIS applet which don't have Wiriscas class (as it was in old CAS applets). if (appletCode.indexOf(' class="' + _wrs_conf_CASClassName + '"') != -1 || appletCode.toUpperCase().indexOf('WIRIS') != -1) { if (appletCode.indexOf(' src="') != -1){ var srcStart = appletCode.indexOf(' src="') + ' src="'.length; var srcEnd = appletCode.indexOf('"', srcStart); var src = appletCode.substring(srcStart, srcEnd); } else{ // This should happen only with old CAS imported from Moodle 1 to Moodle 2. if (typeof(_wrs_conf_pluginBasePath) != 'undefined'){ var src = _wrs_conf_pluginBasePath + '/integration/showcasimage.php?formula=noimage'; } else { var src = ''; } if (appletCode.indexOf(' class="' + _wrs_conf_CASClassName + '"') == -1){ var closeSymbol = appletCode.indexOf('>'); var appletTag = appletCode.substring(0, closeSymbol); var newAppletTag = appletTag.split(' width=').join(' class="Wiriscas" width='); appletCode = appletCode.split(appletTag).join(newAppletTag); appletCode = appletCode.split('\'').join('"'); } } // Double click to edit has been removed here. var imgCode = '<img align="middle" class="' + _wrs_conf_CASClassName + '" ' + _wrs_conf_CASMathmlAttribute + '="' + wrs_mathmlEncode(appletCode) + '" src="' + src + '" />'; code = code.substring(0, appletList[i].start + carry) + imgCode + code.substring(appletList[i].end + carry); carry += imgCode.length - (appletList[i].end - appletList[i].start); } } return code; } /** * Looks for elements that match the given name in a HTML code string. * Important: this function is very concrete for WIRIS code. It takes as preconditions lots of behaviors that are not the general case. * * @param {string} code HTML code * @param {string} name Element names * @param {boolean} autoClosed True if the elements are autoClosed. * @return {array} An array containing all HTML elements of code matching the name argument. * @ignore */ function wrs_getElementsByNameFromString(code, name, autoClosed) { var elements = []; var code = code.toLowerCase(); name = name.toLowerCase(); var start = code.indexOf('<' + name + ' '); while (start != -1) { // Look for nodes. var endString; if (autoClosed) { endString = '>'; } else { endString = '</' + name + '>'; } var end = code.indexOf(endString, start); if (end != -1) { end += endString.length; elements.push({ 'start': start, 'end': end }); } else { end = start + 1; } start = code.indexOf('<' + name + ' ', end); } return elements; } /** * Replaces a selection with an element. * @param {object} element Element * @param {object} focusElement Element to be focused * @param {object} windowTarget Target * @ignore */ function wrs_insertElementOnSelection(element, focusElement, windowTarget) { try { focusElement.focus(); // Integration function // If wrs_int_insertElementOnSelection function exists on // integration script can call focus method from the editor instance. // For example, on CKEditor calls CKEditorInstance.focus() method. // With this method we can call proper focus methods which in some scenarios // help's WIRIS plugin to focus properly on the current editor window. if (typeof wrs_int_insertElementOnSelection != 'undefined') { wrs_int_insertElementOnSelection(); } if (_wrs_isNewElement) { if (document.selection && document.getSelection == 0) { var range = windowTarget.document.selection.createRange(); windowTarget.document.execCommand('InsertImage', false, element.src); if (!('parentElement' in range)) { windowTarget.document.execCommand('delete', false); range = windowTarget.document.selection.createRange(); windowTarget.document.execCommand('InsertImage', false, element.src); } if ('parentElement' in range) { var temporalObject = range.parentElement(); if (temporalObject.nodeName.toUpperCase() == 'IMG') { temporalObject.parentNode.replaceChild(element, temporalObject); } else { // IE9 fix: parentNode() does not return the IMG node, returns the parent DIV node. In IE < 9, pasteHTML does not work well. range.pasteHTML(wrs_createObjectCode(element)); } } } else { var isAndroid = false; if (_wrs_androidRange){ var isAndroid = true; var range = _wrs_androidRange; } else if (_wrs_iosRange){ var isIOS = true; var range = _wrs_iosRange; }else{ var selection = windowTarget.getSelection(); try { var range = selection.getRangeAt(0); } catch (e) { var range = windowTarget.document.createRange(); } selection.removeAllRanges(); } range.deleteContents(); var node = range.startContainer; var position = range.startOffset; if (node.nodeType == 3) { // TEXT_NODE. node = node.splitText(position); node.parentNode.insertBefore(element, node); node = node.parentNode; } else if (node.nodeType == 1) { // ELEMENT_NODE. node.insertBefore(element, node.childNodes[position]); } if (!isAndroid && !isIOS){ // Fix to set the caret after the inserted image. range.selectNode(element); position = range.endOffset; selection.collapse(node, position); } } } else if (_wrs_temporalRange) { if (document.selection && document.getSelection == 0) { _wrs_isNewElement = true; _wrs_temporalRange.select(); wrs_insertElementOnSelection(element, focusElement, windowTarget); } else { var parentNode = _wrs_temporalRange.startContainer; _wrs_temporalRange.deleteContents(); _wrs_temporalRange.insertNode(element); } } else { if (!element) { // Editor empty, formula has been erased on edit. _wrs_temporalImage.parentNode.removeChild(_wrs_temporalImage); } _wrs_temporalImage.parentNode.replaceChild(element, _wrs_temporalImage); } } catch (e) { } } /** * Checks if the mathml at position i is inside an HTML attribute or not. * @param {string} content A string containing MathML code. * @param {string} i Search index. * @return {bool} True if is inside an HTML attribute. In other case, false. * @ignore */ function wrs_isMathmlInAttribute(content, i) { // Regex = '^[\'"][\\s]*=[\\s]*[\\w-]+([\\s]*("[^"]*"|\'[^\']*\')[\\s]*=[\\s]*[\\w-]+[\\s]*)*[\\s]+gmi<'; var math_att = '[\'"][\\s]*=[\\s]*[\\w-]+'; // "=att OR '=att var att_content = '"[^"]*"|\'[^\']*\''; // "blabla" OR 'blabla' var att = '[\\s]*(' + att_content + ')[\\s]*=[\\s]*[\\w-]+[\\s]*'; // "blabla"=att OR 'blabla'=att var atts = '(' + att + ')*'; // "blabla"=att1 "blabla"=att2 var regex = '^' + math_att + atts + '[\\s]+gmi<'; // "=att "blabla"=att1 "blabla"=att2 gmi< . var expression = new RegExp(regex); var actual_content = content.substring(0, i); var reversed = actual_content.split('').reverse().join(''); var exists = expression.test(reversed); return exists; } /** * WIRIS special encoding. * We use these entities because IE doesn't support html entities on its attributes sometimes. Yes, sometimes. * @param {string} input String to be decoded. * @return {string} Decoded string. * @ignore */ function wrs_mathmlDecode(input) { // Decoding entities. input = input.split(_wrs_safeXmlCharactersEntities.tagOpener).join(_wrs_safeXmlCharacters.tagOpener); input = input.split(_wrs_safeXmlCharactersEntities.tagCloser).join(_wrs_safeXmlCharacters.tagCloser); input = input.split(_wrs_safeXmlCharactersEntities.doubleQuote).join(_wrs_safeXmlCharacters.doubleQuote); // Added to fix problem due to import from 1.9.x. input = input.split(_wrs_safeXmlCharactersEntities.realDoubleQuote).join(_wrs_safeXmlCharacters.realDoubleQuote); // Blackboard. if ('_wrs_blackboard' in window && window._wrs_blackboard){ input = input.split(_wrs_safeBadBlackboardCharacters.ltElement).join(_wrs_safeGoodBlackboardCharacters.ltElement); input = input.split(_wrs_safeBadBlackboardCharacters.gtElement).join(_wrs_safeGoodBlackboardCharacters.gtElement); input = input.split(_wrs_safeBadBlackboardCharacters.ampElement).join(_wrs_safeGoodBlackboardCharacters.ampElement); /*var regex = /«mtext».*[<>&].*«\/mtext»/; var result = regex.exec(input); while(result){ var changedResult = result[0].split(_wrs_xmlCharacters.tagOpener).join('§lt;'); changedResult = changedResult.split(_wrs_xmlCharacters.tagCloser).join('§gt;'); changedResult = changedResult.split(_wrs_xmlCharacters.ampersand).join('§amp;'); input = input.replace(result, changedResult); result = regex.exec(input); }*/ } // Decoding characters. input = input.split(_wrs_safeXmlCharacters.tagOpener).join(_wrs_xmlCharacters.tagOpener); input = input.split(_wrs_safeXmlCharacters.tagCloser).join(_wrs_xmlCharacters.tagCloser); input = input.split(_wrs_safeXmlCharacters.doubleQuote).join(_wrs_xmlCharacters.doubleQuote); input = input.split(_wrs_safeXmlCharacters.ampersand).join(_wrs_xmlCharacters.ampersand); input = input.split(_wrs_safeXmlCharacters.quote).join(_wrs_xmlCharacters.quote); // We are replacing $ by & when its part of an entity for retrocompatibility. Now, the standard is replace § by &. var returnValue = ''; var currentEntity = null; for (var i = 0; i < input.length; ++i) { var character = input.charAt(i); if (currentEntity == null) { if (character == '$') { currentEntity = ''; } else { returnValue += character; } } else { if (character == ';') { returnValue += '&' + currentEntity + ';'; currentEntity = null; } else if (character.match(/([a-zA-Z0-9#._-] | '-')/)) { // Character is part of an entity. currentEntity += character; } else { returnValue += '$' + currentEntity; // Is not an entity. currentEntity = null; --i; // Parse again the current character. } } } return returnValue; } /** * WIRIS special encoding. * We use these entities because IE doesn't support html entities on its attributes sometimes. Yes, sometimes. * @param {string} input to be encoded * @return {string} Encoded string. * @ignore */ function wrs_mathmlEncode(input) { input = input.split(_wrs_xmlCharacters.tagOpener).join(_wrs_safeXmlCharacters.tagOpener); input = input.split(_wrs_xmlCharacters.tagCloser).join(_wrs_safeXmlCharacters.tagCloser); input = input.split(_wrs_xmlCharacters.doubleQuote).join(_wrs_safeXmlCharacters.doubleQuote); input = input.split(_wrs_xmlCharacters.ampersand).join(_wrs_safeXmlCharacters.ampersand); input = input.split(_wrs_xmlCharacters.quote).join(_wrs_safeXmlCharacters.quote); return input; } /** * Converts special symbols (> 128) to entities and replaces all textual entities by its number entities. * @param {string} mathml MathML string containing - or not - special symbols * @return {string} MathML with all textual entities replaced. * @ignore */ function wrs_mathmlEntities(mathml) { var toReturn = ''; for (var i = 0; i < mathml.length; ++i) { var character = mathml.charAt(i); // Parsing > 128 characters. if (mathml.charCodeAt(i) > 128) { toReturn += '&#' + mathml.charCodeAt(i) + ';'; } else if (character == '&') { var end = mathml.indexOf(';', i + 1); if (end >= 0) { var container = document.createElement('span'); container.innerHTML = mathml.substring(i, end + 1); toReturn += '&#' + wrs_fixedCharCodeAt((container.innerText || container.textContent),0) + ';'; i = end; } else { toReturn += character; } } else { toReturn += character; } } return toReturn; } /** * Add wrs::type attribute to mathml if the mathml has been created with a custom editor * for example, chemistry. * @param {string} mathml a MathML string created with a custom editor, like chemistry. * @return {string} The MathML string with his class containgin the editor toolbar string. * @ignore */ function wrs_mathmlAddEditorAttribute(mathml) { var toReturn = ''; var start = mathml.indexOf('<math'); if (start == 0 ) { end = mathml.indexOf('>'); if (mathml.indexOf("class") == -1 ) { // Adding custom editor type. toReturn = mathml.substr(start, end) + ' class="wrs_' + wrs_int_getCustomEditorEnabled().toolbar + '">'; toReturn += mathml.substr(end + 1, mathml.length); return toReturn; } } return mathml; } /** * Fix charCodeAt() javascript function to handle non-Basic-Multilingual-Plane characters. * @param {string} str String * @param {int} idx An integer greater than or equal to 0 and less than the length of the string * @return {int} An integer representing the UTF-16 code of the string at the given index. * @ignore */ function wrs_fixedCharCodeAt(str, idx) { idx = idx || 0; var code = str.charCodeAt(idx); var hi, low; /* High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters) */ if (0xD800 <= code && code <= 0xDBFF) { hi = code; low = str.charCodeAt(idx + 1); if (isNaN(low)) { throw 'High surrogate not followed by low surrogate in fixedCharCodeAt()'; } return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; } if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate. /* We return false to allow loops to skip this iteration since should have already handled high surrogate above in the previous iteration. */ return false; } return code; } /** * Gets the accessible text of a given MathML calling mathml2accesible service. * @param {string} mathml MathML to get the accesibility. * @param {string} language Language of the accesibility. * @return {string} Accessibility from mathml string on language string. * @ignore */ function wrs_mathmlToAccessible(mathml, language, data) { data['service'] = 'mathml2accessible'; return wrs_getContent(_wrs_conf_servicePath, data); } /** * Converts mathml to an iframe object. * @param {object} windowTarget Window object. * @param {string} mathml MathML to be converted. * @return {object} iframe object containging parsed mathml. * @ignore */ function wrs_mathmlToIframeObject(windowTarget, mathml) { if (window.navigator.userAgent.toLowerCase().indexOf('webkit') != -1) { // In WebKit, the formula is represented by a div instead of an iframe. var container = windowTarget.document.createElement('span'); container.className = _wrs_conf_imageClassName; container.setAttribute(_wrs_conf_imageMathmlAttribute, mathml); container.setAttribute('height', '1'); container.setAttribute('width', '1'); container.style.display = 'inline-block'; container.style.cursor = 'pointer'; container.style.webkitUserModify = 'read-only'; container.style.webkitUserSelect = 'all'; var formulaContainer = windowTarget.document.createElement('span'); formulaContainer.style.display = 'inline'; container.appendChild(formulaContainer); function waitForViewer() { if (windowTarget.com && windowTarget.com.wiris) { if (!('_wrs_viewer' in windowTarget)) { windowTarget._wrs_viewer = new windowTarget.com.wiris.jsEditor.JsViewerMain(_wrs_conf_pluginBasePath + '/integration/editor'); windowTarget._wrs_viewer.insertCSS(null, windowTarget.document); } windowTarget._wrs_viewer.paintFormulaOnContainer(mathml, formulaContainer, null); function prepareDiv() { if (windowTarget._wrs_viewer.isReady()) { container.style.height = formulaContainer.style.height; container.style.width = formulaContainer.style.width; container.style.verticalAlign = formulaContainer.style.verticalAlign; } else { setTimeout(prepareDiv, 100); } }; prepareDiv(); } else { setTimeout(waitForViewer, 100); } } if (!('_wrs_viewerAppended' in windowTarget)) { var viewerScript = windowTarget.document.createElement('script'); viewerScript.src = _wrs_conf_pluginBasePath + '/integration/editor/viewer.js'; windowTarget.document.getElementsByTagName('head')[0].appendChild(viewerScript); windowTarget._wrs_viewerAppended = true; } waitForViewer(); return container; } windowTarget.document.wrs_assignIframeEvents = function (myIframe) { wrs_addEvent(myIframe.contentWindow.document, 'click', function () { wrs_fireEvent(myIframe, 'dblclick'); }); }; var iframe = windowTarget.document.createElement('iframe'); iframe.className = _wrs_conf_imageClassName; iframe.setAttribute(_wrs_conf_imageMathmlAttribute, mathml); iframe.style.display = 'inline'; iframe.style.border = 'none'; iframe.setAttribute('height', '1'); iframe.setAttribute('width', '1'); iframe.setAttribute('scrolling', 'no'); iframe.setAttribute('frameBorder', '0'); iframe.src = _wrs_conf_pluginBasePath + '/core/iframe.html#' + _wrs_conf_imageMathmlAttribute; return iframe; } /** * Converts mathml to img object. * @param {object} creator Object with the "createElement" method * @param {string} mathml MathML code * @param {object} wirisProperties object containing WIRIS custom properties * @param {language} language Custom language for accesibility. * @return {object} And image containing the formula image corresponding to mathml string. * @ignore */ function wrs_mathmlToImgObject(creator, mathml, wirisProperties, language) { var width; var height; var baseline; var imgObject = creator.createElement('img'); imgObject.align = 'middle'; var data = (wirisProperties) ? wirisProperties : {}; if (window._wrs_conf_useDigestInsteadOfMathml && _wrs_conf_useDigestInsteadOfMathml) { data['returnDigest'] = 'true'; } data['mml'] = mathml; if (_wrs_conf_setSize) { // Request metrics of the generated image. data['metrics'] = 'true'; data['centerbaseline'] = 'false'; } // Full base64 method (edit & save). if (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'default') { data['base64'] = true; } // Render js params: _wrs_int_wirisProperties contains some js render params. Since mathml can support render params, js params should be send only to editor, not to render. imgObject.className = _wrs_conf_imageClassName; // TODO Custom Editors: class="wrs_toolbar" should be given by the editor // so the first condition shouldn't be longer necessary. if (customEditor = wrs_int_getCustomEditorEnabled()) { imgObject.setAttribute('data-custom-editor', customEditor.toolbar); } else if (mathml.indexOf('class="') != -1) { // We check here if the mathmnl has been created from a customEditor (such chemistry) // to add data-custom-editor attribute to img object (if necessary). mathmlSubstring = mathml.substring(mathml.indexOf('class="') + 'class="'.length, mathml.length); mathmlSubstring = mathmlSubstring.substring(0, mathmlSubstring.indexOf('"')); mathmlSubstring = mathmlSubstring.substring(4,mathmlSubstring.length); imgObject.setAttribute('data-custom-editor', mathmlSubstring); } // Experimental settings. if (_wrs_conf_wirisPluginPerformance && (_wrs_conf_saveMode == 'xml' || _wrs_conf_saveMode == 'safeXml')) { var result = JSON.parse(wrs_createShowImageSrc(mathml, data, language)); if (result["status"] == 'warning') { // POST call. result = JSON.parse(wrs_getContent(_wrs_conf_showimagePath, data)); } result = result.result; imgObject.src = result['format'] == 'svg' ? 'data:image/svg+xml;base64,' : 'data:image/png;base64,'; imgObject.src = imgObject.src + result["base64"]; imgObject.setAttribute(_wrs_conf_imageMathmlAttribute, wrs_mathmlEncode(mathml)); if (_wrs_conf_setSize) { wrs_setImgSize(imgObject,result, true); } if (window._wrs_conf_enableAccessibility && _wrs_conf_enableAccessibility) { if (typeof result.alt == 'undefined') { imgObject.alt = wrs_mathmlToAccessible(mathml, language, data); } else { imgObject.alt = result.alt; } } } else { var result = wrs_createImageSrc(mathml, data); if (window._wrs_conf_useDigestInsteadOfMathml && _wrs_conf_useDigestInsteadOfMathml) { var parts = result.split(':', 2); imgObject.setAttribute(_wrs_conf_imageMathmlAttribute, parts[0]); imgObject.src = parts[1]; } else { imgObject.setAttribute(_wrs_conf_imageMathmlAttribute, wrs_mathmlEncode(mathml)); imgObject.src = result; if (_wrs_conf_setSize) { wrs_setImgSize(imgObject,result, (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'default') ? true : false); } } if (window._wrs_conf_enableAccessibility && _wrs_conf_enableAccessibility) { imgObject.alt = wrs_mathmlToAccessible(mathml, language, data); } } /* if (_wrs_conf_setSize) { var ar = wrs_urlToAssArray(result); width = ar['cw']; height = ar['ch']; baseline = ar['cb']; dpi = ar['dpi']; if (dpi) { width = width * 96/dpi; height = height * 96/dpi; baseline = baseline * 96/dpi; } // result = wrs_assArrayToUrl(ar); }*/ if (typeof wrs_observer != 'undefined') { wrs_observer.observe(imgObject, wrs_observer_config); } // Role math https://www.w3.org/TR/wai-aria/roles#math. imgObject.setAttribute('role', 'math'); return imgObject; } /** * Opens a new CAS window. * @param {object} target The editable element * @param {boolean} isIframe Specifies if target is an iframe or not * @param {string} language CAS language. * @return {object} The opened window * @ignore */ function wrs_openCASWindow(target, isIframe, language) { if (isIframe === undefined) { isIframe = true; } _wrs_temporalRange = null; if (target) { var selectedItem = wrs_getSelectedItem(target, isIframe); if (selectedItem != null && selectedItem.caretPosition === undefined && selectedItem.node.nodeName.toUpperCase() == 'IMG' && selectedItem.node.className == _wrs_conf_CASClassName) { _wrs_temporalImage = selectedItem.node; _wrs_isNewElement = false; } } var path = _wrs_conf_CASPath; if (language) { path += '?lang=' + language; } return window.open(path, 'WIRISCAS', _wrs_conf_CASAttributes); } /** * Opens a new editor window. * @param {string} language Language code for the editor * @param {object} target The editable element * @param {boolean} isIframe Specifies if the target is an iframe or not * @param {boolean} isModal Specifies if the target is a modal window or not * @return {object} The opened window * @ignore */ function wrs_openEditorWindow(language, target, isIframe) { var ua = navigator.userAgent.toLowerCase(); var isAndroid = ua.indexOf("android") > -1; var isIOS = ((ua.indexOf("ipad") > -1) || (ua.indexOf("iphone") > -1)); if(isAndroid) { if (isIframe) { // Variable contentWindow have sense only on a iframe context. var selection = target.contentWindow.getSelection(); _wrs_androidRange = selection.getRangeAt(0); } _wrs_conf_modalWindow = true; // Conf property must be overrided on tablet/phone devices. } if(isIOS) { if (isIframe) { var selection = target.contentWindow.getSelection(); _wrs_iosRange = selection.getRangeAt(0); } _wrs_conf_modalWindow = true; // Conf property must be overrided on tablet/phone devices. } if (isIframe === undefined) { isIframe = true; } var path = _wrs_conf_path + "/core/editor.html"; if (language) { path = wrs_addArgument(path, "lang", language); } if (location.protocol == 'https:') { path = wrs_addArgument(path, "secure", "true"); } var availableDirs = new Array('rtl', 'ltr'); if (typeof _wrs_int_directionality != 'undefined' && wrs_arrayContains(availableDirs, _wrs_int_directionality) != -1){ path = wrs_addArgument(path,"dir",_wrs_int_directionality); } // Cross Domain Policy. wrs_addArgument(path, 'host', 'localhost'); _wrs_editMode = (window._wrs_conf_defaultEditMode) ? _wrs_conf_defaultEditMode : 'images'; _wrs_temporalRange = null; if (target) { var selectedItem = wrs_getSelectedItem(target, isIframe); if (selectedItem != null) { if (selectedItem.caretPosition === undefined) { if (wrs_containsClass(selectedItem.node, _wrs_conf_imageClassName)) { if (selectedItem.node.nodeName.toUpperCase() == 'IMG') { _wrs_editMode = 'images'; } else if (selectedItem.node.nodeName.toUpperCase() == 'IFRAME') { _wrs_editMode = 'iframes'; } _wrs_temporalImage = selectedItem.node; _wrs_isNewElement = false; } } else { var latexResult = wrs_getLatexFromTextNode(selectedItem.node, selectedItem.caretPosition); if (latexResult != null) { _wrs_editMode = 'latex'; var mathml = wrs_getMathMLFromLatex(latexResult.latex); _wrs_isNewElement = false; _wrs_temporalImage = document.createElement('img'); _wrs_temporalImage.setAttribute(_wrs_conf_imageMathmlAttribute, wrs_mathmlEncode(mathml)); var windowTarget = (isIframe) ? target.contentWindow : window; if (document.selection) { var leftOffset = 0; var previousNode = latexResult.startNode.previousSibling; while (previousNode) { leftOffset += wrs_getNodeLength(previousNode); previousNode = previousNode.previousSibling; } _wrs_temporalRange = windowTarget.document.selection.createRange(); _wrs_temporalRange.moveToElementText(latexResult.startNode.parentNode); _wrs_temporalRange.move('character', leftOffset + latexResult.startPosition); _wrs_temporalRange.moveEnd('character', latexResult.latex.length + 4); // Plus 4 for the '$$' characters. } else { _wrs_temporalRange = windowTarget.document.createRange(); _wrs_temporalRange.setStart(latexResult.startNode, latexResult.startPosition); _wrs_temporalRange.setEnd(latexResult.endNode, latexResult.endPosition); } } } } } if (!_wrs_conf_modalWindow) { _wrs_popupWindow = window.open(path, 'WIRISeditor', _wrs_conf_editorAttributes); return _wrs_popupWindow; } else { var deviceWidth = window.outerWidth; var deviceHeight = window.outerHeight; var landscape = deviceWidth > deviceHeight; var portrait = deviceWidth < deviceHeight; var iframeAttributes = {}; iframeAttributes['width'] = _wrs_conf_editorAttributes.split(' ').join('').split(',')[0].split("=")[1]; iframeAttributes['height'] = _wrs_conf_editorAttributes.split(' ').join('').split(',')[1].split("=")[1]; iframeAttributes['src'] = path; var isMobile = (landscape && iframeAttributes['height'] > deviceHeight) || (portrait && iframeAttributes['width'] > deviceWidth) ? true : false; // Device object properties. _wrs_deviceProperties['orientation'] = landscape ? 'landscape' : 'portait'; _wrs_deviceProperties['isAndroid'] = isAndroid ? true : false; _wrs_deviceProperties['isIOS'] = isIOS ? true : false; _wrs_deviceProperties['isMobile'] = isMobile; // Modal properties. var _wrs_modalProperties = { draggable : true }; wrs_createModalWindow('WIRIS editor', iframeAttributes, _wrs_deviceProperties, _wrs_modalProperties); } } /** * Converts all occurrences of mathml code to LATEX. The MathML code should containg <annotation encoding="LaTeX"/> to be converted. * @param {string} content A string containing MathML valid code. * @return {string} String with all MathML annotated occurrences replaced by the corresponding LaTeX code. * @ignore */ function wrs_parseMathmlToLatex(content, characters){ var output = ''; var mathTagBegin = characters.tagOpener + 'math'; var mathTagEnd = characters.tagOpener + '/math' + characters.tagCloser; var openTarget = characters.tagOpener + 'annotation encoding=' + characters.doubleQuote + 'LaTeX' + characters.doubleQuote + characters.tagCloser; var closeTarget = characters.tagOpener + '/annotation' + characters.tagCloser; var start = content.indexOf(mathTagBegin); var end = 0; var mathml, startAnnotation, closeAnnotation; while (start != -1) { output += content.substring(end, start); end = content.indexOf(mathTagEnd, start); if (end == -1) { end = content.length - 1; } else { end += mathTagEnd.length; } mathml = content.substring(start, end); startAnnotation = mathml.indexOf(openTarget); if (startAnnotation != -1){ startAnnotation += openTarget.length; closeAnnotation = mathml.indexOf(closeTarget); var latex = mathml.substring(startAnnotation, closeAnnotation); if (characters == _wrs_safeXmlCharacters) { latex = wrs_mathmlDecode(latex); } output += '$$' + latex + '$$'; // Populate latex into cache. wrs_populateLatexCache(latex, mathml); }else{ output += mathml; } start = content.indexOf(mathTagBegin, end); } output += content.substring(end, content.length); return output; } /** * Converts all occurrences of mathml code to the corresponding image. * @param {string} content An string with valid MathML code. * @param {object} characters An object containing xmlCharacters or safeXmlCharacters relation. * @param {string} language String containging a valid language code in order to generate formula accesibilty. * @return {string} The input string with all the MathML ocurrences replaced by the corresponding image. * @ignore */ function wrs_parseMathmlToImg(content, characters, language) { var output = ''; var mathTagBegin = characters.tagOpener + 'math'; var mathTagEnd = characters.tagOpener + '/math' + characters.tagCloser; var start = content.indexOf(mathTagBegin); var end = 0; while (start != -1) { output += content.substring(end, start); // Avoid WIRIS images to be parsed. imageMathmlAtrribute = content.indexOf(_wrs_conf_imageMathmlAttribute); end = content.indexOf(mathTagEnd, start); if (end == -1) { end = content.length - 1; } else if (imageMathmlAtrribute != -1) { // First close tag of img attribute // If a mathmlAttribute exists should be inside a img tag. end += content.indexOf("/>", start); } else { end += mathTagEnd.length; } if (!wrs_isMathmlInAttribute(content, start) && imageMathmlAtrribute == -1){ var mathml = content.substring(start, end); mathml = (characters == _wrs_safeXmlCharacters) ? wrs_mathmlDecode(mathml) : wrs_mathmlEntities(mathml); output += wrs_createObjectCode(wrs_mathmlToImgObject(document, mathml, null, language)); } else { output += content.substring(start, end); } start = content.indexOf(mathTagBegin, end); } output += content.substring(end, content.length); return output; } /** * Converts all occurrences of safe applet code to the corresponding code. * @param {string} content String containging valid applet code <APPLET>...</APPLET> * @return {string} String with all the applet code conerted to safe tags. * @ignore */ function wrs_parseSafeAppletsToObjects(content) { var output = ''; var appletTagBegin = _wrs_safeXmlCharacters.tagOpener + 'APPLET'; var appletTagEnd = _wrs_safeXmlCharacters.tagOpener + '/APPLET' + _wrs_safeXmlCharacters.tagCloser; var upperCaseContent = content.toUpperCase(); var start = upperCaseContent.indexOf(appletTagBegin); var end = 0; var applet; while (start != -1) { output += content.substring(end, start); end = upperCaseContent.indexOf(appletTagEnd, start); if (end == -1) { end = content.length - 1; } else { end += appletTagEnd.length; } applet = wrs_convertOldXmlinitialtextAttribute(content.substring(start, end)); output += wrs_mathmlDecode(applet); start = upperCaseContent.indexOf(appletTagBegin, end); } output += content.substring(end, content.length); return output; } /** * Cross-browser removeEventListener/detachEvent function. * @param {object} element Element target * @param {event} event Event * @param {function} func Function to run * @ignore */ function wrs_removeEvent(element, event, func) { if (element.removeEventListener) { element.removeEventListener(event, func, false); } else if (element.detachEvent) { element.detachEvent('on' + event, func); } } /** * Splits an HTML content in three parts: the code before <body>, the code between <body> and </body> and the code after </body>. * @param {string} code HTML code to be splited. * @return {objet} An object with the structure {'prefix': xxx, 'code': yyy, 'sufix': zzz} * @ignore */ function wrs_splitBody(code) { var prefix = ''; var sufix = ''; var bodyPosition = code.indexOf('<body'); if (bodyPosition != -1) { bodyPosition = code.indexOf('>', bodyPosition); if (bodyPosition != -1) { ++bodyPosition; var endBodyPosition = code.indexOf('</body>', bodyPosition); if (endBodyPosition == -1) { endBodyPosition = code.length; } prefix = code.substring(0, bodyPosition); sufix = code.substring(endBodyPosition, code.length); code = code.substring(bodyPosition, endBodyPosition); } } return { 'prefix': prefix, 'code': code, 'sufix': sufix }; } /** * Inserts or modifies CAS. * @param {object} focusElement Element to be focused * @param {object} windowTarget Window where the editable content is * @param {string} appletCode Applet code * @param {string} image Base 64 image stream * @param {int} imageWidth Image width * @param {int} imageHeight Image height * @ignore */ function wrs_updateCAS(focusElement, windowTarget, appletCode, image, imageWidth, imageHeight) { var imgObject = wrs_appletCodeToImgObject(windowTarget.document, appletCode, image, imageWidth, imageHeight); wrs_insertElementOnSelection(imgObject, focusElement, windowTarget); } var wrs_PluginEvent = function () { this.cancelled = false; this.defaultPrevented = false; } wrs_PluginEvent.prototype.cancel = function () { this.cancelled = true; } wrs_PluginEvent.prototype.preventDefault = function () { this.defaultPrevented = true; } /** * Fires one WIRIS event * @param {String} eventName event name * @param {Object} e event properties * @return {bool} false if event has been prevented. * @ignore */ function wrs_fireEvent(eventName, e) { for (var i = 0; i < wrs_pluginListeners.length && !e.cancelled; ++i) { if (wrs_pluginListeners[i][eventName]) { // Calling listener. wrs_pluginListeners[i][eventName](e); } } return e.defaultPrevented; } /** * Inserts or modifies formulas. * @param {object} focusElement Element to be focused * @param {object} windowTarget Window where the editable content is * @param {string} mathml Mathml code * @param {object} wirisProperties Extra attributes for the formula (like background color or font size). * @param {string} editMode Current edit mode. * @param {string} language Language for the formula. * @ignore */ function wrs_updateFormula(focusElement, windowTarget, mathml, wirisProperties, editMode, language) { // Before update listener. // Params on beforeUpdate listener // - mathml // - editMode (read only) // - wirisProperties // - language (read only). var e = new wrs_PluginEvent(); e.mathml = mathml; // Cloning wirisProperties object // We don't want wirisProperties object modified. e.wirisProperties = {}; for (var attr in wirisProperties) { e.wirisProperties[attr] = wirisProperties[attr]; } // Read only. e.language = language; e.editMode = editMode; if (wrs_fireEvent('onBeforeFormulaInsertion', e)) { return; } mathml = e.mathml; wirisProperties = e.wirisProperties; // Setting empty params for after. e = new wrs_PluginEvent(); e.editMode = editMode; e.windowTarget = windowTarget; e.focusElement = focusElement; if (mathml.length == 0) { wrs_insertElementOnSelection(null, focusElement, windowTarget); } else if (editMode == 'latex') { e.latex = wrs_getLatexFromMathML(mathml); e.node = windowTarget.document.createTextNode('$$' + e.latex + '$$'); wrs_populateLatexCache(e.latex, mathml); wrs_insertElementOnSelection(e.node, focusElement, windowTarget); } else if (editMode == 'iframes') { var iframe = wrs_mathmlToIframeObject(windowTarget, mathml); wrs_insertElementOnSelection(iframe, focusElement, windowTarget); } else { e.node = wrs_mathmlToImgObject(windowTarget.document, mathml, wirisProperties, language); wrs_insertElementOnSelection(e.node, focusElement, windowTarget); } if (wrs_fireEvent('onAfterFormulaInsertion', e)) { return; } } /** * Inserts or modifies formulas or CAS on a textarea. * @param {object} textarea Target * @param {string} text Text to add in the textarea. For example, if you want to add the link to the image, you can call this function as wrs_updateTextarea(textarea, wrs_createImageSrc(mathml)); * @ignore */ function wrs_updateTextarea(textarea, text) { if (textarea && text) { textarea.focus(); if (textarea.selectionStart != null) { textarea.value = textarea.value.substring(0, textarea.selectionStart) + text + textarea.value.substring(textarea.selectionEnd, textarea.value.length); } else { var selection = document.selection.createRange(); selection.text = text; } } } /** * URL decode function. * @param {string} input String to be decoded * @return {string} decode string. * @ignore */ function wrs_urldecode(input) { return decodeURIComponent(input); } /** * URL encode function. * @param {string} clearString Input string to be encoded * @return {string} encoded string. * @ignore */ function wrs_urlencode(clearString) { var output = ''; // Method encodeURIComponent doesn't encode !'()*~ . output = encodeURIComponent(clearString).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/~/g, '%7E'); return output; } function wrs_addArgument(path,key,value) { if (path.indexOf("?") > 0) { sep = "&"; } else { sep = "?"; } return path + sep + key + "=" + value; } function wrs_urlToAssArray(url) { var i; i = url.indexOf("?"); if (i > 0) { var query = url.substring(i + 1); var ss = query.split("&"); var h = new Object(); for (i = 0; i < ss.length; i++) { var s = ss[i]; var kv = s.split("="); if (kv.length > 1) { h[kv[0]] = decodeURIComponent(kv[1].replace(/\+/g, ' ')); } } return h; } else { return new Object(); } } function wrs_setImgSize(img, url, base64) { if (base64) { // Cleaning data:image/png;base64. var base64String = img.src.substr( img.src.indexOf('base64,') + 7, img.src.length); if (_wrs_conf_imageFormat == 'svg') { var ar = getMetricsFromSvgString(atob(base64String)); } else { bytes = wrs_b64ToByteArray(base64String, 88); var ar = wrs_getMetricsFromBytes(bytes); } } else { var ar = wrs_urlToAssArray(url); } var width = ar['cw']; if (!width) { return; } var height = ar['ch']; var baseline = ar['cb']; var dpi = ar['dpi']; if (dpi) { width = width * 96 / dpi; height = height * 96 / dpi; baseline = baseline * 96 / dpi; } img.width = width; img.height = height; img.style.verticalAlign = "-" + (height - baseline) + "px"; } function wrs_fixAfterResize(img) { img.removeAttribute('style'); img.removeAttribute('width'); img.removeAttribute('height'); if (_wrs_conf_setSize) { if (img.src.indexOf("base64") != -1) { wrs_setImgSize(img,'', true); } else { wrs_setImgSize(img,img.src); } } } function wrs_initSetSize() { // Override _wrs_conf_setSize to align formulas when xml or safeXml mode are enabled. _wrs_conf_setSize = _wrs_conf_setSize || _wrs_conf_saveMode == 'xml' || _wrs_conf_saveMode == 'safeXml' || (_wrs_conf_saveMode == 'base64' && _wrs_conf_editMode == 'default'); } function wrs_loadConfiguration() { if (typeof _wrs_conf_path == 'undefined') { // Discover path. var scriptName = "core/core.js"; var col = document.getElementsByTagName("script"); for (i = 0; i < col.length; i++) { var d; var src; d = col[i]; src = d.src; var j = src.lastIndexOf(scriptName); if (j >= 0) { // That's my script! baseURL = src.substr(0, j - 1); } } _wrs_conf_path = baseURL; } var script = document.createElement('script'); script.type = 'text/javascript'; // Sometimes _wrs_conf_path contains a final "/" because is obtained using some editor's API. // With this variable we avoid URL's with doubles //. var newConfPath = _wrs_conf_path.lastIndexOf("/") == _wrs_conf_path.length - 1 ? _wrs_conf_path + _wrs_int_conf_file : _wrs_conf_path + "/" + _wrs_int_conf_file; var configUrl = _wrs_int_conf_file.indexOf("/") == 0 || _wrs_int_conf_file.indexOf("http") == 0 ? _wrs_int_conf_file : newConfPath; script.src = configUrl; document.getElementsByTagName('head')[0].appendChild(script); // Asynchronous load of configuration. } var _wrs_conf_core_loaded = true; if (typeof _wrs_conf_configuration_loaded == 'undefined') { wrs_loadConfiguration(); } else { _wrs_conf_plugin_loaded = true; } /** * Create modal window with embebbed iframe * * @param {string} title Modal window title * @param {object} iframeParams iframe attributes * @param {object} deviceProperties device properties like orientation, OS.. * @param {object} modalProperites modal properties (like draggable). * @ignore */ function wrs_createModalWindow(title, iframeParams, deviceProperties, modalProperties) { // Adding css stylesheet. var fileref = document.createElement("link"); fileref.setAttribute("rel", "stylesheet"); fileref.setAttribute("type", "text/css"); fileref.setAttribute("href", window.parent._wrs_conf_path + '/core/modal.css'); document.getElementsByTagName("head")[0].appendChild(fileref); var attributes = {}; attributes['class'] = 'wrs_modal_overlay'; var modalDiv = wrs_createElement('div', attributes); attributes['class'] = 'wrs_modal_title_bar'; var barModalDiv = wrs_createElement('div', attributes); attributes = {}; attributes['class'] = 'wrs_modal_title'; var titleModalDiv = wrs_createElement('div', attributes); titleModalDiv.innerHTML = title; attributes = {}; attributes['class'] = 'wrs_modal_close_button' var closeDiv = wrs_createElement('div', attributes); closeDiv.innerHTML = "X"; attributes = {}; attributes['class'] = 'wrs_modal_dialogContainer'; var containerDiv = wrs_createElement('div', attributes); containerDiv.style.overflow = 'hidden'; attributes = {}; attributes['class'] = 'wrs_modal_iframe'; attributes['src'] = iframeParams['src']; attributes['frameBorder'] = "0"; var iframe = wrs_createElement('iframe', attributes); barModalDiv.appendChild(closeDiv); barModalDiv.appendChild(titleModalDiv); modalDiv.appendChild(containerDiv); if (!deviceProperties['isMobile']) { containerDiv.appendChild(barModalDiv); } containerDiv.appendChild(iframe); document.body.className = !(document.body.className) ? "wrs_modal_open" : document.body.className + " wrs_modal_open"; if (!deviceProperties['isMobile'] && !deviceProperties['isIOS'] && !deviceProperties['isAndroid']) { // Desktop. wrs_createModalWindowDesktop(modalDiv, containerDiv, iframe, iframeParams); } else if (deviceProperties['isAndroid'] && !deviceProperties['isMobile']) { wrs_createModalWindowAndroid(modalDiv, containerDiv, iframe, iframeParams); } else if (deviceProperties['isIOS'] && !deviceProperties['isMobile']) { wrs_createModalWindowIos(modalDiv, containerDiv, iframe, iframeParams); } else if (deviceProperties['isMobile']) { if (!wrs_isBadStockAndroid()) { wrs_createModalWindowMobile(modalDiv, containerDiv, iframe, iframeParams); } else { wrs_createModalWindowBadStockAndroid(modalDiv, containerDiv, iframe, iframeParams); } } document.body.appendChild(modalDiv); if (modalProperties.draggable) { wrs_addModalListeners(); } wrs_addEvent(closeDiv, 'click', function() { wrs_closeModalWindow(); }); _wrs_popupWindow = iframe.contentWindow; } /** * Makes an object draggable adding mouse and touch events. * * @param {object} draggable object (for example modal dialog). * @param {target} target to add the events (for example de titlebar of a modal dialog) * @ignore */ function wrs_addModalListeners(object, target) { _wrs_dragObject = document.getElementsByClassName('wrs_modal_dialogContainer')[0]; // Mouse events. wrs_addEvent(document.body, 'mousedown', wrs_startDrag); wrs_addEvent(window, 'mouseup', wrs_stopDrag); wrs_addEvent(document, 'mouseup', wrs_stopDrag); wrs_addEvent(document.getElementsByClassName("wrs_modal_iframe")[0], 'mouseup', wrs_stopDrag); wrs_addEvent(document.body, 'mousemove', wrs_drag); // Touch Events. // Don't add touch events on modal window for mobile. if (typeof(document.getElementsByClassName('wrs_modal_title')[0]) != 'undefined') { wrs_addEvent(document.getElementsByClassName('wrs_modal_title')[0], 'touchstart', wrs_startDrag); wrs_addEvent(document.body, 'touchmove', wrs_drag); wrs_addEvent(window, 'touchend', wrs_stopDrag); } } /** * Returns mouse or touch coordinates (on touch events ev.ClientX doesn't exists) * @param {event} ev mnouse or touch event * @return {object} with the X and Y coordinates. * @ignore */ function wrs_eventClient(ev) { if (typeof(ev.clientX) == 'undefined') { var client = { X : ev.changedTouches[0].clientX, Y : ev.changedTouches[0].clientY }; return client; } else { client = { X : ev.clientX, Y : ev.clientY }; return client; } } /** * Start drag function: set the object _wrs_dragDataObject with the draggable object offsets coordinates. * when drag starts (on touchstart or mousedown events). * * @param {event} ev touchstart or mousedown event. * @ignore */ function wrs_startDrag(ev) { if (ev.target.className == 'wrs_modal_title') { if(!_wrs_dragDataObject) { ev = ev || event; _wrs_dragDataObject = { x: wrs_eventClient(ev).X - (isNaN(parseInt(window.getComputedStyle(_wrs_dragObject)).left && parseInt(window.getComputedStyle(_wrs_dragObject).left > 0 )) ? _wrs_dragObject.offsetLeft : parseInt(window.getComputedStyle(_wrs_dragObject).left)), y: wrs_eventClient(ev).Y - (isNaN(parseInt(window.getComputedStyle(_wrs_dragObject).top)) ? _wrs_dragObject.offsetTop : parseInt(window.getComputedStyle(_wrs_dragObject).top)) }; }; } } /** * Updates_wrs_dragDataObject with the draggable object coordinates when the draggable object is being moved. * * @param {event} ev touchmouve or mousemove events. * @ignore */ function wrs_drag(ev) { if(_wrs_dragDataObject) { ev.preventDefault(); ev = ev || event; _wrs_dragObject.style.left = wrs_eventClient(ev).X - _wrs_dragDataObject.x + "px"; _wrs_dragObject.style.top = wrs_eventClient(ev).Y - _wrs_dragDataObject.y + "px"; _wrs_dragObject.style.position = 'absolute'; } } /** * Set the _wrs_dragDataObject to null when the drag finish (touchend or mouseup events). * * @param {event} ev touchend or mouseup event. * @ignore */ function wrs_stopDrag(ev) { _wrs_dragDataObject = null; } /** * Create modal dialog for desktop OS. * @param {modalDiv} modal overlay div. * @param {containerDiv} modal window div. * @param {iframe} embedded iframe. * @param {iframeParams} embedded iframe params (height, width). * @ignore */ function wrs_createModalWindowDesktop(modalDiv, containerDiv, iframe, iframeParams) { modalDiv.className = modalDiv.className + " wrs_modal_desktop"; containerDiv.className = containerDiv.className + " wrs_modal_desktop"; iframe.className = iframe.className + " wrs_modal_android" var modalHeight = parseInt(iframeParams['height']) + 30; var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = modalWidth + 'px'; containerDiv.style.height = modalHeight + 'px'; iframe.style.width = iframeParams['width'] + 'px'; iframe.style.height = iframeParams['height'] + 'px'; iframe.style.margin = '6px'; } /** * Create modal dialog for non mobile android devices. * @param {modalDiv} modal overlay div. * @param {containerDiv} modal window div. * @param {iframe} embedded iframe. * @param {iframeParams} embedded iframe params (height, width). * @ignore */ function wrs_createModalWindowAndroid(modalDiv, containerDiv, iframe, iframeParams) { modalDiv.className = modalDiv.className + " wrs_modal_android"; containerDiv.className = containerDiv.className + " wrs_modal_android"; iframe.className = iframe.className + " wrs_modal_android"; // Android portrait. if (window.outerWidth < window.outerHeight) { var modalHeight = parseInt(iframeParams['height']) + 30; var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = modalWidth + 'px'; containerDiv.style.height = modalHeight + 'px'; iframe.style.width = iframeParams['width'] + 'px'; iframe.style.height = iframeParams['height'] + 'px'; } else { var modalHeight = parseInt(iframeParams['height']) + 30; var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = modalWidth + 'px'; containerDiv.style.height = modalHeight + 'px'; iframe.style.width = iframeParams['width'] + 'px'; iframe.style.height = iframeParams['height'] + 'px'; iframe.style.margin = '6px'; } if (window.outerWidth < window.outerHeight) { var portraitZoom = (window.outerWidth / modalWidth).toFixed(2); wrs_addMetaViewport("device-width", portraitZoom, portraitZoom, portraitZoom); } else { wrs_addMetaViewport("device-width", 1.0, 1.0, 1.0); } window.addEventListener('orientationchange', function() { if (window.outerWidth > window.outerHeight) { // Portrait --> landscape. wrs_addMetaViewport("device-width", 1.0, 1.0, 1.0); } else { // Landscape --> portrait. var portraitZoom = (window.outerWidth / modalWidth).toFixed(2); wrs_addMetaViewport("device-width", portraitZoom, portraitZoom, portraitZoom); } }); } /** * Create modal dialog for non mobile iOS devices. * @param {modalDiv} modal overlay div. * @param {containerDiv} modal window div. * @param {iframe} embedded iframe. * @param {iframeParams} embedded iframe params (height, width). * @ignore */ function wrs_createModalWindowIos(modalDiv, containerDiv, iframe, iframeParams) { modalDiv.className = modalDiv.className + " wrs_modal_ios"; if (typeof _wrs_isMoodle24 != 'undefined') { modalDiv.className = modalDiv.className + " moodle"; } containerDiv.className = containerDiv.className + " wrs_modal_ios"; iframe.className = iframe.className + " wrs_modal_ios"; wrs_addMetaViewport("device-width", 1.0, 1.0, 1.0); var modalHeight = parseInt(iframeParams['height']) + 30; var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = modalWidth + 'px'; containerDiv.style.height = modalHeight + 'px'; iframe.style.width = iframeParams['width'] + 'px'; iframe.style.height = iframeParams['height'] + 'px'; } /** * Create modal dialog for mobile devices. * * @param {modalDiv} modal overlay div. * @param {containerDiv} modal window div. * @param {iframe} embedded iframe. * @param {iframeParams} embedded iframe params (height, width). * @ignore */ function wrs_createModalWindowMobile(modalDiv, containerDiv, iframe, iframeParams) { modalDiv.className = modalDiv.className + " wrs_modal_mobile"; containerDiv.className = containerDiv.className + " wrs_modal_mobile"; iframe.className = iframe.className + " wrs_modal_mobile"; wrs_addMetaViewport("device-width", 1.0, 1.0, 1.0); var modalTitleBar = document.getElementsByClassName('wrs_modal_title')[0] if (modalTitleBar) { document.removeChild(modalTitleBar); } } /** * Create modal dialog for Androir mobile devices with an old stock browser (<=4.3). * * @param {modalDiv} modal overlay div. * @param {containerDiv} modal window div. * @param {iframe} embedded iframe. * @param {iframeParams} embedded iframe params (height, width). * @ignore */ function wrs_createModalWindowBadStockAndroid(modalDiv, containerDiv, iframe, iframeParams) { modalDiv.className = modalDiv.className + " wrs_modal_badStock"; containerDiv.className = containerDiv.className + " wrs_modal_badStock"; iframe.className = iframe.className + " wrs_modal_badStock"; if (window.outerWidth < parseInt(iframeParams['width'])) { var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = iframeParams['width'] + 'px'; iframe.style.width = iframeParams['width'] + 'px'; } window.addEventListener('orientationchange', function() { if (window.outerWidth > parseInt(iframeParams['width']) + 10) { var modalWidth = parseInt(iframeParams['width']) + 10; containerDiv.style.width = modalWidth + 'px'; iframe.style.width = iframeParams['width'] + 'px'; } else { containerDiv.style.width = null; iframe.style.width = null; } }); wrs_addMetaViewport("device-width", 1.0, 1.0, 1.0); } /** * Add viewport header for scale control. * * @param {int} width width of the layout viewport. * @param {int} initialScale Sets the initial zoom of the page and the width of the layout viewport. * @param {int} minimumScale Sets the minimum zoom level (i.e. how much the user can zoom out). * @param {int} maximumScale Sets the maximum zoom level (i.e. how much the user can zoom in). * @ignore */ function wrs_addMetaViewport(width, initialScale, minimumScale, maximumScale) { _wrs_originalMetaViewport = document.querySelector('meta[name=viewport]') ? document.querySelector('meta[name=viewport]').content : null; if (_wrs_originalMetaViewport) { document.querySelector('meta[name=viewport]').content = "width=" + width + ", initial-scale=" + initialScale + ", minimum-scale=" + minimumScale + ", maximum-scale=" + maximumScale; } else { var attributes = {}; attributes['name'] = 'viewport'; attributes['content'] = "width=" + width + ", initial-scale=" + initialScale + ", minimum-scale=" + minimumScale + ", maximum-scale=" + maximumScale; var meta = wrs_createElement('meta', attributes); document.getElementsByTagName("head")[0].appendChild(meta); } } /** * Closes modal window and restores viewport header. * @ignore */ function wrs_closeModalWindow() { if (document.querySelector('meta[name=viewport]')) { document.querySelector('meta[name=viewport]').content = ""; } document.body.className = document.body.className != 'wrs_modal_open' ? document.body.className.replace(' wrs_modal_open', '') : document.body.className = "" var modalDiv = document.getElementsByClassName('wrs_modal_overlay')[0]; closeFunction = document.body.removeChild(modalDiv); } /** * Android stock browser test * http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai * * @return {Boolean} true if user agent is from an Android stock browser (<= 4.3) * @ignore */ function wrs_isBadStockAndroid () { var userAgent = window.navigator.userAgent; // Android stock browser test derived from // http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai. var isAndroid = userAgent.indexOf(' Android ') > -1; if (!isAndroid) { return false; } var isStockAndroid = userAgent.indexOf('Version/') > -1; if (!isStockAndroid) { return false; } var versionNumber = parseFloat((userAgent.match('Android ([0-9.]+)') || [])[1]); // Anything below 4.4 uses WebKit without *any* viewport support. return versionNumber <= 4.3; } /** * Populates LaTeX cache into _wrs_int_LatexCache global variable. * * @param {string}latex LaTeX code (with $$ separators) * @param {string} mathml matml LaTeX translation. * @ignore */ function wrs_populateLatexCache(latex, mathml) { if (mathml.indexOf('semantics') == -1 && mathml.indexOf('annotation') == -1 ) { mathml = wrs_insertSemanticsMathml(mathml, latex); } if (!_wrs_int_LatexCache.hasOwnProperty(latex)) { _wrs_int_LatexCache[latex] = mathml; } } /** * Add annotation tag to mathml without it (mathml comes from LaTeX string) * @param {string} mathml MathML code generated by a LaTeX string. * @param {string} latex Original LaTeX string * @return {string} new mathml containing LaTeX code on annotation tag. * @ignore */ function wrs_insertSemanticsMathml(mathml, latex) { var firstEndTag = '>'; var mathTagEnd = '<' + '/math' + '>'; var openSemantics = '<' + 'semantics' + '>'; var closeSemantics = '<' + '/semantics' + '>'; var openTarget = '<annotation encoding="LaTeX">'; var closeTarget = '<' + '/annotation' + '>'; var mrowOpen = '<mrow>'; var mrowClose = '</mrow>'; var indexMathBegin = mathml.indexOf(firstEndTag); var indexMathEnd = mathml.indexOf(mathTagEnd); var mathBeginExists = mathml.substring(mathml.indexOf('<'), mathml.indexOf('>')).indexOf('math'); if (indexMathBegin != -1 && indexMathEnd != -1 && mathBeginExists) { var mathmlContent = mathml.substring(indexMathBegin + 1, indexMathEnd); if (mathmlContent.indexOf(mrowOpen) != 0) { var mathmlContentSemantics = openSemantics + mrowOpen + mathmlContent + mrowClose + openTarget + latex + closeTarget + closeSemantics; } else { var mathmlContentSemantics = openSemantics + mathmlContent + openTarget + latex + closeTarget + closeSemantics; } return mathml.replace(mathmlContent, mathmlContentSemantics); } else { return mathml; } } /** * Transform html img tags inside a html code to mathml, base64 img tags (i.e with base64 on src) or showimage img tags (i.e with showimage.php on src) * * @param {String} code html code * @param {String} mode base642showimage or img2mathml or img264 transform. * @return {String} html code transformed. * @ignore */ function wrs_codeImgTransform(code, mode) { output = ''; var endPosition = 0; var pattern = /<img/gi; var patternLength = pattern.source.length; while (pattern.test(code)) { var startPosition = pattern.lastIndex - patternLength; output += code.substring(endPosition, startPosition); var i = startPosition + 1; while (i < code.length && endPosition <= startPosition) { var character = code.charAt(i); if (character == '"' || character == '\'') { var characterNextPosition = code.indexOf(character, i + 1); if (characterNextPosition == -1) { i = code.length; // End while. } else { i = characterNextPosition; } } else if (character == '>') { endPosition = i + 1; } ++i; } if (endPosition < startPosition) { // The img tag is stripped. output += code.substring(startPosition, code.length); return output; } var imgCode = code.substring(startPosition, endPosition); var imgObject = wrs_createObject(imgCode); var xmlCode = imgObject.getAttribute(_wrs_conf_imageMathmlAttribute); if (mode == 'base642showimage') { if (xmlCode == null) { xmlCode = imgObject.getAttribute('alt'); } xmlCode = wrs_mathmlDecode(xmlCode); imgCode = wrs_mathmlToImgObject(document, xmlCode, null, null); output += wrs_createObjectCode(imgCode); } else if (mode == 'img2mathml') { if (window._wrs_conf_saveMode) { if (_wrs_conf_saveMode == 'safeXml') { convertToXml = true; convertToSafeXml = true; } else if (_wrs_conf_saveMode == 'xml') { convertToXml = true; convertToSafeXml = false; } } output += wrs_getWIRISImageOutput(imgCode, convertToXml, convertToSafeXml); } else if (mode == 'img264') { if (xmlCode == null) { xmlCode = imgObject.getAttribute('alt'); } xmlCode = wrs_mathmlDecode(xmlCode); var properties = {}; properties['base64'] = 'true'; imgCode = wrs_mathmlToImgObject(document, xmlCode, properties, null) // Metrics. wrs_setImgSize(imgCode, imgCode.src, true); output += wrs_createObjectCode(imgCode); } } output += code.substring(endPosition, code.length); return output; } /** * Decode a base64 to its numeric value * * @param {String} el base64 character. * @return {int} base64 char numeric value. * @ignore */ function wrs_decode64(el) { var PLUS = '+'.charCodeAt(0); var SLASH = '/'.charCodeAt(0); var NUMBER = '0'.charCodeAt(0); var LOWER = 'a'.charCodeAt(0); var UPPER = 'A'.charCodeAt(0); var PLUS_URL_SAFE = '-'.charCodeAt(0); var SLASH_URL_SAFE = '_'.charCodeAt(0); var code = el.charCodeAt(0); if (code === PLUS || code === PLUS_URL_SAFE) { return 62; // Char '+'. } if (code === SLASH || code === SLASH_URL_SAFE){ return 63 // Char '/'. } if (code < NUMBER){ return -1 // No match. } if (code < NUMBER + 10){ return code - NUMBER + 26 + 26 } if (code < UPPER + 26){ return code - UPPER } if (code < LOWER + 26){ return code - LOWER + 26 } } /** * Converts a base64 string to a array of bytes. * @param {String} b64String base64 string. * @param {int} len dimension of byte array (by default whole string). * @return {Array} Byte array. * @ignore */ function wrs_b64ToByteArray(b64String, len) { var tmp; if (b64String.length % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4'); // Tipped base64. Length is fixed. } var arr = new Array() if (!len) { // All b64String string. var placeHolders = b64String.charAt(b64String.length - 2) === '=' ? 2 : b64String.charAt(b64String.length - 1) === '=' ? 1 : 0 var l = placeHolders > 0 ? b64String.length - 4 : b64String.length; } else { var l = len; } for (var i = 0; i < l; i += 4) { // Ignoring code checker standards (bitewise operators). // See https://tracker.moodle.org/browse/CONTRIB-5862 for further information. // @codingStandardsIgnoreStart tmp = (wrs_decode64(b64String.charAt(i)) << 18) | (wrs_decode64(b64String.charAt(i + 1)) << 12) | (wrs_decode64(b64String.charAt(i + 2)) << 6) | wrs_decode64(b64String.charAt(i + 3)); arr.push((tmp >> 16) & 0xFF); arr.push((tmp >> 8) & 0xFF); arr.push(tmp & 0xFF); // @codingStandardsIgnoreEnd } if (placeHolders) { if (placeHolders === 2) { // Ignoring code checker standards (bitewise operators). // @codingStandardsIgnoreStart tmp = (wrs_decode64(b64String.charAt(i)) << 2) | (wrs_decode64(b64String.charAt(i + 1)) >> 4); arr.push(tmp & 0xFF) } else if (placeHolders === 1) { tmp = (wrs_decode64(b64String.charAt(i)) << 10) | (wrs_decode64(b64String.charAt(i + 1)) << 4) | (wrs_decode64(b64String.charAt(i + 2)) >> 2) arr.push((tmp >> 8) & 0xFF); arr.push(tmp & 0xFF); // @codingStandardsIgnoreEnd } } return arr } /** * Returns the first 32-bit signed integer from a byte array. * @param {Array} bytes array of bytes. * @return {int} 32-bit signed integer. * @ignore */ function wrs_readInt32(bytes) { if (bytes.length < 4) { return false; } var int32 = bytes.splice(0,4); // @codingStandardsIgnoreStart return (int32[0] << 24 | int32[1] << 16 | int32[2] << 8 | int32[3] << 0); // @codingStandardsIgnoreEnd } /** * Read the first byte from a byte array. * @param {array} bytes byte array. * @return {int} first byte of the byte array. * @ignore */ function wrs_readByte(bytes) { // @codingStandardsIgnoreStart return bytes.shift() << 0; // @codingStandardsIgnoreEnd } /** * Read an arbitrary number of bytes, from a fixed position on a byte array. * @param {array} bytes byte array. * @param {int} post start position. * @param {int} len number of bytes to read. * @return {array} byte array. * @ignore */ function wrs_readBytes(bytes, pos, len) { return bytes.splice(pos, len); } /** * Get metrics (width, height, baseline and dpi) from a png's byte array. * @param {array} bytes png byte array. * @return {array} An array containging the png's metrics. * @ignore */ function wrs_getMetricsFromBytes(bytes) { wrs_readBytes(bytes, 0, 8); alloc = 10; i = 0; while (bytes.length >= 4) { len = wrs_readInt32(bytes); typ = wrs_readInt32(bytes); if (typ == 0x49484452) { width = wrs_readInt32(bytes); height = wrs_readInt32(bytes); // Read 5 bytes. wrs_readInt32(bytes); wrs_readByte(bytes); } else if (typ == 0x62615345) { // Baseline: 'baSE'. baseline = wrs_readInt32(bytes); } else if (typ == 0x70485973) { // Dpis: 'pHYs'. dpi = wrs_readInt32(bytes); dpi = (Math.round(dpi / 39.37)); wrs_readInt32(bytes); wrs_readByte(bytes); } wrs_readInt32(bytes); } if (typeof width != 'undefined') { var arr = new Array(); arr['cw'] = width; arr['ch'] = height; arr['dpi'] = dpi; if (baseline) { arr['cb'] = baseline; } return arr; } } function getMetricsFromSvgString(svgString) { var first = svgString.indexOf('height="'); var last = svgString.indexOf('"',first + 8, svgString.length); var height = svgString.substring(first + 8, last); first = svgString.indexOf('width="'); last = svgString.indexOf('"',first + 7, svgString.length); var width = svgString.substring(first + 7, last); first = svgString.indexOf('wrs:baseline="'); last = svgString.indexOf('"',first + 14, svgString.length); var baseline = svgString.substring(first + 14, last); if (typeof(width != 'undefined')) { var arr = new Array(); arr['cw'] = width; arr['ch'] = height; if (typeof baseline != 'undefined') { arr['cb'] = baseline } return arr; } } /** * Get custom active editor * @ignore */ function wrs_int_getCustomEditorEnabled() { var customEditorEnabled = null; Object.keys(_wrs_int_customEditors).forEach(function(key) { if (_wrs_int_customEditors[key].enabled) { customEditorEnabled = _wrs_int_customEditors[key] } }); return customEditorEnabled; } /** * Disable all custom editors * @ignore */ function wrs_int_disableCustomEditors(){ Object.keys(_wrs_int_customEditors).forEach(function(key) { _wrs_int_customEditors[key].enabled = false; }); } /** * Enable a custom editor * @param {string} editor a custom editor to be enabled * @ignore */ function wrs_int_enableCustomEditor(editor) { // Only one custom editor enabled at the same time. wrs_int_disableCustomEditors(); if (_wrs_int_customEditors[editor]) { _wrs_int_customEditors[editor].enabled = true; } } /** * Convert a hash to string sorting keys to get a deterministic output * @param {hash} h a key-value hash * @return{string} A string with the form key1=value1...keyn=valuen * @ignore */ function wrs_propertiesToString(h) { // 1. Sort keys. We sort the keys because we want a deterministic output. var keys = [] for (var key in h) { if (h.hasOwnProperty(key)) { keys.push(key); } } var n = keys.length; for (var i = 0; i < n; i++) { for (var j = i + 1; j < n; j++) { var s1 = keys[i]; var s2 = keys[j]; if (wrs_compareStrings(s1,s2) > 0) { // Swap. keys[i] = s2; keys[j] = s1; } } } // 2. Generate output. var output = ''; for (var i = 0; i < n; i++) { var key = keys[i]; output += key; output += "="; var value = h[key]; value = value.replace("\\", "\\\\"); value = value.replace("\n", "\\n"); value = value.replace("\r", "\\r"); value = value.replace("\t", "\\t"); output += value; output += "\n"; } return output; } /** * Compare two strings using charCodeAt method * @param {string} a first string to compare. * @param {string} b second string to compare * @return {int} the int difference between a and b * @ignore */ function wrs_compareStrings(a, b){ var i; var an = a.length; var bn = b.length; var n = (an > bn) ? bn : an; for(i = 0; i < n; i++){ var c = wrs_fixedCharCodeAt(a,i) - wrs_fixedCharCodeAt(b,i); if(c != 0) { return c; } } return a.length - b.length; } // Polyfills. if (!Object.keys) { Object.keys = (function () { 'use strict'; var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function (obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } var result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }()); } /** * Add a new callback to a WIRIS plugins listener. * @param {object} listener an Object containing listener name and a callback. */ function wrs_addPluginListener(listener) { wrs_pluginListeners.push(listener); } // Production steps of ECMA-262, Edition 5, 15.4.4.18 // Reference: http://es5.github.io/#x15.4.4.18. if (!Array.prototype.forEach) { Array.prototype.forEach = function(callback, thisArg) { var T, k; if (this == null) { throw new TypeError(' this is null or not defined'); } // 1. Let O be the result of calling ToObject passing the |this| value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". // 3. Let len be ToUint32(lenValue). // @codingStandardsIgnoreStart var len = O.length >>> 0; // @codingStandardsIgnoreEnd // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 . if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 1) { T = thisArg; } // 6. Let k be 0. k = 0; // 7. Repeat, while k < len. while (k < len) { var kValue; // A. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // B. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk // This step can be combined with c // C. If kPresent is true. if (k in O) { // I. Let kValue be the result of calling the Get internal method of O with argument Pk. kValue = O[k]; // II. Call the Call internal method of callback with T as the this value and // argument list containing kValue, k, and O. callback.call(T, kValue, k, O); } // D. Increase k by 1. k++; } // 8. return undefined. }; } // @codingStandardsIgnoreStart (function(){ var HxOverrides = function() { } HxOverrides.__name__ = true; HxOverrides.dateStr = function(date) { var m = date.getMonth() + 1; var d = date.getDate(); var h = date.getHours(); var mi = date.getMinutes(); var s = date.getSeconds(); return date.getFullYear() + "-" + (m < 10?"0" + m:"" + m) + "-" + (d < 10?"0" + d:"" + d) + " " + (h < 10?"0" + h:"" + h) + ":" + (mi < 10?"0" + mi:"" + mi) + ":" + (s < 10?"0" + s:"" + s); } HxOverrides.strDate = function(s) { switch(s.length) { case 8: var k = s.split(":"); var d = new Date(); d.setTime(0); d.setUTCHours(k[0]); d.setUTCMinutes(k[1]); d.setUTCSeconds(k[2]); return d; case 10: var k = s.split("-"); return new Date(k[0],k[1] - 1,k[2],0,0,0); case 19: var k = s.split(" "); var y = k[0].split("-"); var t = k[1].split(":"); return new Date(y[0],y[1] - 1,y[2],t[0],t[1],t[2]); default: throw "Invalid date format : " + s; } } HxOverrides.cca = function(s,index) { var x = s.charCodeAt(index); if(x != x) return undefined; return x; } HxOverrides.substr = function(s,pos,len) { if(pos != null && pos != 0 && len != null && len < 0) return ""; if(len == null) len = s.length; if(pos < 0) { pos = s.length + pos; if(pos < 0) pos = 0; } else if(len < 0) len = s.length + len - pos; return s.substr(pos,len); } HxOverrides.remove = function(a,obj) { var i = 0; var l = a.length; while(i < l) { if(a[i] == obj) { a.splice(i,1); return true; } i++; } return false; } HxOverrides.iter = function(a) { return { cur : 0, arr : a, hasNext : function() { return this.cur < this.arr.length; }, next : function() { return this.arr[this.cur++]; }}; } var IntIter = function(min,max) { this.min = min; this.max = max; }; IntIter.__name__ = true; IntIter.prototype = { next: function() { return this.min++; } ,hasNext: function() { return this.min < this.max; } ,__class__: IntIter } var Std = function() { } Std.__name__ = true; Std["is"] = function(v,t) { return js.Boot.__instanceof(v,t); } Std.string = function(s) { return js.Boot.__string_rec(s,""); } Std["int"] = function(x) { return x | 0; } Std.parseInt = function(x) { var v = parseInt(x,10); if(v == 0 && (HxOverrides.cca(x,1) == 120 || HxOverrides.cca(x,1) == 88)) v = parseInt(x); if(isNaN(v)) return null; return v; } Std.parseFloat = function(x) { return parseFloat(x); } Std.random = function(x) { return Math.floor(Math.random() * x); } var com = com || {} if(!com.wiris) com.wiris = {} if(!com.wiris.js) com.wiris.js = {} com.wiris.js.JsPluginTools = function() { this.tryReady(); }; com.wiris.js.JsPluginTools.__name__ = true; com.wiris.js.JsPluginTools.main = function() { var ev; ev = com.wiris.js.JsPluginTools.getInstance(); haxe.Timer.delay($bind(ev,ev.tryReady),100); } com.wiris.js.JsPluginTools.getInstance = function() { if(com.wiris.js.JsPluginTools.instance == null) com.wiris.js.JsPluginTools.instance = new com.wiris.js.JsPluginTools(); return com.wiris.js.JsPluginTools.instance; } com.wiris.js.JsPluginTools.bypassEncapsulation = function() { if(window.com == null) window.com = { }; if(window.com.wiris == null) window.com.wiris = { }; if(window.com.wiris.js == null) window.com.wiris.js = { }; if(window.com.wiris.js.JsPluginTools == null) window.com.wiris.js.JsPluginTools = com.wiris.js.JsPluginTools.getInstance(); } com.wiris.js.JsPluginTools.prototype = { md5encode: function(content) { return haxe.Md5.encode(content); } ,doLoad: function() { this.ready = true; com.wiris.js.JsPluginTools.instance = this; com.wiris.js.JsPluginTools.bypassEncapsulation(); } ,tryReady: function() { this.ready = false; if(js.Lib.document.readyState) { this.doLoad(); this.ready = true; } if(!this.ready) haxe.Timer.delay($bind(this,this.tryReady),100); } ,__class__: com.wiris.js.JsPluginTools } var haxe = haxe || {} haxe.Log = function() { } haxe.Log.__name__ = true; haxe.Log.trace = function(v,infos) { js.Boot.__trace(v,infos); } haxe.Log.clear = function() { js.Boot.__clear_trace(); } haxe.Md5 = function() { }; haxe.Md5.__name__ = true; haxe.Md5.encode = function(s) { return new haxe.Md5().doEncode(s); } haxe.Md5.prototype = { doEncode: function(str) { var x = this.str2blks(str); var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; var step; var i = 0; while(i < x.length) { var olda = a; var oldb = b; var oldc = c; var oldd = d; step = 0; a = this.ff(a,b,c,d,x[i],7,-680876936); d = this.ff(d,a,b,c,x[i + 1],12,-389564586); c = this.ff(c,d,a,b,x[i + 2],17,606105819); b = this.ff(b,c,d,a,x[i + 3],22,-1044525330); a = this.ff(a,b,c,d,x[i + 4],7,-176418897); d = this.ff(d,a,b,c,x[i + 5],12,1200080426); c = this.ff(c,d,a,b,x[i + 6],17,-1473231341); b = this.ff(b,c,d,a,x[i + 7],22,-45705983); a = this.ff(a,b,c,d,x[i + 8],7,1770035416); d = this.ff(d,a,b,c,x[i + 9],12,-1958414417); c = this.ff(c,d,a,b,x[i + 10],17,-42063); b = this.ff(b,c,d,a,x[i + 11],22,-1990404162); a = this.ff(a,b,c,d,x[i + 12],7,1804603682); d = this.ff(d,a,b,c,x[i + 13],12,-40341101); c = this.ff(c,d,a,b,x[i + 14],17,-1502002290); b = this.ff(b,c,d,a,x[i + 15],22,1236535329); a = this.gg(a,b,c,d,x[i + 1],5,-165796510); d = this.gg(d,a,b,c,x[i + 6],9,-1069501632); c = this.gg(c,d,a,b,x[i + 11],14,643717713); b = this.gg(b,c,d,a,x[i],20,-373897302); a = this.gg(a,b,c,d,x[i + 5],5,-701558691); d = this.gg(d,a,b,c,x[i + 10],9,38016083); c = this.gg(c,d,a,b,x[i + 15],14,-660478335); b = this.gg(b,c,d,a,x[i + 4],20,-405537848); a = this.gg(a,b,c,d,x[i + 9],5,568446438); d = this.gg(d,a,b,c,x[i + 14],9,-1019803690); c = this.gg(c,d,a,b,x[i + 3],14,-187363961); b = this.gg(b,c,d,a,x[i + 8],20,1163531501); a = this.gg(a,b,c,d,x[i + 13],5,-1444681467); d = this.gg(d,a,b,c,x[i + 2],9,-51403784); c = this.gg(c,d,a,b,x[i + 7],14,1735328473); b = this.gg(b,c,d,a,x[i + 12],20,-1926607734); a = this.hh(a,b,c,d,x[i + 5],4,-378558); d = this.hh(d,a,b,c,x[i + 8],11,-2022574463); c = this.hh(c,d,a,b,x[i + 11],16,1839030562); b = this.hh(b,c,d,a,x[i + 14],23,-35309556); a = this.hh(a,b,c,d,x[i + 1],4,-1530992060); d = this.hh(d,a,b,c,x[i + 4],11,1272893353); c = this.hh(c,d,a,b,x[i + 7],16,-155497632); b = this.hh(b,c,d,a,x[i + 10],23,-1094730640); a = this.hh(a,b,c,d,x[i + 13],4,681279174); d = this.hh(d,a,b,c,x[i],11,-358537222); c = this.hh(c,d,a,b,x[i + 3],16,-722521979); b = this.hh(b,c,d,a,x[i + 6],23,76029189); a = this.hh(a,b,c,d,x[i + 9],4,-640364487); d = this.hh(d,a,b,c,x[i + 12],11,-421815835); c = this.hh(c,d,a,b,x[i + 15],16,530742520); b = this.hh(b,c,d,a,x[i + 2],23,-995338651); a = this.ii(a,b,c,d,x[i],6,-198630844); d = this.ii(d,a,b,c,x[i + 7],10,1126891415); c = this.ii(c,d,a,b,x[i + 14],15,-1416354905); b = this.ii(b,c,d,a,x[i + 5],21,-57434055); a = this.ii(a,b,c,d,x[i + 12],6,1700485571); d = this.ii(d,a,b,c,x[i + 3],10,-1894986606); c = this.ii(c,d,a,b,x[i + 10],15,-1051523); b = this.ii(b,c,d,a,x[i + 1],21,-2054922799); a = this.ii(a,b,c,d,x[i + 8],6,1873313359); d = this.ii(d,a,b,c,x[i + 15],10,-30611744); c = this.ii(c,d,a,b,x[i + 6],15,-1560198380); b = this.ii(b,c,d,a,x[i + 13],21,1309151649); a = this.ii(a,b,c,d,x[i + 4],6,-145523070); d = this.ii(d,a,b,c,x[i + 11],10,-1120210379); c = this.ii(c,d,a,b,x[i + 2],15,718787259); b = this.ii(b,c,d,a,x[i + 9],21,-343485551); a = this.addme(a,olda); b = this.addme(b,oldb); c = this.addme(c,oldc); d = this.addme(d,oldd); i += 16; } return this.rhex(a) + this.rhex(b) + this.rhex(c) + this.rhex(d); } ,ii: function(a,b,c,d,x,s,t) { return this.cmn(this.bitXOR(c,this.bitOR(b,~d)),a,b,x,s,t); } ,hh: function(a,b,c,d,x,s,t) { return this.cmn(this.bitXOR(this.bitXOR(b,c),d),a,b,x,s,t); } ,gg: function(a,b,c,d,x,s,t) { return this.cmn(this.bitOR(this.bitAND(b,d),this.bitAND(c,~d)),a,b,x,s,t); } ,ff: function(a,b,c,d,x,s,t) { return this.cmn(this.bitOR(this.bitAND(b,c),this.bitAND(~b,d)),a,b,x,s,t); } ,cmn: function(q,a,b,x,s,t) { return this.addme(this.rol(this.addme(this.addme(a,q),this.addme(x,t)),s),b); } ,rol: function(num,cnt) { return num << cnt | num >>> 32 - cnt; } ,str2blks: function(str) { var nblk = (str.length + 8 >> 6) + 1; var blks = new Array(); var _g1 = 0, _g = nblk * 16; while(_g1 < _g) { var i = _g1++; blks[i] = 0; } var i = 0; while(i < str.length) { blks[i >> 2] |= HxOverrides.cca(str,i) << (str.length * 8 + i) % 4 * 8; i++; } blks[i >> 2] |= 128 << (str.length * 8 + i) % 4 * 8; var l = str.length * 8; var k = nblk * 16 - 2; blks[k] = l & 255; blks[k] |= (l >>> 8 & 255) << 8; blks[k] |= (l >>> 16 & 255) << 16; blks[k] |= (l >>> 24 & 255) << 24; return blks; } ,rhex: function(num) { var str = ""; var hex_chr = "0123456789abcdef"; var _g = 0; while(_g < 4) { var j = _g++; str += hex_chr.charAt(num >> j * 8 + 4 & 15) + hex_chr.charAt(num >> j * 8 & 15); } return str; } ,addme: function(x,y) { var lsw = (x & 65535) + (y & 65535); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return msw << 16 | lsw & 65535; } ,bitAND: function(a,b) { var lsb = a & 1 & (b & 1); var msb31 = a >>> 1 & b >>> 1; return msb31 << 1 | lsb; } ,bitXOR: function(a,b) { var lsb = a & 1 ^ b & 1; var msb31 = a >>> 1 ^ b >>> 1; return msb31 << 1 | lsb; } ,bitOR: function(a,b) { var lsb = a & 1 | b & 1; var msb31 = a >>> 1 | b >>> 1; return msb31 << 1 | lsb; } ,__class__: haxe.Md5 } haxe.Timer = function(time_ms) { var me = this; this.id = window.setInterval(function() { me.run(); },time_ms); }; haxe.Timer.__name__ = true; haxe.Timer.delay = function(f,time_ms) { var t = new haxe.Timer(time_ms); t.run = function() { t.stop(); f(); }; return t; } haxe.Timer.measure = function(f,pos) { var t0 = haxe.Timer.stamp(); var r = f(); haxe.Log.trace(haxe.Timer.stamp() - t0 + "s",pos); return r; } haxe.Timer.stamp = function() { return new Date().getTime() / 1000; } haxe.Timer.prototype = { run: function() { } ,stop: function() { if(this.id == null) return; window.clearInterval(this.id); this.id = null; } ,__class__: haxe.Timer } var js = js || {} js.Boot = function() { } js.Boot.__name__ = true; js.Boot.__unhtml = function(s) { return s.split("&").join("&").split("<").join("<").split(">").join(">"); } js.Boot.__trace = function(v,i) { var msg = i != null?i.fileName + ":" + i.lineNumber + ": ":""; msg += js.Boot.__string_rec(v,""); var d; if(typeof(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null) d.innerHTML += js.Boot.__unhtml(msg) + "<br/>"; else if(typeof(console) != "undefined" && console.log != null) console.log(msg); } js.Boot.__clear_trace = function() { var d = document.getElementById("haxe:trace"); if(d != null) d.innerHTML = ""; } js.Boot.isClass = function(o) { return o.__name__; } js.Boot.isEnum = function(e) { return e.__ename__; } js.Boot.getClass = function(o) { return o.__class__; } js.Boot.__string_rec = function(o,s) { if(o == null) return "null"; if(s.length >= 5) return "<...>"; var t = typeof(o); if(t == "function" && (o.__name__ || o.__ename__)) t = "object"; switch(t) { case "object": if(o instanceof Array) { if(o.__enum__) { if(o.length == 2) return o[0]; var str = o[0] + "("; s += "\t"; var _g1 = 2, _g = o.length; while(_g1 < _g) { var i = _g1++; if(i != 2) str += "," + js.Boot.__string_rec(o[i],s); else str += js.Boot.__string_rec(o[i],s); } return str + ")"; } var l = o.length; var i; var str = "["; s += "\t"; var _g = 0; while(_g < l) { var i1 = _g++; str += (i1 > 0?",":"") + js.Boot.__string_rec(o[i1],s); } str += "]"; return str; } var tostr; try { tostr = o.toString; } catch( e ) { return "???"; } if(tostr != null && tostr != Object.toString) { var s2 = o.toString(); if(s2 != "[object Object]") return s2; } var k = null; var str = "{\n"; s += "\t"; var hasp = o.hasOwnProperty != null; for( var k in o ) { ; if(hasp && !o.hasOwnProperty(k)) { continue; } if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") { continue; } if(str.length != 2) str += ", \n"; str += s + k + " : " + js.Boot.__string_rec(o[k],s); } s = s.substring(1); str += "\n" + s + "}"; return str; case "function": return "<function>"; case "string": return o; default: return String(o); } } js.Boot.__interfLoop = function(cc,cl) { if(cc == null) return false; if(cc == cl) return true; var intf = cc.__interfaces__; if(intf != null) { var _g1 = 0, _g = intf.length; while(_g1 < _g) { var i = _g1++; var i1 = intf[i]; if(i1 == cl || js.Boot.__interfLoop(i1,cl)) return true; } } return js.Boot.__interfLoop(cc.__super__,cl); } js.Boot.__instanceof = function(o,cl) { try { if(o instanceof cl) { if(cl == Array) return o.__enum__ == null; return true; } if(js.Boot.__interfLoop(o.__class__,cl)) return true; } catch( e ) { if(cl == null) return false; } switch(cl) { case Int: return Math.ceil(o%2147483648.0) === o; case Float: return typeof(o) == "number"; case Bool: return o === true || o === false; case String: return typeof(o) == "string"; case Dynamic: return true; default: if(o == null) return false; if(cl == Class && o.__name__ != null) return true; else null; if(cl == Enum && o.__ename__ != null) return true; else null; return o.__enum__ == cl; } } js.Boot.__cast = function(o,t) { if(js.Boot.__instanceof(o,t)) return o; else throw "Cannot cast " + Std.string(o) + " to " + Std.string(t); } js.Lib = function() { } js.Lib.__name__ = true; js.Lib.debug = function() { debugger; } js.Lib.alert = function(v) { alert(js.Boot.__string_rec(v,"")); } js.Lib.eval = function(code) { return eval(code); } js.Lib.setErrorHandler = function(f) { js.Lib.onerror = f; } var $_; function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; }; if(Array.prototype.indexOf) HxOverrides.remove = function(a,o) { var i = a.indexOf(o); if(i == -1) return false; a.splice(i,1); return true; }; else null; Math.__name__ = ["Math"]; Math.NaN = Number.NaN; Math.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY; Math.POSITIVE_INFINITY = Number.POSITIVE_INFINITY; Math.isFinite = function(i) { return isFinite(i); }; Math.isNaN = function(i) { return isNaN(i); }; String.prototype.__class__ = String; String.__name__ = true; Array.prototype.__class__ = Array; Array.__name__ = true; Date.prototype.__class__ = Date; Date.__name__ = ["Date"]; var Int = { __name__ : ["Int"]}; var Dynamic = { __name__ : ["Dynamic"]}; var Float = Number; Float.__name__ = ["Float"]; var Bool = Boolean; Bool.__ename__ = ["Bool"]; var Class = { __name__ : ["Class"]}; var Enum = { }; var Void = { __ename__ : ["Void"]}; if(typeof document != "undefined") js.Lib.document = document; if(typeof window != "undefined") { js.Lib.window = window; js.Lib.window.onerror = function(msg,url,line) { var f = js.Lib.onerror; if(f == null) return false; return f(msg,[url + ":" + line]); }; } com.wiris.js.JsPluginTools.main(); delete Array.prototype.__class__; }()); // @codingStandardsIgnoreEnd