/*if (typeof console == "undefined") { this.console = { log: function (msg) { alert(msg); } }; }*/ /* text selection - double click should select word cursor up/down - remember horizPos of original line and find closest in other lines */ /* example of basic use: var j000inputs = inputs({ inputs:[ {left:900,top:300,width:100,height:50,algText:true}, {left:900,top:500,width:100,height:50,algText:true} ], leftText:[ ['Perimeter = '], ['Area = '] ], rightText:[ ['cm'], ['cm',['pow',false,['2']]] ], checkFuncs:[ function(mathsInput) { if (mathsInput.stringJS == 'correctAns') { return true; } else { return false } }, function(mathsInput) { if (mathsInput.stringJS == 'correctAns') { return true; } else { return false } } ], }); */ function inputs(object) { var inputs = object.inputs; var checkFuncs = object.checkFuncs; var buttonPos = object.buttonPos || [990,620]; var taskComplete = boolean(object.taskCompleted,true); var buttonVis = boolean(object.buttonVisible,true); var inputArray = []; for (var i = 0; i < inputs.length; i++) { var zIndex = inputs[i].zIndex || 2; // mathsInput var input = createMathsInput2(inputs[i]); var vis = boolean(inputs[i].visible,true); // leftText && rightText var button3 = document.createElement('canvas'); button3.width = 1200; button3.height = 700; button3.setAttribute('position', 'absolute'); button3.setAttribute('cursor', 'auto'); button3.setAttribute('draggable', 'false'); button3.setAttribute('class', 'buttonClass'); var data3 = [0,0,1200,700,vis,false,false,zIndex]; if (vis == true) container.appendChild(button3); data3[130] = true; for (var j = 0; j < 8; j++) {data3[100+j] = data3[j];} button3.style.zIndex = zIndex; button3.style.pointerEvents = 'none'; canvases[pageIndex].push(button3); button3.data = data3; button3.ctx = button3.getContext('2d'); if (typeof object.leftText == 'object') { if (typeof object.leftText[i] == 'object') { var maxLines = inputs[i].maxLines || 1; var fontSize = inputs[i].fontSize || 0.5 * (inputs[i].height / maxLines); var textColor = inputs[i].textColor || '#000'; drawMathsText(button3.ctx,object.leftText[i],fontSize,inputs[i].left-4,inputs[i].top+0.5*inputs[i].height,false,[],'right','middle',textColor); input.leftText = object.leftText[i]; } } if (typeof object.rightText == 'object') { if (typeof object.rightText[i] == 'object') { var maxLines = inputs[i].maxLines || 1; var fontSize = inputs[i].fontSize || 0.5 * (inputs[i].height / maxLines); var textColor = inputs[i].textColor || '#000'; drawMathsText(button3.ctx,object.rightText[i],fontSize,inputs[i].left+inputs[i].width+15,inputs[i].top+0.5*inputs[i].height,false,[],'left','middle',textColor); var textMeasure = drawMathsText(button3.ctx,object.rightText[i],fontSize,inputs[i].left+inputs[i].width+15,inputs[i].top+0.5*inputs[i].height,false,[],'left','middle',textColor,'measure'); if (typeof inputs[i].offset === 'undefined') inputs[i].offset = [textMeasure[0]+5,0]; input.rightText = object.rightText[i]; } } if (typeof inputs[i].offset === 'undefined') inputs[i].offset = [0,0]; input.leftRightTextCanvas = button3; input.canvas.leftRightTextCanvas = button3; // what if... maths input is entered through tab key, rather than clicking on?? addListener(input.canvas, function() { hideObj(this.tick,this.tick.data); hideObj(this.cross,this.cross.data); }); // tick canvas var button = document.createElement('canvas'); button.width = 40; button.height = 50; button.setAttribute('position', 'absolute'); button.setAttribute('cursor', 'auto'); button.setAttribute('draggable', 'false'); button.setAttribute('class', 'buttonClass'); var data = [inputs[i].left+inputs[i].width+13+inputs[i].offset[0],inputs[i].top+0.5*inputs[i].height-25+inputs[i].offset[1],40,50,false,false,false,zIndex]; data[130] = true; for (var j = 0; j < 8; j++) {data[100+j] = data[j];} button.style.zIndex = zIndex; button.style.pointerEvents = 'none'; canvases[pageIndex].push(button3); button.data = data; button.ctx = button.getContext('2d'); drawTick(button.ctx,40,50); // cross canvas var button2 = document.createElement('canvas'); button2.width = 32; button2.height = 40; button2.setAttribute('position', 'absolute'); button2.setAttribute('cursor', 'auto'); button2.setAttribute('draggable', 'false'); button2.setAttribute('class', 'buttonClass'); var data2 = [inputs[i].left+inputs[i].width+20+inputs[i].offset[0],inputs[i].top+0.5*inputs[i].height-20+inputs[i].offset[1],32,40,false,false,false,zIndex]; data2[130] = true; for (var j = 0; j < 8; j++) {data2[100+j] = data2[j];} button2.style.zIndex = zIndex; button.style.pointerEvents = 'none'; canvases[pageIndex].push(button3); button2.data = data2; button2.ctx = button2.getContext('2d'); drawCross(button2.ctx,32,40); input.tick = button; input.cross = button2; input.canvas.tick = button; input.canvas.cross = button2; inputArray.push(input); } if (boolean(object.checkAnsButton,true)) { // check answer button var button = document.createElement('canvas'); button.width = 180; button.height = 50; button.setAttribute('position', 'absolute'); button.setAttribute('cursor', 'auto'); button.setAttribute('draggable', 'false'); button.setAttribute('class', 'buttonClass'); var data = [buttonPos[0],buttonPos[1],180,50,buttonVis,false,true,2]; if (buttonVis == true) container.appendChild(button); data[130] = true; for (var i = 0; i < 8; i++) {data[100+i] = data[i];} button.style.zIndex = 2; canvases[pageIndex].push(button3); button.data = data; button.ctx = button.getContext('2d'); if (inputs.length > 1) { drawTextBox(button,button.ctx,button.data,'#6F9','#000',4,'28px Hobo','#000','center','Check Answers'); } else { drawTextBox(button,button.ctx,button.data,'#6F9','#000',4,'28px Hobo','#000','center','Check Answer'); } addListener(button,function() { var inputs = this.inputs; var checkFuncs = this.checkFuncs; var complete = true; for (var i = 0; i < inputs.length; i++) { if (checkFuncs[i](inputs[i]) == true) { hideObj(inputs[i].cross,inputs[i].cross.data); showObj(inputs[i].tick,inputs[i].tick.data); } else { hideObj(inputs[i].tick,inputs[i].tick.data); showObj(inputs[i].cross,inputs[i].cross.data,3000); complete = false; } } if (complete == true) { taskCompleted(); } }); button.inputs = inputArray; button.checkFuncs = checkFuncs; button.taskComplete = true; button.textCanvas = button3; return button; } } function hideAllInputs() { for (var i = 0; i < mathsInput[pageIndex].length; i++) { hideMathsInput(mathsInput[pageIndex][i]); } } function showAllInputs() { for (var i = 0; i < mathsInput[pageIndex].length; i++) { showMathsInput(mathsInput[pageIndex][i]); } } function hideMathsInput(mathsInput) { hideObj(mathsInput.canvas); if (typeof mathsInput.cursorCanvas !== 'undefined') { hideObj(mathsInput.cursorCanvas); } if (typeof mathsInput.tick !== 'undefined') { hideObj(mathsInput.tick); } if (typeof mathsInput.cross !== 'undefined') { hideObj(mathsInput.cross); } if (typeof mathsInput.leftRightTextCanvas !== 'undefined') { hideObj(mathsInput.leftRightTextCanvas); } } function showMathsInput(mathsInput) { showObj(mathsInput.canvas); if (typeof mathsInput.cursorCanvas !== 'undefined') { showObj(mathsInput.cursorCanvas); } if (typeof mathsInput.leftRightTextCanvas !== 'undefined') { showObj(mathsInput.leftRightTextCanvas); } } function moveMathsInput(input,left,top) { if (typeof input.data == 'undefined') return; var dx = left - input.data[100]; var dy = top - input.data[101]; input.data[100] += dx; input.data[101] += dy; resizeCanvas2(input.canvas,input.data[100],input.data[101]); if (typeof input.cross !== 'undefined') { input.cross.data[100] += dx; input.cross.data[101] += dy; resizeCanvas2(input.cross,input.cross.data[100],input.cross.data[101]); } if (typeof input.tick !== 'undefined') { input.tick.data[100] += dx; input.tick.data[101] += dy; resizeCanvas2(input.tick,input.tick.data[100],input.tick.data[101]); } input.cursorData[100] += dx; input.cursorData[101] += dy; resizeCanvas2(input.cursorCanvas,input.cursorData[100],input.cursorData[101]); if (typeof input.leftRightTextCanvas !== 'undefined') { input.leftRightTextCanvas.data[100] += dx; input.leftRightTextCanvas.data[101] += dy; resizeCanvas2(input.leftRightTextCanvas,input.leftRightTextCanvas.data[100],input.leftRightTextCanvas.data[101]); } } function enlargeMathsInput(input,sf) { // be careful! if (typeof sf !== 'number') return; //var l = input.data[100]; //var t = input.data[101]; //input.data[102] = input.data[102] * sf; //input.data[103] = input.data[103] * sf; resizeCanvas(input.canvas,input.data[100],input.data[101],input.data[102]*sf,input.data[103]*sf); /*input.cursorData[100] += (l -input.cursorData[100])*sf; input.cursorData[101] += (t -input.cursorData[101])*sf; input.cursorData[102] = input.cursorData[102] * sf; input.cursorData[103] = input.cursorData[103] * sf; resizeCanvas(input.cursorCanvas,input.cursorData[100],input.cursorData[101],input.cursorData[102],input.cursorData[103]); if (typeof input.cross !== 'undefined') { input.cross.data[100] += (l -input.cross.data[100])*sf; input.cross.data[101] += (t -input.cross.data[101])*sf; input.cross.data[102] = input.cross.data[102] * sf; input.cross.data[103] = input.cross.data[103] * sf; resizeCanvas(input.cross,input.cross.data[100],input.cross.data[101],input.cross.data[102],input.cross.data[103]); } if (typeof input.tick !== 'undefined') { input.tick.data[100] += (l -input.tick.data[100])*sf; input.tick.data[101] += (t -input.tick.data[101])*sf; input.tick.data[102] = input.tick.data[102] * sf; input.tick.data[103] = input.tick.data[103] * sf; resizeCanvas(input.tick,input.tick.data[100],input.tick.data[101],input.tick.data[102],input.tick.data[103]); } if (typeof input.leftRightTextCanvas !== 'undefined') { input.leftRightTextCanvas.data[100] += (l -input.leftRightTextCanvas.data[100])*sf; input.leftRightTextCanvas.data[101] += (t -input.leftRightTextCanvas.data[101])*sf; input.leftRightTextCanvas.data[102] = input.leftRightTextCanvas.data[102] * sf; input.leftRightTextCanvas.data[103] = input.leftRightTextCanvas.data[103] * sf; resizeCanvas(input.leftRightTextCanvas,input.leftRightTextCanvas.data[100],input.leftRightTextCanvas.data[101],input.leftRightTextCanvas.data[102],input.leftRightTextCanvas.data[103]); }*/ } function setMathsInputZIndex(input,zIndex) { if (typeof input.leftRightTextCanvas == 'object') input.leftRightTextCanvas.style.zIndex = zIndex; if (typeof input.tick == 'object') input.tick.style.zIndex = zIndex; if (typeof input.cross == 'object') input.cross.style.zIndex = zIndex; if (typeof input.canvas == 'object') input.canvas.style.zIndex = zIndex; if (typeof input.cursorCanvas == 'object') input.cursorCanvas.style.zIndex = zIndex; } function setMathsInputFont(input,font) { removeTagsOfType(input.richText,'font'); input.richText.unshift('<>'); input.richText = combineSpacesTextArray(input.richText); removeTagsOfType(input.startRichText,'font'); input.startRichText.unshift('<>'); input.startRichText = combineSpacesTextArray(input.startRichText); input.startTags = removeTagsOfType(input.startTags,'font'); input.startTags = '<>'+input.startTags; currMathsInput = input; mathsInputMapCursorPos(); mathsInputCursorCoords(); deselectMathsInput(); } function setMathsInputColor(input,color) { removeTagsOfType(input.richText,'color'); input.richText.unshift('<>'); input.richText = combineSpacesTextArray(input.richText); removeTagsOfType(input.startRichText,'color'); input.startRichText.unshift('<>'); input.startRichText = combineSpacesTextArray(input.startRichText); input.startTags = removeTagsOfType(input.startTags,'color'); input.startTags = '<>'+input.startTags; var saveCurrMathsInput = currMathsInput; currMathsInput = input; drawMathsInputText(input); deselectMathsInput(); } function setMathsInputText(mathsInputObj, opt_newText, opt_newCursorPos) { // eg. setMathsInputText(j37mathsInput[3]); var newText; if (un(opt_newText)) { newText = [""]; } else if (typeof opt_newText == 'string') { newText = [opt_newText]; } else if (typeof opt_newText == 'number') { newText = String(opt_newText); newText = [newText]; } else { newText = clone(opt_newText); } mathsInputObj.text = newText; if (!un(mathsInputObj.startTags)) newText.unshift(mathsInputObj.startTags); mathsInputObj.richText = newText; currMathsInput = mathsInputObj; mathsInputMapCursorPos(); if (typeof opt_newCursorPos !== 'undefined') { mathsInputObj.cursorPos = opt_newCursorPos; } else { mathsInputObj.cursorPos = mathsInputObj.cursorMap.length - 1; } mathsInputCursorCoords(); deselectMathsInput(); } function setMathsInputTextToInitialTags(m) { var newText = ""; if (!un(m.richText) && typeof m.richText[0] == 'string' && m.richText[0].indexOf('<<') == 0) { for (c = 2; c < m.richText[0].length; c++) { if (m.richText[0].slice(c).indexOf('>>') == 0 && m.richText[0].slice(c).indexOf('>><<') !== 0) { newText = m.richText[0].slice(0,c+2); break; } } } setMathsInputText(m,[newText],0); } function drawTick(ctx,width,height,color,left,top,lineWidth) { if (!left) left = 0; if (!top) top = 0; if (!width) width = 75; if (!height) height = 75; if (!color) color = '#F0F'; if(!lineWidth) lineWidth = 8; ctx.save(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(left+4,top+0.5*height); ctx.lineTo(left+width/3,top+height-4); ctx.lineTo(left+width-4,top+4); ctx.stroke(); ctx.restore(); } function drawCross(ctx,width,height,color,left,top,lineWidth) { if (!left) left = 0; if (!top) top = 0; if (!width) width = 75; if (!height) height = 75; if (!color) color = '#F00'; if(!lineWidth) lineWidth = 8; ctx.save(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(left+4,top+4); ctx.lineTo(left+width-4,top+height-4); ctx.moveTo(left+width-4,top+4); ctx.lineTo(left+4,top+height-4); ctx.stroke(); ctx.restore(); } function createMathsInput2(object) { // non-optional: var left = object.left; var top = object.top; var width = object.width; var height = object.height; // optional & defaults: var varSize = object.varSize; // varSize:{minWidth:50,maxWidth:400,minHeight:50,maxHeight:300,padding:5} var visible; if (typeof object.visible == 'boolean') {visible = object.visible} else {visible = true}; var zIndex = object.zIndex || 2; var algText; if (typeof object.algText == 'boolean') {algText = object.algText} else {algText = false}; var textArray = object.textArray || [""]; var leftPoint = object.leftPoint || 10; var textColor = object.textColor || '#000'; var textAlign = object.textAlign || 'center'; var vertAlign = object.vertAlign || 'middle'; var transparent; if (typeof object.transparent == 'boolean') {transparent = object.transparent} else {transparent = false}; var maxChars = object.maxChars || 1000000000; var backColor = object.backColor || '#FFF'; var selectColor = object.selectColor || '#FCF'; var border; if (typeof object.border == 'boolean') {border = object.border} else {border = true}; var borderWidth = object.borderWidth || 3; var borderDash = object.borderDash || []; var borderColor = object.borderColor || '#000'; var maxLines = object.maxLines || 1; var fontSize = object.fontSize || 0.5 * (height/maxLines); var selectable = boolean(object.selectable,false); var pointerCanvas = object.pointerCanvas || false; var inputObject = createMathsInput(0, left, top, width, height, visible, zIndex, algText, textArray, leftPoint, fontSize, textColor, textAlign, transparent, maxChars, backColor, selectColor, border, borderColor, maxLines, vertAlign, varSize, borderWidth, borderDash, selectable, pointerCanvas); return inputObject; } // creates mathsInput canvas function createMathsInput(id, left, top, width, height, visible, zIndex, algText, textArray, leftPoint, fontSize, textColor, textAlign, transparent, maxChars, backColor, selectColor, border, borderColor, maxLines, vertAlign, varSize, borderWidth, borderDash,selectable, pointerCanvas) { if (!maxLines) {maxLines = 1}; if (!zIndex) {zIndex = 2}; if (!algText) {algText = false}; if (!fontSize) (fontSize = (height/maxLines) * 0.75); if (!textColor) (textColor = '#000'); if (!textAlign) {textAlign = 'center'}; if (textAlign == 'center') {leftPoint = 0.5 * width}; if (!vertAlign) {vertAlign = 'middle'}; if (!textArray) {textArray = [""]}; var font = 'Arial'; if (algText == true) font = 'algebra'; var startText = textArray.slice(0); var startTags = "<><><><><><><>"; textArray.unshift(startTags); var startRichText = textArray.slice(0); if (!leftPoint) {leftPoint = 10}; if (typeof transparent !== 'boolean') {transparent = false}; if (!maxChars) {maxChars = 100000000} if (!backColor) backColor = "#fff"; var currBackColor = backColor; if (!selectColor) selectColor = '#FCF'; if (typeof border !== 'boolean') border = true; if (!borderWidth) borderWidth = 5; if (!borderDash) borderDash = []; if (!borderColor) borderColor = '#000'; if (!startText) startText = ['']; if (typeof selectable !== 'boolean') selectable = false; if (!pointerCanvas) pointerCanvas = false; function makeInputCanvas(l,t,w,h,v,d,p,z) { var canvas = document.createElement('canvas'); canvas.setAttribute('class', 'inputClass'); canvas.setAttribute('width', w); canvas.setAttribute('height', h); canvas.setAttribute('left', l); canvas.setAttribute('top', t); canvas.setAttribute('position', 'absolute'); canvas.style.border = 'none'; canvas.style.zIndex = z; if (p == false) { canvas.style.pointerEvents = 'none'; } else { canvas.style.pointerEvents = 'auto'; } canvas.data = [l,t,w,h,v,d,p,z]; canvas.ctx = canvas.getContext('2d'); for (var i = 0; i < 8; i++) {canvas.data[i+100] = canvas.data[i]}; resizeCanvas3(canvas); return canvas; } var textCanvas = makeInputCanvas(left, top, width, height, visible, false, false, zIndex); var cursorCanvas = makeInputCanvas(left, top, width, height, visible, false, true, zIndex); cursorCanvas.addEventListener('mousedown', startMathsInput, false); cursorCanvas.addEventListener('touchstart', startMathsInput, false); var input = { id:id, canvas:textCanvas, ctx:textCanvas.ctx, data:textCanvas.data, cursorCanvas:cursorCanvas, cursorctx:cursorCanvas.ctx, cursorData:cursorCanvas.data, active:true, stringJS:"", text:startText, richText:startRichText, textLoc:[], cursorPos:0, cursorMap:[], algText:algText, leftPoint:leftPoint, fontSize:fontSize, textColor:textColor, textAlign:textAlign, transparent:transparent, maxChars:maxChars, backColor:backColor, selectColor:selectColor, border:border, // boolean borderWidth:borderWidth, borderDash:borderDash, borderColor:borderColor, currBackColor:currBackColor, startText:startText, startRichText:startRichText, startTags:startTags, maxLines:maxLines, preText:'', postText:'', vertAlign:vertAlign, varSize:varSize, selectable:selectable, selectPos:[], selected:false, setBackColor:function(color) { this.backColor = color; drawMathsInputText(this); }, pointerCanvas:pointerCanvas }; //input.creationTime = (new Date()).getTime(); mathsInput[pageIndex].push(input); currMathsInput = input; drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); deselectMathsInput(); if (isTask == false && visible == true) showMathsInput(input); return input; } function mathsInputFrac(e) {mathsInputElement("['frac', [''], ['']]");} function mathsInputPow(e) {mathsInputElement("['power', false, ['']]");} function mathsInputSubs(e) {mathsInputElement("['subs', [''], ['']]");} function mathsInputRoot(e) {mathsInputElement("['root', [''], ['']]");} function mathsInputSqrt(e) {mathsInputElement("['sqrt', ['']]");} function mathsInputSin(e) {mathsInputElement("['sin', ['']]");} function mathsInputCos(e) {mathsInputElement("['cos', ['']]");} function mathsInputTan(e) {mathsInputElement("['tan', ['']]");} function mathsInputInvSin(e) {mathsInputElement("['sin-1', ['']]");} function mathsInputInvCos(e) {mathsInputElement("['cos-1', ['']]");} function mathsInputInvTan(e) {mathsInputElement("['tan-1', ['']]");} function mathsInputLn(e) {mathsInputElement("['ln', ['']]");} function mathsInputLog(e) {mathsInputElement("['log', ['']]");} function mathsInputLogBase(e) {mathsInputElement("['logBase', [''], ['']]");} function mathsInputAbs(e) {mathsInputElement("['abs', ['']]");} function mathsInputExp(e) {mathsInputElement("['exp', ['']]");} function mathsInputSigma1(e) {mathsInputElement("['sigma1', ['']]");} function mathsInputSigma2(e) {mathsInputElement("['sigma2', [''], [''], ['']]");} function mathsInputInt1(e) {mathsInputElement("['int1', ['']]");} function mathsInputInt2(e) {mathsInputElement("['int2', [''], [''], ['']]");} function mathsInputVectorArrow(e) {mathsInputElement("['vectorArrow', ['']]");} function mathsInputBar(e) {mathsInputElement("['bar', ['']]");} function mathsInputHat(e) {mathsInputElement("['hat', ['']]");} function mathsInputRecurring(e) {mathsInputElement("['recurring', ['']]");} function mathsInputColVector2d(e) {mathsInputElement("['colVector2d', [''], ['']]");} function mathsInputColVector3d(e) {mathsInputElement("['colVector3d', [''], [''], ['']]");} function mathsInputMixedNum(e) {mathsInputElement("['mixedNum', [''], [''], ['']]");} function mathsInputLim(e) {mathsInputElement("['lim', [''], ['']]");} function mathsInputCut() { if (currMathsInput.selected == false) return; mathsInputCopy(); currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } function mathsInputCopy() { if (currMathsInput.selected == false) return; var sel = false; clipboard = arrayHandler(clone(currMathsInput.richText)); //console.log(clipboard); function arrayHandler(array) { for (var l = 0; l < array.length; l++) { if (typeof array[l] == 'string') { if (l > 0 || array.length == 1 || ['frac','power','pow','subs','subscript','sin','cos','tan','ln','log','logBase','sin-1','cos-1','tan-1','abs','exp','root','sqrt','sigma1','sigma2','int1','int2','recurring','bar','hat','vectorArrow','colVector2d','colVector3d','mixedNum','lim'].indexOf(array[l]) == -1) { array[l] = stringHandler(array[l]); } } else { array[l] = arrayHandler(array[l]); if (sel == false) { array.splice(l,1); l--; } } } return array; } function stringHandler(string) { var delPos = []; if (sel == true) delPos[0] = 0; var savedTags = ''; for (var j = 0; j < string.length; j++) { var slice = string.slice(j); if (slice.indexOf('<>') == 0) { delPos[0] = j+17; sel = true; } if (slice.indexOf('<>') == 0) { delPos[1] = j; sel = false; } /*if (sel == true && (slice.indexOf('<>')+2); }*/ } if (delPos.length > 0) { if (delPos.length == 1) { return string.slice(delPos[0])+savedTags; } else { return string.slice(delPos[0],delPos[1]); } } else { return string; } } } function mathsInputPaste() { if (typeof clipboard !== 'object' || clipboard == [] || arraysEqual(clipboard,[''])) return; var elementString = JSON.stringify(clipboard); if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; var pos = cursorPos[cursorPos.length - 1]; pos = adjustForBreakPoints(pos); var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { evalString += '[' + cursorPos[aa] + ']'; } var before = parent.slice(0,pos); var after = parent.slice(pos); //console.log('before:',before); //console.log('after:',after); var newParent = clone(clipboard); newParent.unshift(before); newParent.push(after); //console.log('newParent:',newParent); eval(evalString+" = newParent;"); //console.log('currMathsInput.richText:',currMathsInput.richText); var cursorPosCount = 0; arrayHandler(clipboard); function arrayHandler(array) { for (var l = 0; l < array.length; l++) { if (typeof array[l] == 'string') { if (array.length == 1 || ['frac','power','pow','subs','subscript','sin','cos','tan','ln','log','logBase','sin-1','cos-1','tan-1','abs','exp','root','sqrt','sigma1','sigma2','int1','int2','recurring','bar','hat','vectorArrow','colVector2d','colVector3d','mixedNum','lim'].indexOf(array[l]) == -1) { cursorPosCount += array[l].length; } } else { arrayHandler(array[l]); } } } mathsInputMapCursorPos(); currMathsInput.cursorPos += cursorPosCount; mathsInputCursorCoords(); currMathsInput.preText = ''; currMathsInput.postText = ''; } function mathsInputElement(elementString) { if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; var gparent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 2; aa++) { gparent = gparent[cursorPos[aa]] }; var parent = gparent[cursorPos[cursorPos.length-2]]; var parentPos = cursorPos[cursorPos.length-2]; var pos = cursorPos[cursorPos.length-1]; pos = adjustForBreakPoints(pos); var before = parent.slice(0,pos); var after = parent.slice(pos); if (!un(currMathsInput.preText) && currMathsInput.preText !== null && currMathsInput.preText !== '') { before += currMathsInput.preText; } if (!un(currMathsInput.postText) && currMathsInput.postText !== null && currMathsInput.postText !== '') { after = currMathsInput.postText + after; } gparent.splice(parentPos,1,before,eval(elementString),after); mathsInputMapCursorPos(); currMathsInput.cursorPos++; mathsInputCursorCoords(); currMathsInput.preText = ''; currMathsInput.postText = ''; } function mathsInputNewLine() { // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; if (typeof currMathsInput.richText[cursorPos[0]] == 'string') { var slicePos = cursorPos[1]; slicePos = adjustForBreakPoints(slicePos); // check if there is an align tag if (currMathsInput.richText[cursorPos[0]].slice(slicePos).indexOf('<>')+2; } slicePos = mathsInputAvoidTagSplit(currMathsInput.richText[cursorPos[0]],slicePos); currMathsInput.richText[cursorPos[0]] = currMathsInput.richText[cursorPos[0]].slice(0,slicePos) + '<
>' + currMathsInput.richText[cursorPos[0]].slice(slicePos); mathsInputMapCursorPos(); currMathsInput.cursorPos += 1; mathsInputCursorCoords(); } else { // jump forward from element to next string (if it exists) and insert <
> var cursorPosShiftCount = 0; for (var i = currMathsInput.cursorPos; i < currMathsInput.cursorMap.length; i++) { cursorPosShiftCount++; // if the next element has been reached if (cursorPos[0] < currMathsInput.cursorMap[i][0]) { if (typeof currMathsInput.richText[currMathsInput.cursorMap[i][0]] == 'string') { cursorPos = currMathsInput.cursorMap[i]; currMathsInput.richText[currMathsInput.cursorMap[i][0]] = '<
>'+currMathsInput.richText[currMathsInput.cursorMap[i][0]]; break; } else { // this shouldn't happen?? All elements will be separated by a text string } } else if (i == currMathsInput.cursorMap.length - 1) { currMathsInput.richText.push('<
>'); cursorPosShiftCount += 6; } } mathsInputMapCursorPos(); currMathsInput.cursorPos += cursorPosShiftCount; mathsInputCursorCoords(); } } function mathsInputTab(howMany) { if (un(howMany)) howMany = 1; var ins = ""; for (var i = 0; i < howMany; i++) { ins += String.fromCharCode(0x21F4); } // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; if (typeof currMathsInput.richText[cursorPos[0]] == 'string') { var slicePos = cursorPos[1]; slicePos = adjustForBreakPoints(slicePos); // check if there is an align tag if (currMathsInput.richText[cursorPos[0]].slice(slicePos).indexOf('<>')+2; } currMathsInput.richText[cursorPos[0]] = currMathsInput.richText[cursorPos[0]].slice(0,slicePos) + ins + currMathsInput.richText[cursorPos[0]].slice(slicePos); mathsInputMapCursorPos(); currMathsInput.cursorPos += howMany; mathsInputCursorCoords(); } else { // jump forward from element to next string (if it exists) and insert <
> var cursorPosShiftCount = 0; for (var i = currMathsInput.cursorPos; i < currMathsInput.cursorMap.length; i++) { cursorPosShiftCount++; // if the next element has been reached if (cursorPos[0] < currMathsInput.cursorMap[i][0]) { if (typeof currMathsInput.richText[currMathsInput.cursorMap[i][0]] == 'string') { cursorPos = currMathsInput.cursorMap[i]; currMathsInput.richText[currMathsInput.cursorMap[i][0]] = ins+currMathsInput.richText[currMathsInput.cursorMap[i][0]]; break; } else { // this shouldn't happen?? All elements will be separated by a text string } } else if (i == currMathsInput.cursorMap.length - 1) { currMathsInput.richTexts.push(String.fromCharCode(0x21F4)); cursorPosShiftCount += howMany; } } mathsInputMapCursorPos(); currMathsInput.cursorPos += cursorPosShiftCount; mathsInputCursorCoords(); } } function mathsInputLeftArrow(e) { if (currMathsInput.cursorPos > 0) { currMathsInput.cursorPos--; mathsInputCursorCoords(); } else { mathsInputTabPrev(); } } function mathsInputRightArrow(e) { if (currMathsInput.cursorPos < currMathsInput.cursorMap.length - 1) { currMathsInput.cursorPos++; mathsInputCursorCoords(); } else { mathsInputTabNext(); } } function mathsInputTabPrev() { var dx,dy,x,y,currBest1,currBest2; for (var i = 0; i < mathsInput[pageIndex].length; i++) { if (i == currMathsInputId || mathsInput[pageIndex][i].canvas.parentNode !== container || mathsInput[pageIndex][i].active == false) continue; if (mathsInput[pageIndex][i].data[100] < mathsInput[pageIndex][currMathsInputId].data[100] && mathsInput[pageIndex][i].data[101] == mathsInput[pageIndex][currMathsInputId].data[101]) { // if directly to the left if (typeof dy == 'undefined') { dy = 0; dx = mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100]; currBest1 = i; } else if (dy > 0 || (dy == 0 && mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100] < dx)) { dy = 0; dx = mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100]; currBest1 = i; } } else if (mathsInput[pageIndex][i].data[101] < mathsInput[pageIndex][currMathsInputId].data[101]) { // if above if (typeof dy == 'undefined') { dy = mathsInput[pageIndex][currMathsInputId].data[101] - mathsInput[pageIndex][i].data[101]; dx = mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100]; currBest1 = i; } else if (dy > mathsInput[pageIndex][currMathsInputId].data[101] - mathsInput[pageIndex][i].data[101] || (dy == mathsInput[pageIndex][currMathsInputId].data[101] - mathsInput[pageIndex][i].data[101] && mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100] < dx)) { dy = mathsInput[pageIndex][currMathsInputId].data[101] - mathsInput[pageIndex][i].data[101]; dx = mathsInput[pageIndex][currMathsInputId].data[100] - mathsInput[pageIndex][i].data[100]; currBest1 = i; } } else if ((mathsInput[pageIndex][i].data[100] > mathsInput[pageIndex][currMathsInputId].data[100] && mathsInput[pageIndex][i].data[101] == mathsInput[pageIndex][currMathsInputId].data[101]) || mathsInput[pageIndex][i].data[101] > mathsInput[pageIndex][currMathsInputId].data[101]) { // if directly to the right or below if (typeof y == 'undefined') { y = mathsInput[pageIndex][i].data[101]; x = mathsInput[pageIndex][i].data[100]; currBest2 = i; } else if (mathsInput[pageIndex][i].data[101] > y || (mathsInput[pageIndex][i].data[101] == y && mathsInput[pageIndex][i].data[100] > x)) { y = mathsInput[pageIndex][i].data[101]; x = mathsInput[pageIndex][i].data[100]; currBest2 = i; } } } if (typeof currBest1 !== 'undefined') { currMathsInput.preText = ''; currMathsInput.postText = ''; deselectMathsInput(mathsInput[pageIndex][currBest1],true); startMathsInput(mathsInput[pageIndex][currBest1]); currMathsInput.cursorPos = currMathsInput.cursorMap.length - 1; mathsInputCursorCoords(); } else if (typeof currBest2 !== 'undefined') { currMathsInput.preText = ''; currMathsInput.postText = ''; deselectMathsInput(mathsInput[pageIndex][currBest2],true); startMathsInput(mathsInput[pageIndex][currBest2]); currMathsInput.cursorPos = 0; mathsInputCursorCoords(); } } function mathsInputTabNext() { var index = mathsInput[pageIndex].indexOf(currMathsInput); if (index > -1) { var newIndex = (index+1) % mathsInput[pageIndex].length; currMathsInput.preText = ''; currMathsInput.postText = ''; deselectMathsInput(mathsInput[pageIndex][newIndex],true); startMathsInput(mathsInput[pageIndex][newIndex]); currMathsInput.cursorPos = currMathsInput.cursorMap.length - 1; mathsInputCursorCoords(); } return; /*var dx,dy,x,y,currBest1,currBest2; for (var i = 0; i < mathsInput[pageIndex].length; i++) { if (i == currMathsInputId || mathsInput[pageIndex][i].canvas.parentNode !== container || mathsInput[pageIndex][i].active == false) continue; if (mathsInput[pageIndex][i].data[100] > mathsInput[pageIndex][currMathsInputId].data[100] && mathsInput[pageIndex][i].data[101] == mathsInput[pageIndex][currMathsInputId].data[101]) { // if directly to the right if (typeof dy == 'undefined') { dy = 0; dx = mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100]; currBest1 = i; } else if (dy > 0 || (dy == 0 && mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100] < dx)) { dy = 0; dx = mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100]; currBest1 = i; } } else if (mathsInput[pageIndex][i].data[101] > mathsInput[pageIndex][currMathsInputId].data[101]) { // if below if (typeof dy == 'undefined') { dy = mathsInput[pageIndex][i].data[101] - mathsInput[pageIndex][currMathsInputId].data[101]; dx = mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100]; currBest1 = i; } else if (dy > mathsInput[pageIndex][i].data[101] - mathsInput[pageIndex][currMathsInputId].data[101] || (dy == mathsInput[pageIndex][i].data[101] - mathsInput[pageIndex][currMathsInputId].data[101] && mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100] < dx)) { dy = mathsInput[pageIndex][i].data[101] - mathsInput[pageIndex][currMathsInputId].data[101]; dx = mathsInput[pageIndex][i].data[100] - mathsInput[pageIndex][currMathsInputId].data[100]; currBest1 = i; } } else if ((mathsInput[pageIndex][i].data[100] < mathsInput[pageIndex][currMathsInputId].data[100] && mathsInput[pageIndex][i].data[101] == mathsInput[pageIndex][currMathsInputId].data[101]) || mathsInput[pageIndex][i].data[101] < mathsInput[pageIndex][currMathsInputId].data[101]) { // if directly to the left or above if (typeof y == 'undefined') { y = mathsInput[pageIndex][i].data[101]; x = mathsInput[pageIndex][i].data[100]; currBest2 = i; } else if (mathsInput[pageIndex][i].data[101] < y || (mathsInput[pageIndex][i].data[101] == y && mathsInput[pageIndex][i].data[100] < x)) { y = mathsInput[pageIndex][i].data[101]; x = mathsInput[pageIndex][i].data[100]; currBest2 = i; } } } if (typeof currBest1 !== 'undefined') { currMathsInput.preText = ''; currMathsInput.postText = ''; deselectMathsInput(mathsInput[pageIndex][currBest1],true); startMathsInput(mathsInput[pageIndex][currBest1]); currMathsInput.cursorPos = currMathsInput.cursorMap.length - 1; mathsInputCursorCoords(); } else if (typeof currBest2 !== 'undefined') { currMathsInput.preText = ''; currMathsInput.postText = ''; deselectMathsInput(mathsInput[pageIndex][currBest2],true); startMathsInput(mathsInput[pageIndex][currBest2]); currMathsInput.cursorPos = 0; mathsInputCursorCoords(); }*/ } function mathsInputAvoidTagSplit(txt,slicePos) { // check that a tag is not being split - if so adjust slicePos var leftText = txt.slice(0,slicePos); var rightText = txt.slice(slicePos); //console.clear(); //console.log(txt,slicePos); //console.log(leftText); //console.log(rightText); var tagLeft = false; var tagLeftCount = 0; for (var i = 0; i < leftText.length; i++) { tagLeftCount++; //console.log('left '+i+':',leftText.slice(leftText.length - i)); if (leftText.slice(leftText.length - i).indexOf('>>') == 0) break; if (leftText.slice(leftText.length - i).indexOf('<<') == 0) { tagLeft = true; break; } } var tagRight = false; var tagRightCount = 0; for (var j = 0; j < rightText.length; j++) { tagRightCount++; //console.log('right '+j+':',rightText.slice(j)); if (rightText.slice(j).indexOf('<<') == 0) break; if (rightText.slice(j).indexOf('>>') == 0) { tagRight = true; break; } } //console.log(tagLeft,tagRight,tagLeftCount,tagRightCount); if (tagLeft == true && tagRight == true) { if (tagLeftCount <= tagRightCount) { slicePos -= tagLeftCount; } else { slicePos += tagRightCount; } } // test if '<',slicePos,'<' or '>',slicePos,'>' if (leftText.slice(-1) == '<' && rightText.slice(0,1) == '<' && rightText.slice(0,2) !== '<<') slicePos--; if (leftText.slice(-1) == '>' && leftText.slice(-2) !== '>>' && rightText.slice(0,1) == '>') slicePos++; return slicePos; } function startMathsInput(e,startCursorPos) { deselectMathsInput(e,true); window.addEventListener('keydown', hardKeyMathsInput, false); canvas.addEventListener('mousedown', endMathsInput, false); // clicking anywhere on the canvas will end the input canvas.addEventListener('touchstart', endMathsInput, false); // touching anywhere on the canvas will end the input /*// clicking a holder button will end the input if (typeof holderButton !== 'undefined') { for (i = 0; i < 3; i++) { holderButton[i].addEventListener('mousedown', endMathsInput, false); holderButton[i].addEventListener('touchstart', endMathsInput, false); } } for (i = 0; i < taskObject[pageIndex].length; i++) { // clicking any other object will also end the input if (endInputExceptions.indexOf(taskObject[pageIndex][i]) == -1) { taskObject[pageIndex][i].addEventListener('mousedown', endMathsInput, false); taskObject[pageIndex][i].addEventListener('touchstart', endMathsInput, false); } }*/ if (e.target) { var inputCanvas = e.target; } else { var inputCanvas = e; }; for (i = 0; i < mathsInput[pageIndex].length; i++) { if (mathsInput[pageIndex][i].cursorCanvas == inputCanvas || mathsInput[pageIndex][i].canvas == inputCanvas || mathsInput[pageIndex][i] == inputCanvas) { currMathsInput = mathsInput[pageIndex][i]; currMathsInputId = i; } } if (currMathsInput.transparent == false && currMathsInput.selectColor !== 'none') { currMathsInput.canvas.style.backgroundColor = "#FCF"; } else if (currMathsInput.transparent == false || currMathsInput.selectColor == 'none') { currMathsInput.canvas.style.backgroundColor = "#transparent"; } inputState = true; // allows the onscreen keys to function var closestPos = getClosestTextPos(); //console.log(currMathsInput,closestPos,currMathsInput.selectable,startCursorPos); if (currMathsInput.selectable == true && typeof startCursorPos == 'undefined') { currMathsInput.selectPos = [closestPos,closestPos]; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); if (typeof currMathsInput.pointerCanvas !== 'object') { addListenerMove(currMathsInput.cursorCanvas,selectTextMove); addListenerEnd(currMathsInput.cursorCanvas,selectTextStop); } } else { mathsInputMapCursorPos(); currMathsInput.cursorPos = startCursorPos || Number(closestPos) || 0; //console.log(currMathsInput,currMathsInput.cursorPos,currMathsInput.cursorMap[currMathsInput.cursorPos],currMathsInput.textLoc); mathsInputCursorCoords(); updateKeyboardCurrFont(); showKeyboard2(true); } if (!un(currMathsInput.markPos)) { currMathsInput.markctx.clearRect(currMathsInput.markPos[0]-5,currMathsInput.markPos[1]-5,currMathsInput.markPos[2]+10,currMathsInput.markPos[3]+10); } //shiftOn = false; //ctrlOn = false; //altOn = false; if (!un(window.textMenu) && typeof textMenu.show == 'function' && textMenu.showOnStartInput == true) { textMenu.update(); textMenu.show(); } } function selectTextMove(e) { updateMouse(e); var closestPos = getClosestTextPos(); //console.log(closestPos); if (currMathsInput.selectPos[1] !== closestPos) { currMathsInput.selectPos[1] = closestPos; //console.log(currMathsInput.selectPos); currMathsInput.selected = true; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); } console.log(currMathsInput.selectPos); //console.log('selectTextMove',currMathsInput.selected); } function selectTextStop(e) { //console.log(currMathsInput.selectPos); removeListenerMove(currMathsInput.cursorCanvas,selectTextMove); removeListenerEnd(currMathsInput.cursorCanvas,selectTextStop); if (currMathsInput.selectPos[0] == currMathsInput.selectPos[1]) { currMathsInput.cursorPos = currMathsInput.selectPos[0]; currMathsInput.selectPos = []; currMathsInput.selected = false; setSelectPositions(); mathsInputMapCursorPos(); mathsInputCursorCoords(); } updateKeyboardCurrFont(); showKeyboard2(true); } function getClosestTextPos(mathsInput) { if (!mathsInput) mathsInput = currMathsInput; // search through text character locations for a mouse hit test var mousePos = [mouse.x-mathsInput.data[100],mouse.y-mathsInput.data[101]]; //console.log(mathsInput); if (typeof mathsInput.cursorMap == 'undefined') { mathsInputMapCursorPos(); } var map = mathsInput.cursorMap; var closestPos = 0; var closestDist; var vertDist; var closestVertDist; //console.log('getClosestTextPos()'); //console.clear(); for (var pos = 0; pos < map.length; pos++) { var loc = mathsInput.textLoc; for (var aa = 0; aa < map[pos].length; aa++) { loc = loc[map[pos][aa]]; }; /* var ctx = mathsInput.ctx; ctx.strokeStyle = '#F0F'; ctx.beginPath(); ctx.moveTo(loc.left,loc.top); ctx.lineTo(loc.left,loc.top+loc.height); ctx.stroke(); */ if (!loc) continue; if (pos == 0) { closestDist = distancePointToLineSegment(mousePos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); closestPos = pos; vertDist = Math.min(Math.abs(mousePos[1]-loc.top),Math.abs(mousePos[1]-(loc.top+loc.height))); if (mousePos[1] >= loc.top && mousePos[1] <= loc.top + loc.height) vertDist = 0; closestVertDist = vertDist; } else { var newDist = distancePointToLineSegment(mousePos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); var newVertDist = Math.min(Math.abs(mousePos[1]-loc.top),Math.abs(mousePos[1]-(loc.top+loc.height))); if (mousePos[1] >= loc.top && mousePos[1] <= loc.top + loc.height) newVertDist = 0; if (newVertDist < closestVertDist || (newVertDist == closestVertDist && newDist < closestDist)) { closestVertDist = newVertDist; closestDist = newDist; closestPos = pos; } } //console.log(pos,loc.left,newDist,closestDist,closestPos) } /* ctx.beginPath(); ctx.moveTo(mousePos[0]-3,mousePos[1]-3); ctx.lineTo(mousePos[0]+3,mousePos[1]+3); ctx.moveTo(mousePos[0]-3,mousePos[1]+3); ctx.lineTo(mousePos[0]+3,mousePos[1]-3); ctx.stroke(); */ //console.log(closestPos); if (isNaN(closestPos) || typeof closestPos == 'undefined' || closestPos == null) { closestPos = 0; } return closestPos; } function endMathsInput(e) { if (!un(e) && !un(keyboardButton1) && !un(keyboardButton1[pageIndex]) && e.target == keyboardButton1[pageIndex]) return; if (!un(e) && !un(keyboardButton2) && !un(keyboardButton2[pageIndex]) && e.target == keyboardButton2[pageIndex]) return; if (un(currMathsInput)) return; if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } deselectMathsInput(e); if (typeof currMathsInput.onInputEnd == 'function') { currMathsInput.onInputEnd(e); } } function deselectMathsInput(e,diffInput) { if (un(currMathsInput)) return; currMathsInput.preText = ''; currMathsInput.postText = ''; if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } // test if the deselection is caused by a new input var diffInputTest = -1; if (typeof e == 'object' && e && typeof e.target == 'object' && e.target !== currMathsInput.canvas && !un(mathsInput[pageIndex])) { for (var i = 0; i < mathsInput[pageIndex].length; i++) { if (mathsInput[pageIndex][i].cursorCanvas == e.target) { if (currMathsInput.canvas == e.target) { return; // indicates the currently active mathsInput has been reclicked - do nothing } else { diffInputTest = i; } break; } } } if ((typeof diffInput !== 'undefined' && diffInput == true) || diffInputTest > -1) { } else { hideKeyboard2(true); inputState = false; // remove event listeners for mathsInput window.removeEventListener('keydown', hardKeyMathsInput, false); canvas.removeEventListener('mousedown', endMathsInput, false); canvas.removeEventListener('touchstart', endMathsInput, false); } //currMathsInput.currBackColor = currMathsInput.backColor; /* currMathsInput.ctx.clearRect(0, 0, currMathsInput.data[2], currMathsInput.data[3]); if (currMathsInput.transparent == false && currMathsInput.backColor !== 'none') { currMathsInput.ctx.fillStyle = currMathsInput.backColor || '#FFF'; } */ currMathsInput.canvas.style.backgroundColor = currMathsInput.backColor || 'transparent'; if (currMathsInput.backColor == 'none') { currMathsInput.canvas.style.backgroundColor = 'transparent' } clearCorrectingInterval(mathsInputCursorBlinkInterval); inputCursorState = false blinking = false; currMathsInput.cursorctx.clearRect(0,0,1200,700); if ((typeof diffInput !== 'undefined' && diffInput == true) || diffInputTest > -1) { if (typeof currMathsInput.onInputEnd == 'function') { currMathsInput.onInputEnd(); } } else { if (!un(window.textMenu)) { if (typeof textMenu.show == 'function' && textMenu.showOnStartInput == true) { textMenu.hide(); } } } if (typeof holderButton !== 'undefined') { for (var i = 0; i < 3; i++) { holderButton[i].removeEventListener('mousedown', endMathsInput, false); holderButton[i].removeEventListener('mousedown', endMathsInput, false); } } /*var startAt = 0; if (taskKey[pageIndex]) {startAt = taskKey[pageIndex].length} function listenerForI(i) { taskObject[pageIndex][i].removeEventListener('mousedown', endMathsInput, false); taskObject[pageIndex][i].removeEventListener('touchstart', endMathsInput, false); } if (taskObject[pageIndex]) { for (var i = startAt; i < taskObject[pageIndex].length; i++) { // clicking any other object will also end the input listenerForI(i); //'scopes' the variable i } }*/ } function setSelectPositions() { // check for a need to adjust each selectPos var selPos1 = clone(currMathsInput.cursorMap[currMathsInput.selectPos[0]]); if (typeof selPos1 !== 'undefined') { var txt = clone(currMathsInput.richText); for (var i = 0; i < selPos1.length - 1; i++) {txt = txt[selPos1[i]]}; var txtSlice = txt.slice(0,selPos1[selPos1.length-1]); if (txtSlice.indexOf('<>') > -1) { selPos1[selPos1.length-1] -= 17; } if (txtSlice.indexOf('<>') > -1) { selPos1[selPos1.length-1] -= 18; } } var selPos2 = clone(currMathsInput.cursorMap[currMathsInput.selectPos[1]]); if (typeof selPos2 !== 'undefined') { var txt = clone(currMathsInput.richText); for (var i = 0; i < selPos2.length - 1; i++) {txt = txt[selPos2[i]]}; var txtSlice = txt.slice(0,selPos2[selPos2.length-1]); if (txtSlice.indexOf('<>') > -1) { selPos2[selPos2.length-1] -= 17; } if (txtSlice.indexOf('<>') > -1) { selPos2[selPos2.length-1] -= 18; } } removeSelectTags(); if (arraysEqual(currMathsInput.selectPos,[]) == false) { if (currMathsInput.selectPos[0] == currMathsInput.selectPos[1]) { insertTag('<><>',selPos1); } else if (currMathsInput.selectPos[0] > currMathsInput.selectPos[1]) { insertTag('<>',selPos1); insertTag('<>',selPos2); } else if (currMathsInput.selectPos[0] < currMathsInput.selectPos[1]) { insertTag('<>',selPos2); insertTag('<>',selPos1); } } function insertTag(insertion,cursorPos) { // get the relevant string from currMathsInput.richText var text = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) { text = text[cursorPos[aa]]; } // pos is position of cursor var pos = cursorPos[cursorPos.length - 1]; // adjust pos to account for breakPoints if (typeof currMathsInput.breakPoints == 'object') { for (var k = 0; k < currMathsInput.breakPoints.length - 1; k++) { var breakPoint = currMathsInput.allMap[currMathsInput.breakPoints[k]]; if (breakPoint[0] == cursorPos[0] && breakPoint[1] < cursorPos[1]) { pos--; } } } // check that a tag is not being split - if so adjust pos var leftText = text.slice(0,pos); var rightText = text.slice(pos); var tagLeft = false; var tagLeftCount = 0; for (var i = 0; i < leftText.length; i++) { tagLeftCount++; if (leftText.slice(leftText.length - i).indexOf('>>') == 0) break; if (leftText.slice(leftText.length - i).indexOf('<<') == 0) { tagLeft = true; break; } } var tagRight = false; var tagRightCount = 0; for (var j = 0; j < rightText.length; j++) { tagRightCount++; if (rightText.slice(j).indexOf('<<') == 0) break; if (rightText.slice(j).indexOf('>>') == 0) { tagRight = true; break; } } if (tagLeft == true && tagRight == true) { if (tagLeftCount <= tagRightCount) { pos -= tagLeftCount; } else { pos += tagRightCount; } } var leftText = text.slice(0,pos); var rightText = text.slice(pos); if (leftText.slice(-1) == '<' && rightText.slice(0,1) == '<' && rightText.slice(0,2) !== '<<') pos--; if (leftText.slice(-1) == '>' && leftText.slice(-2) !== '>>' && rightText.slice(0,1) == '>') pos++; var textBefore = text.slice(0,pos); var textAfter = text.slice(pos); text = textBefore + insertion + textAfter; // replace the string var evalString = 'currMathsInput.richText' for (aa = 0; aa < cursorPos.length - 1; aa++) { evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ' = text;'); } } function removeSelectTags() { var map1; var map2; var pos = []; function arrayHandler(array) { pos.push(0); for (var l = array.length - 1; l >= 0; l--) { pos[pos.length-1] = l; if (typeof array[l] == 'string') { array[l] = stringHandler(array[l]); } else { array[l] = arrayHandler(array[l]); } } pos.pop(); return array; } function stringHandler(string) { //console.log(string,JSON.stringify(pos)); for (var j = string.length - 1; j >= 0; j--) { var slice = string.slice(j); if (slice.indexOf('<>') == 0) { string = string.slice(0,j)+string.slice(j+slice.indexOf('>>')+2); if (typeof map1 !== 'undefined' && arraysEqual(pos,map1) == true && map2 > j) { map2 = Math.max(0,map2-18); } } if (slice.indexOf('<>') == 0) { string = string.slice(0,j)+string.slice(j+slice.indexOf('>>')+2); if (typeof map1 !== 'undefined' && arraysEqual(pos,map1) == true && map2 > j) { map2 = Math.max(0,map2-17); } } } return string; } //console.log(JSON.stringify(currMathsInput.cursorMap[currMathsInput.cursorPos])); if (typeof currMathsInput.cursorPos == 'number') { map1 = currMathsInput.cursorMap[currMathsInput.cursorPos]; if (typeof map1 !== 'undefined') { map2 = map1[map1.length-1]; map1 = map1.slice(0,-1); //console.log(JSON.stringify(map1),map2); } } currMathsInput.richText = arrayHandler(currMathsInput.richText); //console.log('---',map2); if (typeof map2 !== 'undefined') { currMathsInput.cursorMap[currMathsInput.cursorPos][currMathsInput.cursorMap[currMathsInput.cursorPos].length-1] = map2; } // adjust cursorPos if necessary } function removeSelectTagsFromArray(textArray) { var map1; var map2; var pos = []; function arrayHandler(array) { pos.push(0); for (var l = array.length - 1; l >= 0; l--) { pos[pos.length-1] = l; if (typeof array[l] == 'string') { array[l] = stringHandler(array[l]); } else { array[l] = arrayHandler(array[l]); } } pos.pop(); return array; } function stringHandler(string) { //console.log(string,JSON.stringify(pos)); for (var j = string.length - 1; j >= 0; j--) { var slice = string.slice(j); if (slice.indexOf('<>') == 0) { string = string.slice(0,j)+string.slice(j+slice.indexOf('>>')+2); if (typeof map1 !== 'undefined' && arraysEqual(pos,map1) == true && map2 > j) { map2 = Math.max(0,map2-18); } } if (slice.indexOf('<>') == 0) { string = string.slice(0,j)+string.slice(j+slice.indexOf('>>')+2); if (typeof map1 !== 'undefined' && arraysEqual(pos,map1) == true && map2 > j) { map2 = Math.max(0,map2-17); } } } return string; } return arrayHandler(textArray); } function deleteSelected() { var sel = false; currMathsInput.richText = arrayHandler(currMathsInput.richText); function arrayHandler(array) { for (var l = 0; l < array.length; l++) { if (typeof array[l] == 'string') { if (l > 0 || array.length == 1 || ['frac','power','pow','subs','subscript','sin','cos','tan','ln','log','logBase','sin-1','cos-1','tan-1','abs','exp','root','sqrt','sigma1','sigma2','int1','int2','recurring','bar','hat','vectorArrow','colVector2d','colVector3d','mixedNum','lim'].indexOf(array[l]) == -1) { array[l] = stringHandler(array[l]); } } else { var preSel = false; if (sel == true) {preSel = true}; array[l] = arrayHandler(array[l]); if (sel == true && preSel == true) { array.splice(l,1); l--; } } } return array; } function stringHandler(string) { var delPos = []; if (sel == true) delPos[0] = 0; var savedTags = ''; for (var j = 0; j < string.length; j++) { var slice = string.slice(j); if (slice.indexOf('<>') == 0) { delPos[0] = j; sel = true; } if (slice.indexOf('<>') == 0) { delPos[1] = j + 18; sel = false; } if (sel == true && (slice.indexOf('<>')+2); } } if (delPos.length > 0) { if (delPos.length == 1) { return string.slice(0,delPos[0])+savedTags; } else { return string.slice(0,delPos[0])+savedTags+string.slice(delPos[1]); } } else { return string; } } } function mathsInputMapCursorPos() { // (re-)builds cursor map currMathsInput.richText = reduceTags(currMathsInput.richText); currMathsInput.richText = combineSpacesCursor(currMathsInput.richText); // create new cursor map currMathsInput.textLoc = []; drawMathsInputText(currMathsInput); currMathsInput.cursorMap = mapArray(currMathsInput.textLoc,false); // create new allMap - this includes all markup tag characters currMathsInput.allMap = mapArray(currMathsInput.textLoc,true); // move cursor positions in cursorMap from end to beginning of markup tags (except for beginning) var cursorMap = currMathsInput.cursorMap; //console.log(currMathsInput.cursorPos,JSON.stringify(cursorMap)); for (var i = 1; i < cursorMap.length; i++) { // get text element var richText = currMathsInput.richText; for (var j = 0; j < cursorMap[i].length - 1; j++) richText = richText[cursorMap[i][j]]; // char is position of cursor var char = cursorMap[i][cursorMap[i].length-1]; // adjust char to account for breakPoints if (typeof currMathsInput.breakPoints == 'object') { for (var k = 0; k < currMathsInput.breakPoints.length - 1; k++) { var breakPoint = currMathsInput.allMap[currMathsInput.breakPoints[k]]; if (breakPoint[0] == cursorMap[i][0] && breakPoint[1] < cursorMap[i][1]) { char--; } } } // if proceeded by a tag if (richText.slice(char-2).indexOf('>>') == 0 && richText.slice(char-6).indexOf('<
>') !== 0) { // get text to the left of char var leftText = richText.slice(0,char); // get tagCharCount to the left of char var tagCharCount = 0; for (var j = 0; j < leftText.length; j++) { if (richText.slice(char-j,char).indexOf('<<') == 0 && (leftText.slice(char-j-2,char).indexOf('>>') !== 0 || leftText.slice(char-j-6,char).indexOf('<
>') == 0)) { tagCharCount = j; break; } } // check that it's not the very beginning if (cursorMap[i][0] == 0 && cursorMap[i][1] == tagCharCount) continue; // alter the cursorMap by tagCharCount currMathsInput.cursorMap[i][currMathsInput.cursorMap[i].length-1] -= tagCharCount; } } // update currMathsInput.text to be the same as currMathsInput.richText without any markuptags currMathsInput.text = clone(currMathsInput.richText); for (var p = 0; p < currMathsInput.text.length; p++) { currMathsInput.text[p] = removeTags(currMathsInput.text[p]); } } function combineSpacesCursor(array) { //console.log(array.length); if (array.length > 1) { for (var gg = array.length - 1; gg >= 0; gg--) { //console.log(gg, array[gg], typeof array[gg]); if (typeof array[gg] == 'object') { arrayString += '[' + gg + ']'; combineSpacesCursor(array[gg]); } else { if (gg < array.length - 1 && typeof array[gg] == 'string' && typeof array[gg+1] == 'string') { eval('currMathsInput.richText' + arrayString + '[' + gg + '] += currMathsInput.richText' + arrayString + '[' + (gg+1) + ']'); eval('currMathsInput.richText' + arrayString + '.splice(gg+1, 1);'); } } } } arrayString = arrayString.slice(0, arrayString.lastIndexOf('[') - arrayString.length); return array; } function combineSpacesTextArray(array) { if (array.length > 1) { for (var i = array.length - 1; i >= 0; i--) { if (typeof array[i] == 'object') { if (i < array.length - 1 && typeof array[i] == 'string' && typeof array[i+1] == 'string') { array[i] = array[i] + array[i+1]; array.splice(i+1,1); } } else { combineSpacesTextArray(array[i]); } } } return array; } function mathsInputCursorCoords() { // updates cursor coordinates drawMathsInputText(currMathsInput); var char; var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; if (typeof cursorPos == 'undefined') return; char = currMathsInput.textLoc; for (var aa = 0 ; aa < cursorPos.length; aa++) { char = char[cursorPos[aa]]; } mathsInputCursor.x = char.left; mathsInputCursor.top = char.top; mathsInputCursor.bottom = char.top + char.height; //logText(true); //console.log('mathsInputCursor:',mathsInputCursor); inputCursorState = false; clearCorrectingInterval(mathsInputCursorBlinkInterval); drawMathsInputText(currMathsInput); mathsInputCursorBlink(); mathsInputCursorBlinkInterval = setCorrectingInterval(function(){mathsInputCursorBlink()}, 600); blinking = true; currMathsInput.stringJS = createJsString(); if (typeof textMenu !== 'undefined' && typeof textMenu !== 'undefined' && typeof textMenu.update == 'function') textMenu.update(); } var showCursorPos = false; function adjustForBreakPointsAllMap(pos) { //console.log('pos:',pos); if (typeof currMathsInput.breakPoints == 'object') { //console.log('pos:',pos); var map = currMathsInput.allMap[pos]; for (var i = 0; i < currMathsInput.breakPoints.length - 1; i++) { var iBreak = currMathsInput.allMap[currMathsInput.breakPoints[i]]; if (iBreak[0] == map[0] && iBreak[1] < map[1]) { pos--; } } //console.log('pos:',pos); } return pos; } function adjustForBreakPoints(pos,map,breakPoints) { if (typeof pos == 'undefined') pos = currMathsInput.cursorPos; if (typeof map == 'undefined') map = currMathsInput.cursorMap[currMathsInput.cursorPos]; if (typeof breakPoints == 'undefined') breakPoints = currMathsInput.breakPoints; if (typeof breakPoints == 'object') { for (var i = 0; i < breakPoints.length - 1; i++) { var iBreak = currMathsInput.allMap[breakPoints[i]]; //if (i > 0 && iBreak[1] - currMathsInput.allMap[breakPoints[i-1]][1] <= 7) continue; //console.log(iBreak,iBreak[0] == map[0] && iBreak[1] < map[1]); if (iBreak[0] == map[0] && iBreak[1] < map[1]) { pos--; } } } return pos; } function mathsInputCursorBlink() { if (inputCursorState == true) {inputCursorState = false} else {inputCursorState = true}; currMathsInput.cursorctx.clearRect(0,0,1200,700); currMathsInput.cursorCanvas.style.zIndex = currMathsInput.canvas.style.zIndex + 1; if (showCursorPos == true) { for (var i = 0; i < currMathsInput.cursorMap.length; i++) { var cPos = currMathsInput.textLoc; for (var j = 0; j < currMathsInput.cursorMap[i].length; j++) { cPos = cPos[currMathsInput.cursorMap[i][j]]; } // adjust cPos to account for difference between canvas and cursor canvas positions cPos.left += (currMathsInput.data[100] - currMathsInput.cursorData[100]); cPos.top += (currMathsInput.data[101] - currMathsInput.cursorData[101]); //console.log(cPos); currMathsInput.cursorctx.save(); currMathsInput.cursorctx.strokeStyle = '#F00'; currMathsInput.cursorctx.lineWidth = 2; currMathsInput.cursorctx.beginPath(); currMathsInput.cursorctx.moveTo(cPos.left, cPos.top); currMathsInput.cursorctx.lineTo(cPos.left, cPos.top + cPos.height); currMathsInput.cursorctx.closePath(); currMathsInput.cursorctx.stroke(); currMathsInput.cursorctx.restore(); } } else if (inputCursorState == true && currMathsInput.selected == false) { var hAdjust = currMathsInput.data[100] - currMathsInput.cursorData[100]; var vAdjust = currMathsInput.data[101] - currMathsInput.cursorData[101]; //console.log('blink',inputCursorState,currMathsInput.selected,mathsInputCursor,currMathsInput.cursorPos,hAdjust,vAdjust); currMathsInput.cursorctx.save(); currMathsInput.cursorctx.strokeStyle = currMathsInput.textColor; currMathsInput.cursorctx.lineWidth = 2; currMathsInput.cursorctx.beginPath(); currMathsInput.cursorctx.moveTo(hAdjust + mathsInputCursor.x, vAdjust + mathsInputCursor.top); currMathsInput.cursorctx.lineTo(hAdjust + mathsInputCursor.x, vAdjust + mathsInputCursor.bottom); currMathsInput.cursorctx.closePath(); currMathsInput.cursorctx.stroke(); currMathsInput.cursorctx.restore(); } else { //console.log('blink',inputCursorState,currMathsInput.selected,mathsInputCursor,currMathsInput.cursorPos); } } //var shiftOn = false; //window.addEventListener('keyup', shiftKeyUp, false); /*function shiftKeyUp(e) { e.preventDefault(); if (e.keyCode == 16) { shiftOn = false; } }*/ function hardKeyMathsInput(e) { // if a key is pressed via the hardware keyboard e.preventDefault(); if (inputState == true) { var charCode = e.keyCode; // determine which key has been pressed var keysToIgnore = [16,17,18,27,33,34,35,36,46,112,113,114,115,116,117,118,119,120,121,122,123,144,223]; if (e.getModifierState('Control')) { if (charCode == 88) { //CTRL-x mathsInputCut(); } else if (charCode == 67) { //CTRL-c mathsInputCopy(); } else if (charCode == 86) { //CTRL-v mathsInputPaste(); } return; } if (e.getModifierState('Alt')) return; switch (charCode) { case 37 : // left arrow currMathsInput.preText = ''; currMathsInput.postText = ''; if (e.getModifierState('Shift') == true && currMathsInput.cursorPos > 0) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = [currMathsInput.cursorPos-1]; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos--; } else { currMathsInput.selected = true; currMathsInput.selectPos = [currMathsInput.cursorPos,currMathsInput.cursorPos-1]; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos--; } } else if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } else if (currMathsInput.cursorPos > 0) { currMathsInput.cursorPos--; mathsInputCursorCoords(); } else { mathsInputTabPrev(); } break; case 38 : // up arrow currMathsInput.preText = ''; currMathsInput.postText = ''; if (e.getModifierState('Shift') == true) { if (currMathsInput.selected == false) { currMathsInput.selectPos[0] = currMathsInput.cursorPos; } } else if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get the parent of the current string var parent = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 3; i++) {parent = parent[cursorPos[i]]}; if (parent[0] == 'frac' && cursorPos[cursorPos.length - 3] == 2) { currMathsInput.cursorPos -= cursorPos[cursorPos.length - 1]; currMathsInput.cursorPos--; mathsInputCursorCoords(); } else { // check if there is a row above var lowerBreakPoints = []; for (var i = 0; i < currMathsInput.breakPoints.length - 1; i++) { if (currMathsInput.allMap[currMathsInput.breakPoints[i]][0] < currMathsInput.cursorMap[currMathsInput.cursorPos][0] || (currMathsInput.allMap[currMathsInput.breakPoints[i]][0] == currMathsInput.cursorMap[currMathsInput.cursorPos][0] && currMathsInput.allMap[currMathsInput.breakPoints[i]][1] < currMathsInput.cursorMap[currMathsInput.cursorPos][1])) { lowerBreakPoints.unshift(currMathsInput.allMap[currMathsInput.breakPoints[i]]); } } if (lowerBreakPoints.length == 0) { // cursor is on top line if (shiftOn == true) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = 0; } else { currMathsInput.selectPos = [currMathsInput.cursorPos,0]; currMathsInput.selected = true; } setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos = 0; } } else { // get top point of current cursor position var textLoc = currMathsInput.textLoc; for (var i = 0; i < currMathsInput.cursorMap[currMathsInput.cursorPos].length; i++) { textLoc = textLoc[currMathsInput.cursorMap[currMathsInput.cursorPos][i]]; } var pos = [textLoc.left,textLoc.top]; // search through textLocs var closestPos; var closestDist; for (var i = 0; i < currMathsInput.cursorMap.length; i++) { // position must be less than lowerBreakPoints[0] if (currMathsInput.cursorMap[i][0] < lowerBreakPoints[0][0] || (currMathsInput.cursorMap[i][0] == lowerBreakPoints[0][0] && currMathsInput.cursorMap[i][1] < lowerBreakPoints[0][1])) { // if it is above the current line // position must not be less than lowerBreakPoints[1] if (lowerBreakPoints.length > 1) { if (currMathsInput.cursorMap[i][0] < lowerBreakPoints[1][0] || (currMathsInput.cursorMap[i][0] == lowerBreakPoints[1][0] && currMathsInput.cursorMap[i][1] < lowerBreakPoints[1][1])) continue; } var loc = currMathsInput.textLoc; for (var j = 0; j < currMathsInput.cursorMap[i].length; j++) { loc = loc[currMathsInput.cursorMap[i][j]]; } if (typeof closestPos == 'undefined') { closestPos = i; closestDist = distancePointToLineSegment(pos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); } else { var newDist = distancePointToLineSegment(pos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); if (newDist < closestDist) { closestPos = i; closestDist = newDist; } } } } if (shiftOn == true) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = closestPos; } else { currMathsInput.selectPos = [currMathsInput.cursorPos,closestPos]; currMathsInput.selected = true; } setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos = closestPos; } else { currMathsInput.cursorPos = closestPos; mathsInputCursorCoords(); } } } break; case 39 : // right arrow currMathsInput.preText = ''; currMathsInput.postText = ''; if (e.getModifierState('Shift') == true && currMathsInput.cursorPos > 0) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = [currMathsInput.cursorPos+1]; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos++; } else { currMathsInput.selected = true; currMathsInput.selectPos = [currMathsInput.cursorPos,currMathsInput.cursorPos+1]; setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos++; } } else if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.max(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } else if (currMathsInput.cursorPos < currMathsInput.cursorMap.length - 1) { currMathsInput.cursorPos++; mathsInputCursorCoords(); } else { mathsInputTabNext(); } break; case 40 : // down arrow currMathsInput.preText = ''; currMathsInput.postText = ''; if (e.getModifierState('Shift') == true) { if (currMathsInput.selected == false) { currMathsInput.selectPos[0] = currMathsInput.cursorPos; } } else if (currMathsInput.selected == true) { removeSelectTags(); mathsInputMapCursorPos(); currMathsInput.cursorPos = Math.max(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selectPos = []; mathsInputCursorCoords(); currMathsInput.selected = false; removeSelectTags(); } var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get the parent of the current string var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 3; aa++) {parent = parent[cursorPos[aa]]}; if (parent[0] == 'frac' && cursorPos[cursorPos.length - 3] == 1) { // move to the beginning of the denominator text do { currMathsInput.cursorPos++; var cursorPos2 = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get the parent of the cursorPos var parent2 = currMathsInput.richText; for (var aa = 0; aa < cursorPos2.length - 3; aa++) {parent2 = parent2[cursorPos2[aa]]}; } while ((parent2 !== parent) || (parent2 == parent && cursorPos2[cursorPos.length - 3] !== 2)); // move to the end of the denominator text do { currMathsInput.cursorPos++; var cursorPos2 = currMathsInput.cursorMap[currMathsInput.cursorPos]; } while (cursorPos2.length >= cursorPos.length); currMathsInput.cursorPos--; mathsInputCursorCoords(); } else { var higherBreakPoints = []; for (var i = 0; i < currMathsInput.breakPoints.length - 1; i++) { if (currMathsInput.allMap[currMathsInput.breakPoints[i]][0] > currMathsInput.cursorMap[currMathsInput.cursorPos][0] || (currMathsInput.allMap[currMathsInput.breakPoints[i]][0] == currMathsInput.cursorMap[currMathsInput.cursorPos][0] && currMathsInput.allMap[currMathsInput.breakPoints[i]][1] > currMathsInput.cursorMap[currMathsInput.cursorPos][1])) { higherBreakPoints.push(currMathsInput.allMap[currMathsInput.breakPoints[i]]); } } if (higherBreakPoints.length == 0) { // cursor is on bottom line if (shiftOn == true) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = currMathsInput.cursorMap.length - 1; } else { currMathsInput.selectPos = [currMathsInput.cursorPos,currMathsInput.cursorMap.length - 1]; currMathsInput.selected = true; } setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos = currMathsInput.cursorMap.length - 1; } } else { // get bottom point of current cursor position var textLoc = currMathsInput.textLoc; for (var i = 0; i < currMathsInput.cursorMap[currMathsInput.cursorPos].length; i++) { textLoc = textLoc[currMathsInput.cursorMap[currMathsInput.cursorPos][i]]; } var pos = [textLoc.left,textLoc.top+textLoc.height]; // search through textLocs var closestPos; var closestDist; for (var i = 0; i < currMathsInput.cursorMap.length; i++) { // position must be more than higherBreakPoints[0] if (currMathsInput.cursorMap[i][0] > higherBreakPoints[0][0] || (currMathsInput.cursorMap[i][0] == higherBreakPoints[0][0] && currMathsInput.cursorMap[i][1] > higherBreakPoints[0][1])) { // if it is above the current line // position must not be less than higherBreakPoints[1] if (higherBreakPoints.length > 1) { if (currMathsInput.cursorMap[i][0] > higherBreakPoints[1][0] || (currMathsInput.cursorMap[i][0] == higherBreakPoints[1][0] && currMathsInput.cursorMap[i][1] > higherBreakPoints[1][1])) continue; } var loc = currMathsInput.textLoc; for (var j = 0; j < currMathsInput.cursorMap[i].length; j++) { loc = loc[currMathsInput.cursorMap[i][j]]; } if (typeof closestPos == 'undefined') { closestPos = i; closestDist = distancePointToLineSegment(pos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); } else { var newDist = distancePointToLineSegment(pos,[loc.left,loc.top],[loc.left,loc.top+loc.height]); if (newDist < closestDist) { closestPos = i; closestDist = newDist; } } } } if (shiftOn == true) { if (currMathsInput.selected == true) { currMathsInput.selectPos[1] = closestPos; } else { currMathsInput.selectPos = [currMathsInput.cursorPos,closestPos]; currMathsInput.selected = true; } setSelectPositions(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); currMathsInput.cursorPos = closestPos; } else { currMathsInput.cursorPos = closestPos; mathsInputCursorCoords(); } } } break; case 8 : // backspace key pressed currMathsInput.preText = ''; currMathsInput.postText = ''; if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } else if (currMathsInput.cursorPos > 0) { removeSelectTags(); // get the relevant string from currMathsInput.richText // ie. currMathsInput.richText[cursorPos[0]][cursorPos[1]]...[cursorPos[n]] var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; var pos = cursorPos[cursorPos.length - 1]; pos = adjustForBreakPoints(pos); var text = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 1; i++) {text = text[cursorPos[i]]}; var parent; if (cursorPos.length > 1) { parent = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 2; i++) {parent = parent[cursorPos[i]]}; } var grandParent; if (cursorPos.length > 2) { grandParent = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 3; i++) {grandParent = grandParent[cursorPos[i]]}; } if (text !== '') { if (pos !== 0) { //console.clear(); //console.log(1,text,pos,text.slice(pos-1)); if (text.slice(pos-6).indexOf('<
>') == 0) { text = text.slice(0, pos-6) + text.slice(pos); } else { text = text.slice(0, pos-1) + text.slice(pos); } //console.log(2,text); // replace the string var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 1; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ' = text;'); } } else { if (parent.length == 1) { // ie. empty string is only sub-element var elemsOneParam = ['sqrt', 'pow', 'power', 'subs', 'subscript', 'sin', 'cos', 'tan', 'sin-1', 'cos-1', 'tan-1', 'log', 'ln', 'abs', 'exp', 'sigma1', 'int1', 'vectorArrow', 'bar', 'hat', 'recurring']; var elemsTwoParams = ['root', 'frac', 'logBase', 'colVector2d', 'lim']; var elemsThreeParams = ['sigma2', 'int2', 'colVector3d', 'mixedNum']; if (elemsOneParam.indexOf(grandParent[0]) > -1 || (elemsTwoParams.indexOf(grandParent[0]) > -1 && cursorPos[cursorPos.length - 3] == 1) || (elemsThreeParams.indexOf(grandParent[0]) > -1 && cursorPos[cursorPos.length - 3] == 1)) { // conditions to delete // replace grandParent with ""; var evalString = 'currMathsInput.richText' for (var i = 0; i < cursorPos.length - 3; i++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[i] + ']'; } eval(evalString + ' = "";'); } } } //console.log(JSON.stringify(currMathsInput.richText)); mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); } break; case 46 : // delete key currMathsInput.preText = ''; currMathsInput.postText = ''; if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } else if (currMathsInput.cursorPos < currMathsInput.cursorMap.length - 1) { // get the relevant string from currMathsInput.richText // ie. currMathsInput.richText[cursorPos[0]][cursorPos[1]]...[cursorPos[n]] var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; var pos = cursorPos[cursorPos.length - 1]; pos = adjustForBreakPoints(pos); var text = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 1; i++) {text = text[cursorPos[i]]}; if (cursorPos[cursorPos.length - 1] !== text.length) { if (text.slice(pos).indexOf('<
>') == 0) { text = text.slice(0,pos) + text.slice(pos+6); } else if (text.slice(pos).indexOf('<<') == 0) { //skip forward to end of tags var text2 = text.slice(pos); var endFound = false; var charCount = 0; do { var c = text2.indexOf('>>') + 2; charCount += c; var text2 = text2.slice(c); if (text2.indexOf('<<') !== 0) { endFound = true; } } while (endFound == false); pos += charCount; text = text.slice(0,pos) + text.slice(pos+1); } else { text = text.slice(0,pos) + text.slice(pos+1); } // replace the string var evalString = 'currMathsInput.richText' for (var i = 0; i < cursorPos.length - 1; i++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[i] + ']'; } eval(evalString + ' = text;'); mathsInputMapCursorPos(); mathsInputCursorCoords(); } } break; case 9 : // tab key pressed if (typeof draw !== 'undefined' && draw.drawMode == 'textEdit') { if (e.getModifierState('Control')) { mathsInputTab(10); } else if (e.getModifierState('Shift')) { mathsInputTab(5); } else { mathsInputTab(); } } else { mathsInputTabNext(); } break; case 13 : // enter key pressed if (currMathsInput.maxLines > 1 || (typeof draw !== 'undefined' && draw.drawMode == 'textEdit')) { if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } mathsInputNewLine(); } else { endMathsInput(e); } break; case 27 : // escape key pressed endMathsInput(e); break; /*case 16 : //shift key pressed shiftOn = true; window.addEventListener('keyup', shiftKeyUp, false); break;*/ default : // need to protect against << or >> being entered if (currMathsInput.text[0].length >= currMathsInput.maxChars) {break}; if (e.getModifierState('Shift') == true && charCode == 54/* && currMathsInput.cursorMap[currMathsInput.cursorPos].length == 2*/) { // if hat symbol is used and current text element is a text string mathsInputPow(); break; } if (keysToIgnore.indexOf(charCode) == -1) { if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } var caps = false; if (e.getModifierState('Shift') || e.getModifierState('CapsLock')) caps = true for (var ii = 0; ii < charMap.length; ii++) { if (charCode == charMap[ii][0]) { if (caps) { charCode = charMap[ii][2]; } else { charCode = charMap[ii][1]; } } } // if it is a letter key and shift is not pressed, use lower case instead of upper case if (!caps && charCode >= 65 && charCode <= 90) charCode += 32; var keyValue = String.fromCharCode(charCode); // get the relevant string from currMathsInput.richText // ie. currMathsInput.richText[cursorPos[0]][cursorPos[1]]...[cursorPos[n]] //console.log(currMathsInput.cursorMap,currMathsInput.cursorPos,currMathsInput.cursorMap[currMathsInput.cursorPos]); var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; /* console.log('currMathsInput.cursorMap:',JSON.stringify(currMathsInput.cursorMap,null,4),currMathsInput.cursorMap.length-1); console.log('currMathsInput.cursorPos:',JSON.stringify(currMathsInput.cursorPos,null,4)); console.log('currMathsInput.cursorMap[currMathsInput.cursorPos]:',JSON.stringify(currMathsInput.cursorMap[currMathsInput.cursorPos],null,4)); console.log('currMathsInput.richText[0]:',JSON.stringify(currMathsInput.richText[0],null,4),currMathsInput.richText[0].length-1); console.log('cursorPos:',JSON.stringify(cursorPos,null,4)); */ var text = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 1; i++) { text = text[cursorPos[i]]; } var slicePos = cursorPos[cursorPos.length - 1]; slicePos = adjustForBreakPoints(slicePos); /*var prev = 0; var breakPoints = currMathsInput.breakPoints; for (var b = 0; b < breakPoints.length; b++) { prev = breakPoints[b]; }*/ //console.log(text,slicePos); slicePos = mathsInputAvoidTagSplit(text,slicePos); /* this section replaced by the function above // check that a tag is not being split - if so adjust slicePos var leftText = text.slice(0,slicePos); var rightText = text.slice(slicePos); var tagLeft = false; var tagLeftCount = 0; for (var i = 0; i < leftText.length; i++) { tagLeftCount++; //console.log('left '+i+':',leftText.slice(leftText.length - i)); if (leftText.slice(leftText.length - i).indexOf('>>') == 0) break; if (leftText.slice(leftText.length - i).indexOf('<<') == 0) { tagLeft = true; break; } } var tagRight = false; var tagRightCount = 0; for (var j = 0; j < rightText.length; j++) { tagRightCount++; //console.log('right '+j+':',rightText.slice(j)); if (rightText.slice(j).indexOf('<<') == 0) break; if (rightText.slice(j).indexOf('>>') == 0) { tagRight = true; break; } } //console.log(tagLeft,tagRight,tagLeftCount,tagRightCount); if (tagLeft == true && tagRight == true) { if (tagLeftCount <= tagRightCount) { slicePos -= tagLeftCount; } else { slicePos += tagRightCount; } } // test if '<',slicePos,'<' or '>',slicePos,'>' if (leftText.slice(-1) == '<' && rightText.slice(0,1) == '<' && rightText.slice(0,2) !== '<<') slicePos--; if (leftText.slice(-1) == '>' && leftText.slice(-2) !== '>>' && rightText.slice(0,1) == '>') slicePos++;*/ if (un(currMathsInput.preText) || currMathsInput.preText == null) { var pre = ""; } else { var pre = currMathsInput.preText; } if (un(currMathsInput.postText) || currMathsInput.postText == null) { var post = ""; } else { var post = currMathsInput.postText; } text = text.slice(0, slicePos) + pre + keyValue + post + text.slice(slicePos); // replace the string var evalString = 'currMathsInput.richText' for (var i = 0; i < cursorPos.length - 1; i++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[i] + ']'; } eval(evalString + ' = text;'); //logText(); mathsInputMapCursorPos(); // set the last number of cursorMap[cursorPos+1] to be one more than cursorMap[cursorPos] //currMathsInput.cursorMap[currMathsInput.cursorPos + 1][currMathsInput.cursorMap[currMathsInput.cursorPos + 1].length - 1] = currMathsInput.cursorMap[currMathsInput.cursorPos][currMathsInput.cursorMap[currMathsInput.cursorPos].length - 1] + 1; currMathsInput.cursorPos += 1; mathsInputCursorCoords(); currMathsInput.preText = ''; currMathsInput.postText = ''; //logText(); } } } } function softKeyMathsInput(e) { //console.log(inputState); if (inputState == true) { /* if (mathsInputDoubleInput == true) { return; } else { mathsInputDoubleInput = true; setTimeout(function() { mathsInputDoubleInput = false; }, 250); } */ var keyNum; var keyValue; if (keyboard[pageIndex]) { keyNum = key1[pageIndex].indexOf(e.target); keyValue = key1Data[pageIndex][keyNum][6]; } //console.log(keyValue); if (keyValue == 'delete') { // if it's the delete button currMathsInput.preText = ''; currMathsInput.postText = ''; if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } else if (currMathsInput.cursorPos > 0) { // get the relevant string from currMathsInput.richText // ie. currMathsInput.richText[cursorPos[0]][cursorPos[1]]...[cursorPos[n]] var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; //console.log(cursorPos); var pos = cursorPos[cursorPos.length - 1]; //console.log(pos); pos = adjustForBreakPoints(pos); //console.log(pos); var text = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 1; i++) {text = text[cursorPos[i]]}; var parent; if (cursorPos.length > 1) { parent = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 2; i++) {parent = parent[cursorPos[i]]}; } var grandParent; if (cursorPos.length > 2) { grandParent = currMathsInput.richText; for (var i = 0; i < cursorPos.length - 3; i++) {grandParent = grandParent[cursorPos[i]]}; } if (text !== '') { if (pos !== 0) { //console.log(1,text,text.length,pos,text.slice(0, pos-1) + text.slice(pos)); if (text.slice(pos-6).indexOf('<
>') == 0) { text = text.slice(0, pos-6) + text.slice(pos); } else { text = text.slice(0, pos-1) + text.slice(pos); } //console.log(2,text); // replace the string var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 1; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ' = text;'); } } else { if (parent.length == 1) { // ie. empty string is only sub-element var elemsOneParam = ['sqrt', 'pow', 'power', 'subs', 'subscript', 'sin', 'cos', 'tan', 'sin-1', 'cos-1', 'tan-1', 'log', 'ln', 'abs', 'exp', 'sigma1', 'int1', 'vectorArrow', 'bar', 'hat', 'recurring']; var elemsTwoParams = ['root', 'frac', 'logBase', 'colVector2d', 'lim']; var elemsThreeParams = ['sigma2', 'int2', 'colVector3d', 'mixedNum']; if (elemsOneParam.indexOf(grandParent[0]) > -1 || (elemsTwoParams.indexOf(grandParent[0]) > -1 && cursorPos[cursorPos.length - 3] == 1) || (elemsThreeParams.indexOf(grandParent[0]) > -1 && cursorPos[cursorPos.length - 3] == 1)) { // conditions to delete elements // replace grandParent with ""; var evalString = 'currMathsInput.richText' for (var i = 0; i < cursorPos.length - 3; i++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[i] + ']'; } eval(evalString + ' = "";'); } } } mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); } } else { // type text char if (currMathsInput.text[0].length >= currMathsInput.maxChars) {return}; if (currMathsInput.selected == true) { currMathsInput.cursorPos = Math.min(currMathsInput.selectPos[0],currMathsInput.selectPos[1]); currMathsInput.selPos = []; currMathsInput.selected = false; deleteSelected(); removeSelectTags(); drawMathsInputText(currMathsInput); mathsInputMapCursorPos(); mathsInputCursorCoords(); } // get the relevant string from currMathsInput.richText // ie. currMathsInput.richText[cursorPos[0]][cursorPos[1]]...[cursorPos[n]] var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; var text = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) { text = text[cursorPos[aa]]; } /* // test if sin, cos, tan, ln or log have been written: if (keyValue == 'n' && text.length > 1 && text.slice(cursorPos[cursorPos.length - 1] - 2, cursorPos[cursorPos.length - 1]) == 'si') { // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get parent var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; // get position of cursor in parent string var pos = cursorPos[cursorPos.length - 1]; var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ".splice(parentPos, 1, parent.slice(0, pos - 2), ['sin', ['']], parent.slice(pos));"); mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); return; } if (keyValue == 's' && text.length > 1 && text.slice(cursorPos[cursorPos.length - 1] - 2, cursorPos[cursorPos.length - 1]) == 'co') { // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get parent var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; // get position of cursor in parent string var pos = cursorPos[cursorPos.length - 1]; var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ".splice(parentPos, 1, parent.slice(0, pos - 2), ['cos', ['']], parent.slice(pos));"); mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); return; } if (keyValue == 'n' && text.length > 1 && text.slice(cursorPos[cursorPos.length - 1] - 2, cursorPos[cursorPos.length - 1]) == 'ta') { console.log('tan'); // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get parent var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; // get position of cursor in parent string var pos = cursorPos[cursorPos.length - 1]; var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ".splice(parentPos, 1, parent.slice(0, pos - 2), ['tan', ['']], parent.slice(pos));"); mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); return; } if (keyValue == 'n' && text.length > 0 && text.slice(cursorPos[cursorPos.length - 1] - 1, cursorPos[cursorPos.length - 1]) == 'l') { console.log('ln'); // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get parent var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; // get position of cursor in parent string var pos = cursorPos[cursorPos.length - 1]; var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ".splice(parentPos, 1, parent.slice(0, pos - 1), ['ln', ['']], parent.slice(pos));"); mathsInputMapCursorPos(); mathsInputCursorCoords(); return; } if (keyValue == 'g' && text.length > 1 && text.slice(cursorPos[cursorPos.length - 1] - 2, cursorPos[cursorPos.length - 1]) == 'lo') { console.log('log'); // get cursorPos var cursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos]; // get parent var parent = currMathsInput.richText; for (var aa = 0; aa < cursorPos.length - 1; aa++) {parent = parent[cursorPos[aa]]}; // get position of cursor in parent string var pos = cursorPos[cursorPos.length - 1]; var parentPos = cursorPos[cursorPos.length - 2]; var evalString = 'currMathsInput.richText' for (var aa = 0; aa < cursorPos.length - 2; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + cursorPos[aa] + ']'; } eval(evalString + ".splice(parentPos, 1, parent.slice(0, pos - 2), ['log', ['']], parent.slice(pos));"); mathsInputMapCursorPos(); currMathsInput.cursorPos--; mathsInputCursorCoords(); return; } */ var slicePos = cursorPos[cursorPos.length - 1]; slicePos = adjustForBreakPoints(slicePos); //console.log(slicePos); slicePos = mathsInputAvoidTagSplit(text,slicePos); /* the section below is replaced by the function above // check that a tag is not being split - if so adjust slicePos var leftText = text.slice(0,slicePos); var rightText = text.slice(slicePos); var tagLeft = false; var tagLeftCount = 0; for (var i = 0; i < leftText.length; i++) { tagLeftCount++; //console.log('left '+i+':',leftText.slice(leftText.length - i)); if (leftText.slice(leftText.length - i).indexOf('>>') == 0) break; if (leftText.slice(leftText.length - i).indexOf('<<') == 0) { tagLeft = true; break; } } var tagRight = false; var tagRightCount = 0; for (var j = 0; j < rightText.length; j++) { tagRightCount++; //console.log('right '+j+':',rightText.slice(j)); if (rightText.slice(j).indexOf('<<') == 0) break; if (rightText.slice(j).indexOf('>>') == 0) { tagRight = true; break; } } //console.log(tagLeft,tagRight,tagLeftCount,tagRightCount); if (tagLeft == true && tagRight == true) { if (tagLeftCount <= tagRightCount) { slicePos -= tagLeftCount; } else { slicePos += tagRightCount; } } // test if '<',slicePos,'<' or '>',slicePos,'>' if (leftText.slice(-1) == '<' && rightText.slice(0,1) == '<' && rightText.slice(0,2) !== '<<') slicePos--; if (leftText.slice(-1) == '>' && leftText.slice(-2) !== '>>' && rightText.slice(0,1) == '>') slicePos++;*/ if (un(currMathsInput.preText) || currMathsInput.preText == null) { var pre = ""; } else { var pre = currMathsInput.preText; } if (un(currMathsInput.postText) || currMathsInput.postText == null) { var post = ""; } else { var post = currMathsInput.postText; } text = text.slice(0, slicePos) + pre + keyValue + post + text.slice(slicePos); // replace the string var evalString = 'currMathsInput.richText' for (var i = 0; i < cursorPos.length - 1; i++) { // ugly string creation approach in order to use eval() evalString += '[' + cursorPos[i] + ']'; } eval(evalString + ' = text;'); // if followed by a power, test if a baseSpacer is now required if (cursorPos[cursorPos.length - 1] + 1 == text.length && typeof currMathsInput.cursorMap[currMathsInput.cursorPos + 1] !== 'undefined') { // get the next element after the parent var nextCursorPos = currMathsInput.cursorMap[currMathsInput.cursorPos + 1]; var nextElem = currMathsInput.richText; for (var aa = 0; aa < nextCursorPos.length - 3; aa++) {nextElem = nextElem[nextCursorPos[aa]]}; if (nextElem[0] == 'power' || nextElem[0] == 'subs') { var baseSpacer = true; if (/[a-zA-Z0-9)]/g.test(keyValue) == true) baseSpacer = false var evalString = 'currMathsInput.richText' for (var aa = 0; aa < nextCursorPos.length - 3; aa++) { // ugly string creation apprach in order to use eval() evalString += '[' + nextCursorPos[aa] + ']'; } eval(evalString + "[1] = " + baseSpacer + ";"); } } mathsInputMapCursorPos(); currMathsInput.cursorPos += 1; mathsInputCursorCoords(); currMathsInput.preText = ''; currMathsInput.postText = ''; } } } //var date = new Date(); //var prevMathsInputTime = date.getTime(); var mathsInputDoubleInput = false; /*function setMathsInputBackColor(input,color) { input.backColor = color; drawMathsInputText(input); }*/ function measureMathsInputText(input) { var leftPoint = 10; if (input.textAlign == 'center') {leftPoint = 0.5 * input.data[2]}; if (typeof input.richText[input.richText.length - 1] !== 'string') {input.richText.push('')}; return drawMathsText(input.ctx, input.richText, input.fontSize, leftPoint, 0.5 * input.data[3], input.algText, input.textLoc, input.textAlign, 'middle', input.textColor, 'measure'); } function drawMathsInputText(input,ctxLocal,sf,useRelPos) { if (typeof sf == 'undefined') sf = 1; if (typeof ctxLocal == 'undefined') { input.ctx.clearRect(0,0,input.data[102],input.data[103]); var ctx = input.ctx; var ownCanvas = true; } else { var ctx = ctxLocal; // will draw to a different canvas var ownCanvas = false; } if (typeof input.richText[input.richText.length-1] !== 'string') {input.richText.push('')}; var leftPoint = 10*sf; var topPoint = 0; if (typeof input.varSize == 'object') { if (input.textAlign == 'left') { leftPoint = input.varSize.padding*sf; if (typeof input.varSize.padding !== 'number') leftPoint = 10*sf; } else if (input.textAlign == 'center') { leftPoint = 0; } else if (input.textAlign == 'right') { leftPoint = 0 - input.varSize.padding*sf; if (typeof input.varSize.padding !== 'number') leftPoint = -10*sf; } var minTightWidth = input.varSize.minWidth*sf || 50*sf; var minTightHeight = input.varSize.minHeight*sf || 50*sf; var padding = input.varSize.padding*sf; var maxWidth = input.varSize.maxWidth*sf || input.data[102]*sf; var maxHeight = input.varSize.maxHeight*sf || input.data[103]*sf; } else { if (input.textAlign == 'left') { leftPoint = 10*sf; } else if (input.textAlign == 'center') { leftPoint = 0; } else if (input.textAlign == 'right') { } var minTightWidth = 50*sf; var minTightHeight = 50*sf; var padding = 0.01*sf; var maxWidth = input.data[102]*sf; var maxHeight = input.data[103]*sf; } if (input.border == true) { if (typeof input.varSize == 'object') { var border = { type:'tight', color:input.backColor, borderColor:input.borderColor, borderWidth:input.borderWidth*sf, dash:input.borderDash, radius:input.borderRadius*sf || input.radius*sf || 0 } } else { var radius = input.borderRadius*sf || input.radius*sf || 0; var borderLeft = input.borderWidth*sf/2; var borderTop = input.borderWidth*sf/2; if (ownCanvas == false) { borderLeft += input.data[100]*sf; borderTop += input.data[101]*sf; } roundedRect(ctx,borderLeft,borderTop,input.data[102]*sf-input.borderWidth*sf,input.data[103]*sf-input.borderWidth*sf,radius,input.borderWidth*sf,input.borderColor,input.backColor,input.borderDash); var border = {type:'none'}; } } else { var border = {type:'none'}; } if (ownCanvas == false) { if (!isNaN(input.data[100])) { leftPoint += input.data[100]*sf; topPoint += input.data[101]*sf; } else { leftPoint += input.data[0]*sf; topPoint += input.data[1]*sf; } if (boolean(useRelPos,true) == true && typeof draw !== 'undefined' && typeof draw !== 'undefined' && typeof draw.drawRelPos !== 'undefined') { leftPoint -= draw.drawRelPos[0]*sf; topPoint -= draw.drawRelPos[1]*sf; } } var lineSpacingFactor = input.lineSpacingFactor || 1.2; var lineSpacingStyle = input.lineSpacingStyle || 'variable'; var drawText = text({ context:ctx, textArray:input.richText, left:leftPoint, top:topPoint, width:maxWidth, height:maxHeight, allowSpaces:true, textAlign:input.textAlign, vertAlign:input.vertAlign, minTightWidth:minTightWidth, minTightHeight:minTightHeight, padding:padding, box:border, sf:sf, lineSpacingFactor:lineSpacingFactor, spacingStyle:lineSpacingStyle }); if (ownCanvas == true) { input.textLoc = drawText.textLoc; input.breakPoints = drawText.breakPoints; input.tightRect = drawText.tightRect; input.totalTextWidth = drawText.totalTextWidth; input.maxWordWidth = drawText.maxWordWidth; } /*if (typeof input.drawPath == 'object') { if (input.tightRect[3] > input.drawPath.obj[0].height) { input.drawPath.obj[0].height = input.tightRect[3]; input.varSize.maxHeight = input.tightRect[3]; updateBorder(input.drawPath); drawCanvasPaths(); } }*/ if (typeof input.varSize == 'object' && ownCanvas == true) { // resize cursor canvas if (typeof input.tightRect == 'object') { input.cursorData[100] = input.data[100] + input.tightRect[0]; input.cursorData[101] = input.data[101] + input.tightRect[1]; input.cursorData[102] = input.tightRect[2]; input.cursorData[103] = input.tightRect[3]; } else { input.cursorData[100] = input.data[100]; input.cursorData[101] = input.data[101]; input.cursorData[102] = input.data[102]; input.cursorData[103] = input.data[103]; } input.cursorCanvas.width = input.cursorData[102]; input.cursorCanvas.height = input.cursorData[103]; resizeCanvas(input.cursorCanvas,input.cursorData[100],input.cursorData[101],input.cursorData[102],input.cursorData[103]); } if (!un(draw) && draw.drawMode == 'textEdit') { var obj = sel(); if (obj.type == 'text' && obj.mathsInput.canvas == input.canvas) { if (input.cursorData[103] > obj.height || input.cursorData[102] > obj.width) { for (var i = 0; i < draw.path.length; i++) { if (draw.path[i].selected == true) { if (input.cursorData[103] > obj.height) obj.height = input.cursorData[103]; if (input.cursorData[102] > obj.width) obj.width = input.cursorData[102]; updateBorder(draw.path[i]); } } } } calcCursorPositions(); drawSelectCanvas(); } //console.clear(); //if (currMathsInput.id == 1) console.log(currMathsInput.id,JSON.stringify(currMathsInput.richText)); } function mathsInputAddChar(mInput,char) { if (un(mInput)) mInput = currMathsInput; // get last position var cursorPos = mInput.cursorMap[mInput.cursorMap.length-1]; var loc = mInput.textLoc; for (var aa = 0 ; aa < cursorPos.length; aa++) { loc = loc[cursorPos[aa]]; } //console.log(cursorPos); var font,fontSize,color,bold,italic; arrayHandler(mInput.richText); var newLoc = drawMathsText(mInput.ctx,char,fontSize,loc.left,loc.top+0.5*loc.height,false,[],'left','middle',color,'draw','none',bold,italic,font,false,1).textLoc; var evalString = ''; for (var aa = 0 ; aa < cursorPos.length-1; aa++) { evalString += '['+cursorPos[aa]+']'; } eval('mInput.richText'+evalString+'=mInput.richText'+evalString+'+char'); eval('mInput.textLoc'+evalString+'.push(newLoc[0][1])'); cursorPos[cursorPos.length-1]++; mInput.cursorMap.push(cursorPos); //console.log(mInput); function markupTag(tag) { if (tag.indexOf('< -1) bold = true; if (tag.indexOf('false') > -1) bold = false; } else if (tag.indexOf('< -1) italic = true; if (tag.indexOf('false') > -1) italic = false; } } function arrayHandler(arr) { //console.log(JSON.stringify(arr)); for (var i = 0; i < arr.length; i++) { if (typeof arr[i] == 'object') { arrayHandler(arr[i]); } else if (typeof arr[i] == 'string') { var splitText = splitMarkup(arr[i]); for (var splitElem = 0; splitElem < splitText.length; splitElem++) { if (splitText[splitElem].indexOf('<<') == 0 && splitText[splitElem].indexOf('<
>') !== 0) { markupTag(splitText[splitElem],true); } } } } } } function createJsString (angleMode) { if (typeof angleMode == 'undefined') { angleMode = currMathsInput.angleMode || 'deg'; } var depth = 0; var jsArray = ['']; var js = ''; var algArray = ['']; var alg = ''; var exceptions = ['Math.pow','Math.sqrt','Math.PI','Math.sin','Math.cos','Math.tan','Math.asin','Math.acos','Math.atan','Math.e','Math.log','Math.abs','sin','cos','tan']; var position = [0]; for (var p = 0; p < currMathsInput.richText.length; p++) { //console.log('Before ' + p + ' base element(s):', jsArray); subJS(currMathsInput.richText[p],true); position[depth]++; //console.log('After ' + p + ' base elements:', jsArray); } js = jsArray[0]; alg = algArray[0]; //console.log(js); function removeAllTagsFromString(str) { for (var char = str.length-1; char > -1; char--) { if (str.slice(char).indexOf('>>') == 0 && str.slice(char-1).indexOf('>>>') !== 0) { for (var char2 = char-2; char2 > -1; char2--) { if (str.slice(char2).indexOf('<<') == 0) { str = str.slice(0,char2) + str.slice(char+2); char = char2; break; } } } } return str; } function subJS(elem, addMultIfNecc) { if (typeof addMultIfNecc !== 'boolean') addMultIfNecc = true; //console.log('subJS', elem); if (typeof elem == 'string') { //console.log('string'); var subText = replaceAll(elem, ' ', ''); // remove white space subText = removeAllTagsFromString(subText); subText = subText.replace(/\u00D7/g, '*'); // replace multiplications signs with * subText = subText.replace(/\u00F7/g, '/'); // replace division signs with / subText = subText.replace(/\u2264/g, '<='); // replace signs with <= subText = subText.replace(/\u2265/g, '>='); // replace signs with >= for (var c = 0; c < subText.length - 2; c++) { if (subText.slice(c).indexOf('sin') == 0 || subText.slice(c).indexOf('cos') == 0 || subText.slice(c).indexOf('tan') == 0) { if (subText.slice(c).indexOf('(') == 3) { if (angleMode == 'rad') { subText = subText.slice(0,c)+'Math.'+subText.slice(c); c += 5; } else { subText = subText.slice(0,c)+'Math.'+subText.slice(c,c+4)+'(Math.PI/180)*'+subText.slice(c+4); c += 19; } } } } subText = timesBeforeLetters(subText); // if following frac or power, add * if necessary if (addMultIfNecc == true && jsArray[depth] !== '' && elem !== '' && /[ \+\-\=\u00D7\u00F7\u2264\u2265\<\>\])]/.test(elem.charAt(0)) == false) subText = '*' + subText; jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'frac') { //console.log('frac'); var subText = ''; var subText2 = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '((' + jsArray[depth] + ')/'; subText2 += 'frac(' + jsArray[depth] + ','; jsArray[depth] = ''; subJS(elem[2], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '(' + jsArray[depth] + '))'; subText2 += jsArray[depth] + ')'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText2; return; } else if (elem[0] == 'sqrt') { //console.log('sqrt'); var subText = ''; var subText2 = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += 'Math.sqrt('+ jsArray[depth] +')'; subText2 += 'sqrt('+jsArray[depth]+')'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText2; return; } else if (elem[0] == 'root') { //console.log(elem[0]); var subText = ''; var subText2 = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[2], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '(Math.pow('+jsArray[depth]+','; subText2 += 'root('+jsArray[depth]+','; jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '(1/('+jsArray[depth]+'))))'; subText2 += jsArray[depth]+')'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText2; return; } else if (elem[0] == 'sin' || elem[0] == 'cos' || elem[0] == 'tan') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space var convertText1 = ''; var convertText2 = ''; if (angleMode == 'deg' || angleMode == 'degrees') { convertText1 = '('; convertText2 = ')*Math.PI/180'; } subText += 'Math.'+ elem[0] +'('+convertText1+jsArray[depth]+convertText2+')'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'sin-1' || elem[0] == 'cos-1' || elem[0] == 'tan-1') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space var convertText1 = ''; var convertText2 = ''; if (angleMode == 'deg' || angleMode == 'degrees') { convertText1 = '(('; convertText2 = ')*180/Math.PI)'; } subText += convertText1+'Math.a'+elem[0].slice(0,3)+'('+jsArray[depth]+')'+convertText2;; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'ln') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += 'Math.log('+jsArray[depth]+')'; jsArray[depth] = ''; position.pop(); depth--; jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'log') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '((Math.log('+jsArray[depth]+'))/(Math.log(10)))'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'logBase') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[2], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '((Math.log('+jsArray[depth]+'))/'; jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += '(Math.log('+jsArray[depth]+')))'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'abs') { //console.log(elem[0]); var subText = ''; // if not proceeded by an operator, put a times sign in if (jsArray[depth] !== '' && /[\+\-\u00D7\u00F7\*\/\=\[(]/.test(jsArray[depth].slice(-1)) == false) subText += "*"; depth++; position.push(0); jsArray[depth] = ''; subJS(elem[1], false); jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); // remove white space subText += 'Math.abs('+jsArray[depth]+')'; jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText; return; } else if (elem[0] == 'power' || elem[0] == 'pow') { //console.log('power'); var baseSplitPoint = 0; var trigPower = false; //if the power is after a close bracket if (jsArray[depth] !== '') { if (jsArray[depth].charAt(jsArray[depth].length - 1) == ')') { var bracketCount = 1 for (jsChar = jsArray[depth].length - 2; jsChar >= 0; jsChar--) { if (jsArray[depth].charAt(jsChar) == ')') {bracketCount++} if (jsArray[depth].charAt(jsChar) == '(') {bracketCount--} if (bracketCount == 0 && !baseSplitPoint) { baseSplitPoint = jsChar; break; } } //if the power is after sin, cos or tan } else if (jsArray[depth].slice(jsArray[depth].length-3) == 'sin' || jsArray[depth].slice(jsArray[depth].length-3) == 'coa' || jsArray[depth].slice(jsArray[depth].length-3) == 'tan') { trigPower = true; //if the power is after a letter } else if (/[A-Za-z]/g.test(jsArray[depth].charAt(jsArray[depth].length - 1)) == true) { baseSplitPoint = jsArray[depth].length - 1; //if the power is after a numerical digit } else if (/[0-9]/g.test(jsArray[depth].charAt(jsArray[depth].length - 1)) == true) { var decPoint = false; for (jsChar = jsArray[depth].length - 2; jsChar >= 0; jsChar--) { if (decPoint == false && jsArray[depth].charAt(jsChar) == '.') { decPoint = true; } else if (decPoint == true && jsArray[depth].charAt(jsChar) == '.') { baseSplitPoint = jsChar + 1; break; } else if (/[0-9]/g.test(jsArray[depth].charAt(jsChar)) == false) { baseSplitPoint = jsChar + 1; break; } } } else { return ''; // error } } /*if (trigPower == true) { var power = elem[2]; if (typeof power == 'string') { power = removeAllTagsFromString(power); console.log(power); if (power == '-1') { jsArray[depth] = jsArray[depth].slice(0,-3) + 'Math.a' + jsArray[depth].slice(-3); } else if (power == '2') { } } }*/ var base = jsArray[depth].slice(baseSplitPoint); jsArray[depth] = jsArray[depth].slice(0, baseSplitPoint); depth++; position.push(0); jsArray[depth] = ''; subJS(elem[2], false) jsArray[depth] = replaceAll(jsArray[depth], ' ', ''); if (trigPower == true) { console.log(jsArray,jsArray[depth-1],jsArray[depth]); if (jsArray[depth] == '-1') { jsArray[depth-1] = jsArray[depth-1].slice(0,-3) + 'Math.a' + jsArray[depth-1].slice(-3); } } else { var subText = 'Math.pow(' + base + ',' + jsArray[depth] + ')'; var subText2 = base + '^' + jsArray[depth]; } jsArray[depth] = ''; depth--; position.pop(); jsArray[depth] += subText; algArray[depth] += subText2; return; } else if (typeof elem == 'object') { //console.log('array'); depth++; position.push(0); jsArray[depth] = ''; for (var sub = 0; sub < elem.length; sub++) { //console.log('depth:', depth); //console.log('Before ' + sub + ' sub element(s):', jsArray); subJS(elem[sub], addMultIfNecc); //console.log('After ' + sub + ' sub element(s):', jsArray); } jsArray[depth-1] += jsArray[depth]; algArray[depth-1] += algArray[depth]; jsArray[depth] = ''; depth--; position.pop(); //console.log('endOfArray', jsArray); return; } } function timesBeforeLetters(testText) { // find instances of letters - if proceeded by a number, add * for (q = 0; q < testText.length; q++) { if (q > 0) { if (/[a-zA-Z]/g.test(testText.charAt(q)) == true && /[a-zA-Z0-9)]/.test(testText.charAt(q - 1)) == true) { testText = testText.slice(0, q) + '*' + testText.slice(q); } // if an open bracket is proceeded by a letter, number or ), add * if (/[\[(]/g.test(testText.charAt(q)) == true && testText.length > q && /[A-Za-z0-9)]/g.test(testText.charAt(q - 1)) == true) { testText = testText.slice(0, q) + '*' + testText.slice(q); } } for (var i = 0; i < exceptions.length; i++) { if (testText.slice(q).indexOf(exceptions[i]) == 0) { q += exceptions[i].length; } } } return testText; } var jsValue; try { jsValue = eval(js); } catch (err) {} return js; } function splitText(text) { // find split points in text string var splitPointCount = 0; var textSplitPoints = []; var delimiter = '%&^'; for (i = 0; i <= text.length; i++) { var fracStartPos = text.substring(i, text.length).indexOf('frac('); var rootStartPos = text.substring(i, text.length).indexOf('root('); var powerStartPos = text.substring(i, text.length).indexOf('power('); if (fracStartPos !== -1) {fracStartPos += i}; if (rootStartPos !== -1) {rootStartPos += i}; if (powerStartPos !== -1) {powerStartPos += i}; if (fracStartPos > -1 || rootStartPos > -1 || powerStartPos > -1) { textSplitPoints[splitPointCount] = []; if (fracStartPos == -1) {fracStartPos = 10000}; if (rootStartPos == -1) {rootStartPos = 10000}; if (powerStartPos == -1) {powerStartPos = 10000}; textSplitPoints[splitPointCount][0] = Math.min(fracStartPos, rootStartPos, powerStartPos); var openBracketCount = 0; var closeBracketCount = 0; for (j = textSplitPoints[splitPointCount][0]; j <= text.length; j++) { if (!textSplitPoints[splitPointCount][1]) { if (text.charAt(j) == '(') {openBracketCount++}; if (text.charAt(j) == ')') {closeBracketCount++}; if (openBracketCount > 0 && (openBracketCount == closeBracketCount)) { textSplitPoints[splitPointCount][1] = j; i = j; } } } splitPointCount++; } } if (textSplitPoints.length == 0) {return text} for (i = 0; i < textSplitPoints.length; i++) { text = text.substring(0, textSplitPoints[i][0] + i * 2 * delimiter.length) + delimiter + text.substring(textSplitPoints[i][0] + i * 2 * delimiter.length, textSplitPoints[i][1] + 1 + i * 2 * delimiter.length) + delimiter + text.substring(textSplitPoints[i][1] + 1 + i * 2 * delimiter.length, text.length); } var splitArray = text.split(delimiter); var returnArray = []; for (i = 0; i < splitArray.length; i++) { var type = 0; if (splitArray[i].indexOf('frac(') == 0) {type = 'frac'}; if (splitArray[i].indexOf('root(') == 0) {type = 'root'}; if (splitArray[i].indexOf('power(') == 0) {type = 'power'}; if (type == 0) { if (splitArray[i] !== '') {returnArray.push(splitArray[i])} } else { var subArray = []; subArray[0] = type; var params = splitArray[i].substring(type.length + 1, splitArray[i].length - 1); var openBracketCount = 0; var closeBracketCount = 0; var splitPoint = -1; // find split point of params for (j = 0; j <= params.length; j++) { if (params.charAt(j) == '(') {openBracketCount++}; if (params.charAt(j) == ')') {closeBracketCount++}; if (params.charAt(j) == ',' && (openBracketCount == closeBracketCount) && splitPoint == -1) { splitPoint = j; } } subArray[1] = params.substring(0, splitPoint); subArray[2] = params.substring(splitPoint + 1, params.length).trim(); returnArray.push(subArray) } } return returnArray; } /*! correcting-interval 2.0.0 | Copyright 2014 Andrew Duthie | MIT License */ /* jshint evil: true */ /* usage example: var startTime = Date.now(); setCorrectingInterval(function() { console.log((Date.now() - startTime) + 'ms elapsed'); }, 1000); */ ;(function(global, factory) { // Use UMD pattern to expose exported functions if (typeof exports === 'object') { // Expose to Node.js module.exports = factory(); } else if (typeof define === 'function' && define.amd) { // Expose to RequireJS define([], factory); } // Expose to global object (likely browser window) var exports = factory(); for (var prop in exports) { global[prop] = exports[prop]; } }(this, function() { // Track running intervals var numIntervals = 0, intervals = {}; // Polyfill Date.now var now = Date.now || function() { return new Date().valueOf(); }; var setCorrectingInterval = function(func, delay) { var id = numIntervals++, planned = now() + delay; // Normalize func as function switch (typeof func) { case 'function': break; case 'string': var sFunc = func; func = function() { eval(sFunc); }; break; default: func = function() { }; } function tick() { func(); // Only re-register if clearCorrectingInterval was not called during function if (intervals[id]) { planned += delay; intervals[id] = setTimeout(tick, planned - now()); } } intervals[id] = setTimeout(tick, delay); return id; }; var clearCorrectingInterval = function(id) { clearTimeout(intervals[id]); delete intervals[id]; }; return { setCorrectingInterval: setCorrectingInterval, clearCorrectingInterval: clearCorrectingInterval }; })); function logText(clearConsole) { var input = currMathsInput; if (clearConsole == true) console.clear(); console.log('richText:',input.richText); console.log('cursorMap:'); for (var i = 0; i < input.cursorMap.length; i++) { var char = input.richText; for (var j = 0; j < input.cursorMap[i].length - 1; j++) {char = char[input.cursorMap[i][j]];}; // check for breakPoints var slicePos = input.cursorMap[i][input.cursorMap[i].length-1]; if (typeof currMathsInput.breakPoints == 'object') { var map = currMathsInput.cursorMap[i]; for (var k = 0; k < currMathsInput.breakPoints.length - 1; k++) { var iBreak = currMathsInput.allMap[currMathsInput.breakPoints[k]]; if (iBreak[0] == map[0] && iBreak[1] < map[1]) { slicePos--; } } } var char1 = char.slice(slicePos-5,slicePos); var char2 = char.slice(slicePos,slicePos+5); if (i == input.cursorPos) { console.log('>'+i+':',input.cursorMap[i],char1,char2,'<<< cursorPos'); } else { console.log('>'+i+':',input.cursorMap[i],char1,char2); } } } function drawTextLocs() { for (var loc = 0; loc < currMathsInput.cursorMap.length; loc++) { var cursorPos = currMathsInput.cursorMap[loc]; var evalString = 'currMathsInput.textLoc' for (aa = 0; aa < cursorPos.length; aa++) { evalString += '[' + cursorPos[aa] + ']'; } var pos = eval(evalString); console.log(loc, pos.left); currMathsInput.ctx.strokeStyle = '#00F'; currMathsInput.ctx.lineWidth = 2; currMathsInput.ctx.beginPath(); currMathsInput.ctx.moveTo(pos.left,pos.top); currMathsInput.ctx.lineTo(pos.left,pos.top+pos.height); currMathsInput.ctx.closePath(); currMathsInput.ctx.stroke(); } } function isMouseOverText(mathsInput) { if (typeof mathsInput == 'undefined') mathsInput = currMathsInput; var locs = []; for (var i = 0; i < mathsInput.cursorMap.length; i++) { var textLoc = mathsInput.textLoc; for (var j = 0; j < mathsInput.cursorMap[i].length; j++) {textLoc = textLoc[mathsInput.cursorMap[i][j]];}; locs.push(textLoc); } var left = mathsInput.data[100]; var top = mathsInput.data[101]; for (var i = 0; i < locs.length; i++) { if (mouse.x >= left + locs[i].left && mouse.x <= left + locs[i].left + locs[i].width && mouse.y >= top + locs[i].top && mouse.y <= top + locs[i].top + locs[i].height) { return true; } } return false; } function splitMarkup(element) { // seperates markup tags from other text var splitAt = [0]; for (var c = 0; c < element.length; c++) { if (element.slice(c).indexOf('<<') == 0 && element.slice(c).indexOf('<<<') !== 0) { for (var d = c; d < element.length; d++) { if (element.slice(d).indexOf('>>') == 0) { splitAt.push(c,d+2); break; } } } else if (element.slice(c).indexOf(br) == 0) { splitAt.push(c,c+1); } } splitAt.push(element.length); var returnArray = []; for (var c = 0; c < splitAt.length-1; c++) { returnArray.push(element.slice(splitAt[c],splitAt[c+1])) } return returnArray; } function reduceTags(textArray) { var bold = {value:null,char:true}; var italic = {value:null,char:true}; var fontSize = {value:null,char:true}; var font = {value:null,char:true}; var color = {value:null,char:true}; var backColor = {value:null,char:true}; var align = {set:false}; var selected = {value:null}; function arrayHandler(arr) { for (var l = arr.length - 1; l >= 0; l--) { if (typeof arr[l] == 'string') { arr[l] = stringHandler(arr[l]); } else if (typeof arr[l] == 'object') { arr[l] = arrayHandler(arr[l]); } } return arr; } function stringHandler(string) { // first split string into tag and non-tag elements var splitString = splitMarkup(string); // work backwards through the string looking for tags for (var j = splitString.length - 1; j >= 0; j--) { if (splitString[j].indexOf('<<') == 0) { for (var k = splitString[j].length; k >= 0; k--) { var slice = splitString[j].slice(k); if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+7,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == bold.value) { // repeated tag - !! } else { // new tag bold.value = value; bold.char = false; } } } else if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+9,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == italic.value) { // repeated tag } else { // new tag italic.value = value; italic.char = false; } } } else if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+11,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == fontSize.value) { // repeated tag } else { // new tag fontSize.value = value; fontSize.char = false; } } } else if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+7,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == font.value) { // repeated tag } else { // new tag font.value = value; font.char = false; } } } else if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+8,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == color.value) { // repeated tag } else { // new tag color.value = value; color.char = false; } } } else if (slice.indexOf('<>')+2); } else { var value = splitString[j].slice(k+12,k+splitString[j].slice(k).indexOf('>>')).toLowerCase(); if (value == backColor.value) { // repeated tag } else { // new tag backColor.value = value; backColor.char = false; } } } else if (slice.indexOf('<
>') == 0 || slice.indexOf(br) == 0) { align.set = false; } else if (slice.indexOf('<>')+2); } } else if (slice.indexOf('<>')).toLowerCase(); //console.log('selected tag',j,k,value,JSON.stringify(splitString[j])); if (value == selected.value) { // repeated tag } else { // new tag selected.value = value; } } } } else { if (splitString[j].length > 0) { bold.char = true; italic.char = true; fontSize.char = true; font.char = true; color.char = true; backColor.char = true; } } } string = ''; for (var j = 0; j < splitString.length; j++) string += splitString[j]; return string; } if (typeof textArray == 'object') textArray = arrayHandler(textArray); //var arrayString = ''; //console.log('reduceTags()1',JSON.stringify(textArray)); textArray = combineSpaces2(textArray); // find any adjacent text blocks and combine them function combineSpaces2(textArray) { if (textArray.length > 1) { for (var gg = textArray.length - 1; gg >= 0; gg--) { if (typeof textArray[gg] == 'object') { //arrayString += '[' + gg + ']'; combineSpaces2(textArray[gg]); } else { if (gg < textArray.length - 1 && typeof textArray[gg] == 'string' && typeof textArray[gg+1] == 'string') { eval('textArray[' + gg + '] += textArray[' + (gg+1) + ']'); eval('textArray.splice(gg+1, 1);'); } } } } //arrayString = arrayString.slice(0, arrayString.lastIndexOf('[') - arrayString.length); return textArray; } //console.log('reduceTags()2',JSON.stringify(textArray)); return textArray; }