//Javascript Document if (typeof cacheVersion === 'undefined') var cacheVersion = false; function un(variable) { if (typeof variable == 'undefined') { return true; } else if (variable == null) { return true; } else { return false; } } function def(arr) { for (var d = 0; d < arr.length; d++) { if (typeof arr[d] !== 'undefined') { return arr[d]; } } return undefined; } function boolean(testVar, def) { if (typeof testVar == 'boolean') { return testVar; } else { return def; } } function isInt(num) { if (num % 1 == 0) return true; return false; } /*function clone(obj) { var copy; if (null == obj || "object" != typeof obj) return obj; if (obj instanceof Date) { copy = new Date(); copy.setTime(obj.getTime()); return copy; } if (obj instanceof Array) { copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = clone(obj[i]); } return copy; } if (obj instanceof Object) { copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); }*/ /*function clone(obj) { return JSON.parse(JSON.stringify(obj,function(key,value) { return (typeof value === 'function') ? value.toString() : value; })); }*/ function isObjectEmpty(ob) { for (var key in ob) { if (ob[key].hasOwnProperty() === false) continue; if (!un(ob[key])) return false; } return true; } Array.prototype.last = function(){ return this[this.length - 1]; }; Array.prototype.isEmpty = function() { for (var i = 0; i < this.length; i++) if (!un(this[i])) return false; return true; } Array.prototype.ran = function () { return this[Math.floor(Math.random() * this.length)] } Array.prototype.shuffle = function() { for (var i = 0; i < this.length-1; i++) { var j = ran(i,this.length-1); if (i !== j) { var elementi = this[i]; var elementj = this[j]; this.splice(i,1,elementj); this.splice(j,1,elementi); } } return this; } Array.prototype.sortOn = function(key) { this.sort(function(a, b){ if (a[key] < b[key]) { return -1; } else if (a[key] > b[key]) { return 1; } return 0; }); }; Array.prototype.max = function() { return Math.max.apply(null, this); }; Array.prototype.min = function() { return Math.min.apply(null, this); }; if (!Array.prototype.find) { // https://tc39.github.io/ecma262/#sec-array.prototype.find Object.defineProperty(Array.prototype, 'find', { value: function(predicate) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception. if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. var thisArg = arguments[1]; // 5. Let k be 0. var k = 0; // 6. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kValue be ? Get(O, Pk). // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). // d. If testResult is true, return kValue. var kValue = o[k]; if (predicate.call(thisArg, kValue, k, o)) { return kValue; } // e. Increase k by 1. k++; } // 7. Return undefined. return undefined; }, configurable: true, writable: true }); } if (typeof Array.prototype.includes == 'undefined') { Array.prototype.includes = function(element) { return this.indexOf(element) > -1; } } function arraysEqual(array1,array2) { if (typeof array1 == 'undefined' || typeof array2 == 'undefined') return false if (array1.length !== array2.length) return false; for (var arr = 0; arr < array1.length; arr++) { if (typeof array1[arr] !== typeof array2[arr]) return false; if (typeof array1[arr] == 'object' && arraysEqual(array1[arr],array2[arr]) == false) return false; if (typeof array1[arr] !== 'object' && array1[arr] !== array2[arr]) return false; } return true; } function isEqual(a,b,recursionCount) { if (un(recursionCount)) { var recursionCount = 0; } else { recursionCount++; if (recursionCount > 6) return true; } if (typeof a == 'undefined' || typeof b == 'undefined') return false; if (typeof a !== typeof b) return; if (a instanceof Array) { if (b instanceof Array == false) return false; if (a.length !== b.length) return false; for (var i = 0, iMax = a.length; i < iMax; i++) { if (!isEqual(a[i],b[i],recursionCount)) return false } for (var i = 0, iMax = b.length; i < iMax; i++) { if (!isEqual(b[i],a[i],recursionCount)) return false } } else if (typeof a == 'object') { if (b instanceof Array == true) return false; for (var key in a) { if (!a.hasOwnProperty(key)) continue; if (!isEqual(a[key],b[key],recursionCount)) return false } for (var key in b) { if (!b.hasOwnProperty(key)) continue; if (!isEqual(b[key],a[key],recursionCount)) return false } } else if (typeof a === 'function') { if (a.toString() !== b.toString()) return false; } else { if (a !== b) return false; } return true; } if (typeof CanvasRenderingContext2D.prototype.ellipse == 'undefined') { CanvasRenderingContext2D.prototype.ellipse = function(cx, cy, rx, ry, rot, aStart, aEnd) { this.save(); this.translate(cx, cy); this.rotate(rot); this.translate(-rx, -ry); this.scale(rx, ry); this.arc(1, 1, 1, aStart, aEnd, false); this.restore(); } } if (un(window.requestIdleCallback)) { window.requestIdleCallback = function (cb) { var start = Date.now(); return setTimeout(function () { cb({ didTimeout: false, timeRemaining: function () { return Math.max(0, 50 - (Date.now() - start)); } }); }, 1); }; window.cancelIdleCallback = function (id) { clearTimeout(id); } } function mapArray(array,includeAll) { var mapString = ''; var map = []; /*if (includeAll === false) { for (var i = 0; i < array.length; i++) { for (var j = 0; j < array[i].length; j++) { if (typeof array[i][j].markupTag == 'undefined' || array[i][j].markupTag == false) { console.log(i,j, JSON.stringify(array[i][j])); } } } }*/ function mapArray2(array,includeAll) { for (var aa = 0; aa < array.length; aa++) { if (typeof array[aa] !== 'undefined') { if (typeof array[aa].left == 'undefined' && typeof array[aa] !== 'boolean') { if (mapString == '') {mapString = String(aa)} else {mapString = mapString + ',' + String(aa)} mapArray2(array[aa], includeAll); } else if (includeAll == true || typeof array[aa].markupTag == 'undefined' || array[aa].markupTag == false) { if (mapString == '') {mapString = String(aa)} else {mapString = mapString + ',' + String(aa)} var mapArr = mapString.split(','); for (var bb = 0; bb < mapArr.length; bb++) {mapArr[bb] = Number(mapArr[bb])} map.push(mapArr); mapString = mapString.slice(0, mapString.lastIndexOf(',') - mapString.length); } } } mapString = mapString.slice(0, mapString.lastIndexOf(',') - mapString.length); } for (var aa = 0; aa < array.length; aa++) { if (typeof array[aa] !== 'undefined') { if (typeof array[aa].left == 'undefined') { if (mapString == '') {mapString = String(aa)} else {mapString = mapString + ',' + String(aa)} mapArray2(array[aa], includeAll); } else if (includeAll == true || typeof array[aa].markupTag == 'undefined' || array[aa].markupTag == false) { if (mapString == '') {mapString = String(aa)} else {mapString = mapString + ',' + String(aa)} var mapArr = mapString.split(','); for (var bb = 0; bb < mapArr.length; bb++) {mapArr[bb] = Number(mapArr[bb])} map.push(mapArr); } mapString = ''; } } return map; } var arrayString = ''; function loop(obj,func,recursive) { // eg. // loop( // {a:1,b:2,c:['q','r',function(){},{g:true,h:false}],d:{x:11,y:12}}, // function(obj,key) {console.log(obj,key)} // ); // // recursive is true by default if (obj instanceof Array) { for (var i = 0; i < obj.length; i++) { if (boolean(recursive,true) == true && (obj[i] instanceof Array || typeof obj[i] == 'object')) { loop(obj[i],func,recursive); } else { func(obj[i],i); } } } else if (typeof obj == 'object') { for (var i in obj) { if (boolean(recursive,true) == true && (obj[i] instanceof Array || typeof obj[i] == 'object')) { loop(obj[i],func,recursive); } else { func(obj[i],i); } } } } function getSortOrder(arr) { var toSort = clone(arr); for (var i = 0; i < toSort.length; i++) toSort[i] = [toSort[i], i]; toSort.sort(function(left, right) {return left[0] < right[0] ? -1 : 1;}); var sortIndices = []; for (var j = 0; j < toSort.length; j++) sortIndices.push(toSort[j][1]); return sortIndices; } function copyProperties(from,to,exceptions) { if (un(exceptions)) exceptions = []; if (un(to)) to = {}; for (var key in from) { if (exceptions.includes(key) || isElement(from[key]) || key.indexOf("_") == 0) continue; to[key] = clone(from[key]); } return to; } if (typeof scriptsToLoad == 'undefined') { var scriptsToLoad = [ '_algebra.js', '_drawMathsText.js', '_mathsInput.js', '_grid2.js', '_keyboard.js', '_text2.js', '_textEdit.js', '_draw.js', '_draw2.js', '_miscFuncs.js', 'Notifier.js', 'timeme.min.js', 'clone.js', '_draw3.js' ]; } if (scriptsToLoad.includes('clone.js') == false) scriptsToLoad.unshift('clone.js'); if (scriptsToLoad.includes('_draw3.js') == false) scriptsToLoad.push('_draw3.js'); var loadedScriptCount = 0; var pageIndex = 0; if (typeof FontFace !== 'undefined') { addFont('Hobo', 'url(fonts/hobo-webfont.woff)'); addFont('segoePrint', 'url(fonts/segeo-print-webfont.woff)'); addFont('smileyMonster', 'url(fonts/smileymonster.woff)'); function addFont(name,url) { var font = new FontFace(name,url,{style:'normal',weight:'normal'}); document.fonts.add(font); font.load(); } } if (!Array.from) { // Production steps of ECMA-262, Edition 6, 22.1.2.1 Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // The length property of the from method is 1. return function from(arrayLike/*, mapFn, thisArg */) { // 1. Let C be the this value. var C = this; // 2. Let items be ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError('Array.from requires an array-like object - not null or undefined'); } // 4. If mapfn is undefined, then let mapping be false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. else // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. if (!isCallable(mapFn)) { throw new TypeError('Array.from: when provided, the second argument must be a function'); } // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Let lenValue be Get(items, "length"). // 11. Let len be ToLength(lenValue). var len = toLength(items.length); // 13. If IsConstructor(C) is true, then // 13. a. Let A be the result of calling the [[Construct]] internal method // of C with an argument list containing the single item len. // 14. a. Else, Let A be ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0. var k = 0; // 17. Repeat, while k < len… (also steps a - h) var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Let putStatus be Put(A, "length", len, true). A.length = len; // 20. Return A. return A; }; }()); } function hasDuplicates(array) { var valuesSoFar = []; for (var i = 0; i < array.length; ++i) { var value = array[i]; if (valuesSoFar.indexOf(value) !== -1) { return true; } valuesSoFar.push(value); } return false; } function printCanvases(arr) { // needs cross-browser testing var data = []; var windowContent = ''; windowContent += ''; windowContent += 'Print Worksheet'; windowContent += '' for (var i = 0; i < arr.length; i++) { data[i] = arr[i].toDataURL(); windowContent += ''; } windowContent += ''; windowContent += ''; var printWin = window.open(); printWin.document.open(); printWin.document.write(windowContent); printWin.document.addEventListener('load', function() { printWin.focus(); printWin.print(); //printWin.document.close(); //printWin.close(); //printWin.onfocus = function () {printWin.close();} setTimeout(function() { printWin.document.close(); printWin.close(); },500); }, true); } function getHighestZIndex() { var elems = container.childNodes; var highest = 0; for (var i = 0; i < elems.length; i++) { if (elems[i].nodeType !== 1) continue; var zIndex = Number(elems[i].style.zIndex); if ((zIndex > highest) && (zIndex != 'auto')) highest = zIndex; } return highest; } function getNodes() { var elems = container.childNodes; var obj = []; for (var i = 0; i < elems.length; i++) { if (elems[i].nodeType !== 1) continue; var zIndex = Number(elems[i].style.zIndex); var rect = []; if (!un(elems[i].data)) { rect[0] = elems[i].data[100]; rect[1] = elems[i].data[101]; rect[2] = elems[i].data[102]; rect[3] = elems[i].data[103]; } var opacity = elems[i].style.opacity; var pointerEvents = elems[i].style.pointerEvents == 'auto' ? true : false; obj.push({zIndex:zIndex,node:elems[i],rect:rect,opacity:opacity,pointerEvents:pointerEvents}); } obj.sort(function(a,b) { return a.zIndex - b.zIndex; }); return obj; } function funcLog() { augment(function(name, fn) { console.log("fn " + name); }); } function augment(withFn) { var name, fn; for (name in window) { fn = window[name]; var exceptions = ['mouseCoordsChange', 'xWindowToCanvas', 'yWindowToCanvas', 'xCanvasToWindow','yCanvasToWindow', 'setTimeout', 'clearTimeout', 'dragMove', 'pointerEventsListen', 'hitTestMouseOver', 'mathsInputCursorBlink', 'drawMathsInputText', 'drawMathsText', 'mapArray', 'removeTags', 'buildArray', 'clearCorrectingInterval', 'logMe', 'boolean', 'replaceAll', 'showObj', 'dist', 'distancePointToLineSegment', 'closestPointOnLineSegment', 'escapeRegExp', 'resizeCanvas', 'arraysEqual','def','un','resizeCanvas3','updateMouse','addListener','createCanvas','newctx','clone','addEventListener','addListenerStart','addListenerEnd','resize','showObj','hideObj','removeEventListener','addListenerMove','clearCanvas','active','inactive','stopDefaultBackspaceBehaviour']; if (typeof fn === 'function' && exceptions.indexOf(name) == -1) { window[name] = (function(name, fn) { var args = arguments; return function() { withFn.apply(this, args); return fn.apply(this, arguments); } })(name, fn); } } } //funcLog(); var mainCanvasLeft = 0; var mainCanvasTop = 0; var mainCanvasWidth = 1200; var mainCanvasHeight = 700; var mainCanvasMargins = [0,0,0,0]; //l,t,r,b - used in teach: edit mode var canvasDisplayLeft = 0; var canvasDisplayTop = 0; if (typeof mainCanvasBorderWidth == 'undefined') var mainCanvasBorderWidth = 10; if (typeof mainCanvasFillStyle == 'undefined') var mainCanvasFillStyle = mainCanvasFillStyle || '#FFC'; var mainCanvasMode = 'full'; var pi = String.fromCharCode(0x03C0); var times = String.fromCharCode(0x00D7); var divide = String.fromCharCode(0x00F7); var degrees = String.fromCharCode(0x00B0); var infinity = String.fromCharCode(0x221E); var lessThanEq = String.fromCharCode(0x2264); var moreThanEq = String.fromCharCode(0x2265); var notEqual = String.fromCharCode(0x2260); var theta = String.fromCharCode(0x03B8); var plusMinus = String.fromCharCode(0x00B1); var minusPlus = String.fromCharCode(0x2213); var tab = String.fromCharCode(0x21F4); var br = String.fromCharCode(0x23CE); var key1 = []; var key1Data = []; var mouse = {x:0, y:0}; function updateMouse(e) { if (un(e)) return; if (e.touches) { if (un(e.touches[0])) return; var x = e.touches[0].pageX; var y = e.touches[0].pageY; } else { var x = e.clientX || e.pageX; var y = e.clientY || e.pageY; } if (!un(draw) && !un(draw.div)) { var bounds = draw.drawCanvas[0].getBoundingClientRect(); mouse.x = (x - bounds.left) * (1200 / bounds.width); mouse.y = (y - bounds.top) * (1700 / bounds.height); draw.mouse = [mouse.x,mouse.y]; } else { mouse.x = xWindowToCanvas(x); mouse.y = yWindowToCanvas(y); if (!un(draw) && !un(draw.drawRelPos)) { draw.mouse = canvasPosToDrawPos([mouse.x,mouse.y]); } } } function canvasPosToDrawPos(pos) { if (un(draw)) return pos; return [ (pos[0]-draw.drawRelPos[0])/draw.scale, (pos[1]-draw.drawRelPos[1])/draw.scale ]; } function drawPosToCanvasPos(pos) { if (un(draw)) return pos; return [ pos[0]*draw.scale+draw.drawRelPos[0], pos[1]*draw.scale+draw.drawRelPos[1] ]; } var dragObject = []; var dragObjectData = []; var currentDragId; var dragOffset = {x:0, y:0}; var dragArea = {xMin:0, xMax:0, yMin:0, yMax:0}; var currMathsInput; var currMathsInputId; var mathsInputCursorBlinkInterval; var mathsInputCursorState; var mathsInputCursor = {x:0, top:0, bottom:0} var charMap = [[42,215,215], [48,48,41], [49,49,33], [50,50,34], [51,51,163], [52,52,36], [53,53,37], [54,54,94], [55,55,38], [56,56,215], [57,57,40], [96,48,48], [97,49,49], [98,50,50], [99,51,51], [100,52,52], [101,53,53], [102,54,54], [103,55,55], [104,56,56], [105,57,57], [106,215,215], [107,43,43], [109,189,189], [110,190,190], [111,191,191], [186,59,58], [187,61,43], [188,44,60], [189,45,95], [190,46,62], [191,247,63], [192,39,64], [219,91,123], [220,92,124], [221,93,125], [222,35,126]]; var endInputExceptions = []; var currSlider; var slider = []; var draw; var keyboard = []; var keyboardData = []; var keyboardVis = []; var showKeys = []; var hideKeys = []; var zIndexFront = 1000; var canvases = [[]]; var mathsInput = [[]]; var container = document.getElementById('canvascontainer'); var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var canvasDisplayRect; var canvasDisplayWidth; var canvasDisplayHeight; var canvasMetrics = canvas.getBoundingClientRect(); var openhand = 'url("cursors/openhand.cur"), auto'; var closedhand = 'url("cursors/closedhand.cur"), auto'; var logPointerEvents = false; window.addEventListener("touchstart", function (e) { updateMouse(e); if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('touchstart', e.target); }, true); window.addEventListener("touchmove", function (e) { updateMouse(e); if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('touchmove', e.target); }, true); window.addEventListener("touchend", function (e) { if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('touchend', e.target); }, true); window.addEventListener("pointerstart", function (e) { if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('pointerstart'); }, true); window.addEventListener("pointermove", function (e) { if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); //if (logPointerEvents) console.log('pointermove'); }, true); window.addEventListener("pointerend", function (e) { if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('pointerend'); }, true); window.addEventListener("mousedown", function (e) { updateMouse(e); if (e.target.allowDefault === true) return; e.preventDefault(); if (logPointerEvents) console.log('mousedown'); }, true); window.addEventListener("mousemove", function (e) { updateMouse(e); if (un(e.target.allowDefault) || e.target.allowDefault == false) e.preventDefault(); if (logPointerEvents) console.log('mousemove'); }, true); window.addEventListener("mouseup", function (e) { if (e.target.allowDefault === true) return; e.preventDefault(); if (logPointerEvents) console.log('mouseup'); }, true); window.addEventListener('resize', resize, false); window.addEventListener('orientationchange', resize, false); window.addEventListener('keydown', stopDefaultBackspaceBehaviour, false); //window.addEventListener('mousemove', updateMouse, false); //window.addEventListener('touchstart', updateMouse, false); //window.addEventListener('touchmove', updateMouse, false); var foc = true; var blinking = false; window.addEventListener('focus', function () { foc = true; if (blinking == true) { setTimeout(function () { mathsInputCursorBlinkInterval = setCorrectingInterval(function () { mathsInputCursorBlink() }, 600); }, 100); } }); window.addEventListener('blur', function () { foc = false; if (blinking == true) { clearCorrectingInterval(mathsInputCursorBlinkInterval); inputCursorState = false; drawMathsInputText(currMathsInput); } if (typeof currMathsInput !== 'undefined') endMathsInput(); }); var makePDFLoaded = false; function loadMakePDF(callback) { if (makePDFLoaded == false) { makePDFLoaded = true; window.callback = callback; loadScript('pdfmake.min.js',loadMakePDF2); } else { callback(); } } function loadMakePDF2() { var callback = window.callback; delete window.callback; loadScript('vfs_fonts.js',callback); } /*window.addEventListener('touchstart',touchPreventDefault,false); window.addEventListener('touchmove',touchPreventDefault,false); window.addEventListener('touchend',touchPreventDefault,false); var touchPreventDefault = function(e) { e.preventDefault; } var isMobile = { Android: function () { return navigator.userAgent.match(/Android/i); }, BlackBerry: function () { return navigator.userAgent.match(/BlackBerry/i); }, iOS: function () { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }, Opera: function () { return navigator.userAgent.match(/Opera Mini/i); }, Windows: function () { return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i); }, any: function () { return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); } } if (isMobile.any()) { document.getElementsByTagName("head")[0].innerHTML += '' document.ontouchmove = function (event) { event.preventDefault() } } */ if (isTask == true) { var page = []; if (boolean(window.sortPages,true) == true) { pages.sort(function(a,b) { return Number(a.order) - Number(b.order); }); } //pages.reverse(); prevPages.sort(function(a,b) { var d1 = new Date(a.timestamp).getTime(); var d2 = new Date(b.timestamp).getTime(); return d2-d1; }); for (var i = 0; i < prevPages.length; i++) { if (Number(prevPages[i].percentage < 100)) continue; var pageId = Number(prevPages[i].pageid); for (var j = 0; j < pages.length; j++) { if (Number(pages[j].pageid) == pageId) { if (un(pages[j].prev)) { pages[j].prev = prevPages[i].timestamp; } break; } } } } if (typeof FontFace !== 'undefined') { document.fonts.ready.then(function(res) { //console.log(document.fonts.size, 'FontFaces loaded.'); //console.log('result',res); loadScripts1(); }, function(err) { //console.log('error',err); loadScripts1(); }); } else { loadScripts1(); } function loadScripts1() { for (var i = 0; i < scriptsToLoad.length; i++) { loadScript(scriptsToLoad[i], scriptLoaded); } } function loadScript(url, callback, errorCallback, index) { if (un(errorCallback)) errorCallback = function() {}; var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.charset = "UTF-8"; var url2 = typeof cacheVersion === 'string' ? url + '?' + cacheVersion : url; script.src = url2; script.index = index; script.onload = function() { if (!un(callback)) callback(this.index); }; script.onerror = function() { if (!un(errorCallback)) errorCallback(this.index); }; head.appendChild(script); } function scriptLoaded() { loadedScriptCount++; if (loadedScriptCount >= scriptsToLoad.length) { clearCanvas(); if (boolean(isTask,true) == true) { window.holder = createHolder(); showPage(0); } else { if (!un(scriptsToLoad2)) { for (var i = 0; i < scriptsToLoad2.length; i++) { loadScript(scriptsToLoad2[i]); } } } resize(); if (isTask == true) { TimeMe.initialize({ currentPageName: "page", idleTimeoutInSeconds: idleTimeoutInSeconds }); TimeMe.callWhenUserLeaves(function(){ inactive(); }); TimeMe.callWhenUserReturns(function(){ active(); }); if (typeof taskLogData == 'undefined') return; if (Number(taskLogData.status) < 3) { TimeMe.callAfterTimeElapsedInSeconds(reportIntervalInSeconds,reportHandler); } } } } var inactiveBox; function openPHP(url,postVars) { var form = document.createElement("form"); form.target = "_blank"; form.method = "POST"; form.action = url; form.style.display = "none"; for (var key in postVars) { var input = document.createElement("input"); input.type = "hidden"; input.name = key; input.value = encodeURIComponent(postVars[key]); form.appendChild(input); } document.body.appendChild(form); form.submit(); document.body.removeChild(form); } if (isTask == true) { var pointsMode = false; var pageLoadErrorCount = 0; var faded = false; function createInactiveBox() { inactiveBox = document.createElement('canvas'); inactiveBox.width = 400; inactiveBox.height = 120; inactiveBox.setAttribute('position', 'absolute'); inactiveBox.setAttribute('cursor', 'auto'); inactiveBox.setAttribute('draggable', 'false'); inactiveBox.setAttribute('class', 'buttonClass'); var ctx = inactiveBox.getContext('2d'); ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.clearRect(0, 0, 400, 120); ctx.fillStyle = "#FFF"; ctx.strokeStyle = "#000"; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(3, 3); ctx.lineTo(397, 3); ctx.lineTo(397, 117); ctx.lineTo(3, 117); ctx.lineTo(3, 3); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.font = "80px Hobo"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "#000"; ctx.fillText('Inactive', 200, 66); inactiveBox.style.pointerEvents = 'default'; inactiveBox.style.cursor = 'default'; inactiveBox.style.zIndex = 900000000; resize(); return inactiveBox; } //* var idleTimeoutInSeconds = 2*60; var reportIntervalInSeconds = 4*60; function reportHandler() { if (Number(taskLogData.status) == 3 || userType !== 0) return; logTime(); if (un(TimeMe)) return; clearReportTimeouts(); var time = Math.round(TimeMe.getTimeOnPageInSeconds('page')); TimeMe.callAfterTimeElapsedInSeconds(time+reportIntervalInSeconds,reportHandler); } function clearReportTimeouts() { for (var i = TimeMe.timeElapsedCallbacks.length - 1; i >= 0; i--) { TimeMe.timeElapsedCallbacks[i].pending = false; } } function active(e) { /*unfadePage(); /if (!un(inactiveBox)) { if (inactiveBox.parentNode == container) { container.removeChild(inactiveBox); } }*/ removeListenerStart(window,active); //console.log('active'); } function inactive() { /*fadePage(); if (un(inactiveBox)) inactiveBox = createInactiveBox(); container.appendChild(inactiveBox);*/ addListenerStart(window,active); //console.log('inactive'); } function logTime() { if (userType !== 0) return; if (Number(taskLogData.percentage) == 100 || Number(taskLogData.status) == 3) { clearReportTimeouts(); return; } var timeSpent = Math.round(TimeMe.getTimeOnPageInSeconds('page')/60); var browserInfo = getBrowserInfo(); var params = "tasksLogId="+taskLogData.taskNumber+"&timeSpent="+timeSpent+"&browserInfo="+browserInfo; //console.log('logTime params: ', params); var sendReportX = new XMLHttpRequest(); sendReportX.open("post", "_logTime.php", true); sendReportX.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); sendReportX.errorCallback = function() {}; sendReportX.onreadystatechange = function() { if (this.readyState == 4) { if (this.status !== 200) { if (typeof this.errorCallback == 'function') this.errorCallback(); return; } //console.log('logTime sent'); //reportHandler(); } } sendReportX.send(params); } //*/ /* var inactiveAfter = 300; var inactiveStartTime; var inactiveTime = 0; var isActive = true; var startTime = new Date(); var activityMonitor = setTimeout(function(){inactive()}, inactiveAfter*1000); window.addEventListener('mouseup', active, false); window.addEventListener('touchend', active, false); window.addEventListener('mousedown', active, false); window.addEventListener('touchstart', active, false); window.addEventListener('keydown', active, false); window.addEventListener('blur', inactive, false); function active(event) { if (!un(event) && event.target.nodeName !== 'TEXTAREA') event.preventDefault(); if (isTask == true) { clearTimeout(activityMonitor); activityMonitor = setTimeout(function(){inactive()}, inactiveAfter*1000); if (isActive == false && pageIndex !== pages.length) { isActive = true; var currentTime = new Date(); inactiveTime += (currentTime - inactiveStartTime); if (inactiveBox.parentNode == container) container.removeChild(inactiveBox); unfadePage(); } } } function inactive() { clearTimeout(activityMonitor); isActive = false; inactiveStartTime = new Date(); if (boolean(window.logPages,false) == false) { fadePage(); if (un(inactiveBox)) inactiveBox = createInactiveBox(); container.appendChild(inactiveBox); } } function getTimeSpent() { var currentTime = new Date(); var ms = currentTime - startTime - inactiveTime; return Math.floor(ms/1000); } function getTime() { var currentTime = new Date(); var timeSpent = currentTime - startTime - inactiveTime; timeSpent /= 60000; return Math.round(timeSpent+Number(taskLogData.prevTime)); } function logTime() { if (userType !== 0) return; if (Number(taskLogData.percentage) == 100 || Number(taskLogData.status) == 3) { clearTimeout(minuteCounter); return; } if (isActive == true) { var timeSpent = getTime(); var browserInfo = getBrowserInfo(); var params = "tasksLogId="+taskLogData.taskNumber+"&time="+timeSpent+"&inactiveTime="+inactiveTime+"&browserInfo="+browserInfo; //console.log('logTime params: ', params); var sendReportX = new XMLHttpRequest(); sendReportX.open("post", "_logTime.php", true); sendReportX.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); sendReportX.onload = function() { //var response = (this.responseText).split(';'); //console.log('logTime response: ', this.responseText); taskLogData.totalTime = this.responseText; connectionErrorMessage = 0; } sendReportX.onreadystatechange = function() { if (sendReportX.readyState == 4 && sendReportX.status !== 200 && connectionErrorMessage == 0) { alert('Error connecting to the MathsPad database. Your results may not be logged. Check your internet connection.'); connectionErrorMessage = 1; } } sendReportX.send(params); } clearTimeout(minuteCounter); minuteCounter = setTimeout(function(){logTime()}, 4*60000); } if (userType == 0) { taskLogData.prevTime = taskLogData.totalTime; taskLogData.prevStatus = taskLogData.status; taskLogData.prevPercentage = taskLogData.percentage; var connectionErrorMessage; var minuteCounter = setTimeout(function(){logTime()}, 4*60000); } //*/ function fadePage() { if (faded == true) return; var nodes = container.childNodes; for (var n = 0; n < nodes.length; n++) { if (nodes[n].nodeType !== 1 || nodes[n] == inactiveBox) continue; nodes[n].savedOpacity = nodes[n].style.opacity; nodes[n].style.opacity = 0.5; } faded = true; } function unfadePage() { var nodes = container.childNodes; for (var n = 0; n < nodes.length; n++) { if (nodes[n].nodeType !== 1) continue; var opacity = !un(nodes[n].savedOpacity) ? nodes[n].savedOpacity : 1; nodes[n].style.opacity = opacity; delete nodes[n].savedOpacity; } faded = false; } function createHolder() { var prev = playButton(20,20,50,prevPage,{dir:'left',fillColor:'#3FF',lineWidth:4,radius:8,zIndex:1000}); var next = playButton(1200-20-50,20,50,nextPage,{dir:'right',fillColor:'#3FF',lineWidth:4,radius:8,zIndex:1000}); var reload = newctx({rect:[1200-130,20,50,50],pe:true,zIndex:1000}); addListener(reload.canvas,reloadPage); drawRefreshButton(reload,4,4,42,'#C9F','left'); var canvas = newctx({rect:[0,0,1200,700],z:1}).canvas; showObj(canvas); var check = newctx({rect:[1200-340,20,200,50],pe:true,z:10000000}).canvas; text({ctx:check.ctx,textArray:['<><>Check Answer'],left:2,top:2,width:196,height:46,align:'center',vertAlign:'middle',box:{type:'loose',borderColor:'#000',borderWidth:4,radius:8,color:'#6F9'}}); addListenerEnd(check,checkPage); var home2 = newctx({rect:[712,555,386,80],pe:true,zIndex:1000}).canvas; text({ctx:home2.ctx,rect:[2,2,382,76],text:['<><>Return to My Profile '],align:'right',vertAlign:'middle',box:{type:'loose',borderColor:'#000',borderWidth:4,color:'#FFF',radius:8},allowSpaces:true}); var home = newctx({rect:[80,20,50,50],pe:true,zIndex:1000}).canvas; roundedRect2(home.ctx,2,2,46,46,8,4,'#000','#FFF'); var homeImage = new Image; homeImage.onload = function() { holder.home.ctx.drawImage(homeImage, 4.5, 4, 42, 42); var image = holder.home.ctx.getImageData(0, 0, 500, 200); var imageData = image.data, length = imageData.length; for (var i=0; i < length; i+=4) { if (imageData[i] == 255 && imageData[i+1] == 255 && imageData[i+2] == 255) imageData[i+3] = 50; } image.data = imageData; roundedRect2(home.ctx,2,2,46,46,8,4,'#000','#FFF'); holder.home.ctx.putImageData(image, 0, 0); roundedRect2(holder.home.ctx,2,2,46,46,8,4,'#000'); holder.home2.ctx.drawImage(homeImage, 12, 8, 42*1.5, 42*1.5); } homeImage.src = "/Images/logoSmall.PNG"; var loading = newctx({pe:true,z:1000000}).canvas; loading.style.cursor = 'default'; textBox(loading.ctx,[425,295,350,110],['<><>Loading...'],'#3FF'); var disablePeCanvas = newctx({pe:true,zIndex:1000000000000}).canvas; disablePeCanvas.style.cursor = 'default'; var summary = newctx().canvas; var summary2 = newctx({z:3}).canvas; return {prev:prev,next:next,reload:reload.canvas,canvas:canvas,check:check,home:home,loading:loading,feedback:[],feedbackButton:[],completed:[],disablePeCanvas:disablePeCanvas,summary:summary,summary2:summary2,home2:home2}; } function prevPage() { if (pageIndex == 0) return; hidePage(); pageIndex--; showPage(); } function nextPage() { if (pageIndex == pages.length - 1) return; hidePage(); pageIndex++; showPage(); } function goToPage(num) { if (un(num)) num = pages.length - 1; if (num < 0 || num > pages.length-1) return; hidePage(); pageIndex = roundToNearest(num,1); showPage(); } function hidePage() { endMathsInput(); unfadePage(); keyboardHardOpen = false; hideKeyboard2(); if (pageIndex < pages.length) { for (var c = 0; c < canvases[pageIndex].length; c++) { if (canvases[pageIndex][c].parentNode == container) { container.removeChild(canvases[pageIndex][c]); } } for (var m = 0; m < mathsInput[pageIndex].length; m++) { hideMathsInput(mathsInput[pageIndex][m]); } for (var s = 0; s < pages[pageIndex].stars.length; s++) { hideObj(pages[pageIndex].stars[s]); //pages[pageIndex].stars[s].stopSpin(); } } if (!un(draw) && !un(draw.drawCanvas)) { pages[pageIndex].paths = draw.path; pages[pageIndex].beforeDraw = draw.beforeDraw; pages[pageIndex].afterDraw = draw.afterDraw; pages[pageIndex].drawMode = draw.drawMode; delete draw.beforeDraw; delete draw.afterDraw; draw.path = []; drawCanvasPaths(); calcCursorPositions(); } holder.canvas.ctx.clearRect(0,80,1200,620); hideObj(holder.feedbackButton[pageIndex]); hideObj(holder.completed[pageIndex]); hideObj(holder.summary); hideObj(holder.summary2); hideObj(holder.home2); } function showPage() { /*if (pageIndex == pages.length) { showSummaryPage(); return; }*/ active(); if (un(page[pageIndex])) { pageLoadErrorCount++; loadPage(function() { if (boolean(p.taskPageAutoLoad,false) == true) { taskPageAutoLoad(p); }; pages[pageIndex].paths = draw.path; pages[pageIndex].beforeDraw = draw.beforeDraw; pages[pageIndex].afterDraw = draw.afterDraw; showPage(); },function() { page[pageIndex] = undefined; if (pageLoadErrorCount < 3) prevPage(); Notifier.error('Error connecting to the server. The page cannot be loaded.'); }); } else { for (var c = 0; c < canvases[pageIndex].length; c++) { if (canvases[pageIndex][c].vis == true) { container.appendChild(canvases[pageIndex][c]); } } for (var m = 0; m < mathsInput[pageIndex].length; m++) { showMathsInput(mathsInput[pageIndex][m]); } holder.canvas.ctx.clearRect(0,0,1200,700); if (boolean(window.logPages,false) == false) { textBox(holder.canvas.ctx,[140,20,100,50],['<><>'+String(pageIndex+1)+' / '+String(pages.length)],'#CCF'); drawPoints(); for (var s = 0; s < pages[pageIndex].stars.length; s++) { if (pages[pageIndex].stars[s].show == true) { showObj(pages[pageIndex].stars[s]); } } if (pages[pageIndex].completed == false && un(pages[pageIndex].prev)) { if (boolean(page[pageIndex].showHolderCheckButton,true) == true) { showObj(holder.check); } else { hideObj(holder.check); } holder.reload.style.opacity = 1; holder.reload.style.pointerEvents = 'auto'; if (pointsMode == true) holder.canvas.ctx.rect2({rect:[650+2,20+2,200-4,50-4],lineWidth:4,color:'#000',radius:8}); if (!un(holder.feedback[pageIndex]) && holder.feedback[pageIndex].fb == true) { showObj(holder.feedbackButton[pageIndex]); } else { hideObj(holder.feedbackButton[pageIndex]); } } else if (pages[pageIndex].completed == true) { hideObj(holder.check); showObj(holder.completed[pageIndex]); text({ctx:holder.canvas.ctx,left:650,width:410,top:20,height:50,align:'center',vertAlign:'middle',textArray:['<><><>Page Completed!']}); holder.reload.style.opacity = 0.5; holder.reload.style.pointerEvents = 'none'; hideObj(holder.feedbackButton[pageIndex]); } else if (!un(pages[pageIndex].prev)) { if (boolean(page[pageIndex].showHolderCheckButton,true) == true) { showObj(holder.check); } else { hideObj(holder.check); } showObj(holder.completed[pageIndex]); holder.reload.style.opacity = 1; holder.reload.style.pointerEvents = 'auto'; if (pointsMode == true) holder.canvas.ctx.rect2({rect:[650+2,20+2,200-4,50-4],lineWidth:4,color:'#000',radius:8}); if (!un(holder.feedback[pageIndex]) && holder.feedback[pageIndex].fb == true) { showObj(holder.feedbackButton[pageIndex]); } else { hideObj(holder.feedbackButton[pageIndex]); } } showObj(holder.reload); showObj(holder.home); } else { var filename = String(pageData[pageIndex].pageid); while (filename.length < 4) filename = "0"+filename; textBox(holder.canvas.ctx,[80,20,100,50],['<><>'+String(filename)],'#CCF'); if (typeof preview !== 'undefined' && !un(preview.button)) showObj(preview.button); } showObj(holder.prev); showObj(holder.next); hideObj(holder.loading); if (boolean(page[pageIndex].allowReload,true) == false) { hideObj(holder.reload); } else { showObj(holder.reload); } if (!un(draw) && !un(draw.drawCanvas)) { draw.path = pages[pageIndex].paths || []; draw.beforeDraw = pages[pageIndex].beforeDraw; draw.afterDraw = pages[pageIndex].afterDraw; if (!un(pages[pageIndex].drawMode)) { if (draw.drawMode !== pages[pageIndex].drawMode) { changeDrawMode(pages[pageIndex].drawMode); } } drawCanvasPaths(); calcCursorPositions(); for (var i = 0; i < draw.drawCanvas.length; i++) showObj(draw.drawCanvas); showObj(draw.cursorCanvas); } if (pageIndex == 0) { holder.prev.style.opacity = 0.5; holder.prev.style.pointerEvents = 'none'; } else { holder.prev.style.opacity = 1; holder.prev.style.pointerEvents = 'auto'; } if (pageIndex == pages.length - 1) { holder.next.style.opacity = 0.5; holder.next.style.pointerEvents = 'none'; } else { holder.next.style.opacity = 1; holder.next.style.pointerEvents = 'auto'; } if (typeof keyboardButton1[pageIndex] !== 'undefined') { showObj(keyboardButton1[pageIndex]); } resize(); p = page[pageIndex]; if (boolean(window.logPages,false) == true) { if (typeof pageDataLog == 'function') pageDataLog(); if (typeof savePagePNG == 'function') savePagePNG(); } pageLoadErrorCount = 0; } } /*function showSummaryPage() { holder.canvas.ctx.clearRect(0,0,1200,700); hideObj(holder.check); hideObj(holder.reload); hideObj(holder.home); holder.next.style.opacity = 0.5; holder.next.style.pointerEvents = 'none'; var ctx = holder.summary.ctx; var ctx2 = holder.summary2.ctx; ctx.clear(); ctx2.clear(); text({ctx:ctx,rect:[120,5,1000,80],text:['<><>Task Summary'],vertAlign:'middle'}); var l = 712; var t = 130; text({ctx:ctx,left:l,width:386,top:t,height:46,vertAlign:'middle',textArray:['<>'+userName],box:{type:'loose',radius:8,color:'#CFF',borderColor:'#000',borderWidth:4,padding:10}}); if (pointsMode == true) { text({ctx:ctx,left:l,width:386,top:t,height:46,align:'right',vertAlign:'middle',textArray:['<><><>'+userPoints+' '],allowSpaces:true}); ctx.beginPath(); ctx.lineWidth = 4; ctx.strokeStyle = '#000'; drawStar({ctx:ctx,c:[l+361,t+23],r:12}); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = '#00F'; drawStar({ctx:ctx,c:[l+361,t+23],r:12}); ctx.fill(); } var cells = []; var comp = 0; var totalPoints = 0; for (var r = 0; r < pages.length; r++) { if (pages[r].completed == true) { comp++; totalPoints += pages[r].points; cells[r] = [ {text:['Page '+(r+1)],color:'#CFC'}, {minWidth:180,text:['<>Completed!'],color:'#CFC'} ]; if (pointsMode == true) cells[r].push({minWidth:200,color:'#CFC'}); } else if (!un(pages[r].prev)) { comp++; cells[r] = [ {text:['Page '+(r+1)],color:'#CFC'}, {minWidth:180,text:['<>Completed!'],color:'#CFC'} ]; if (pointsMode == true) cells[r].push({minWidth:200,color:'#CFC'}); } else { cells[r] = [ {text:['Page '+(r+1)]}, {minWidth:180,text:['Keep Trying!']} ]; if (pointsMode == true) cells[r].push({minWidth:200}); } } var table = drawTable2({ ctx:ctx, left:102, top:t, minCellWidth:100, minCellHeight:40, horizAlign:'center', text:{font:'Hobo',size:28,color:'#000'}, outerBorder:{show:true,width:4,color:'#000'}, innerBorder:{show:true,width:2,color:'#000'}, cells:cells }); if (pointsMode == true) { for (var r = 0; r < pages.length; r++) { var c = table.cell[r][2]; var rect = [c.left,c.top,c.width,c.height]; var l = rect[0]+rect[2]/2-(pages[r].points-1)*17.5; var t = (table.yPos[r]+table.yPos[r+1])/2; ctx2.lineWidth = 4; if (pages[r].completed == true) { ctx2.strokeStyle = '#000'; ctx2.fillStyle = '#FC3'; } else if (!un(pages[r].prev)) { ctx2.strokeStyle = '#666'; ctx2.fillStyle = '#CFC'; } else { ctx2.strokeStyle = '#666'; ctx2.fillStyle = '#FFC'; } for (var s = 0; s < pages[r].points; s++) { ctx2.beginPath(); drawStar({ctx:ctx2,c:[l,t],r:12}); ctx2.closePath(); ctx2.stroke(); ctx2.beginPath(); drawStar({ctx:ctx2,c:[l,t],r:12}); ctx2.fill(); l += 35; } } } if (pointsMode == true) { textBox(ctx2,[712,190,386,350],['<>Task Progress: '+String(taskLogData.percentage)+'%'+br+br+'Points earned: '+totalPoints+br+br+'Time Spent: '+String(taskLogData.totalTime)+' mins'+br+br+'<><>Your progress has'+br+'been logged.'],'#CFF'); } else { textBox(ctx2,[712,190,386,350],['<>Task Progress: '+String(taskLogData.percentage)+'%'+br+br+'Time Spent: '+String(taskLogData.totalTime)+' mins'+br+br+'<><>Your progress has'+br+'been logged.'],'#CFF'); } showObj(holder.summary); showObj(holder.summary2); showObj(holder.home2); inactive(); resize(); }*/ function loadPage(callback,errorCallback) { showObj(holder.loading); holder.prev.style.pointerEvents = 'none'; holder.prev.style.opacity = 0.5; holder.next.style.pointerEvents = 'none'; holder.next.style.opacity = 0.5; if (un(errorCallback)) errorCallback = function() {}; var filename = pages[pageIndex].pageid; while (filename.length < 4) { filename = "0" + filename; } pages[pageIndex].filename = filename; if (!un(pages[pageIndex].prev)) { pages[pageIndex].maxPoints = 1; pages[pageIndex].points = 1; holder.completed[pageIndex] = textCanvas([600-450/2,285,450,170],[''],'#EEE').canvas; resizeCanvas3(holder.completed[pageIndex]); var date = new Date(pages[pageIndex].prev.slice(0,pages[pageIndex].prev.indexOf(" "))); pages[pageIndex].prevDate = ['Sun','Mon','Tues','Weds','Thurs','Fri','Sat'][date.getDay()]+" "+date.getDate()+" "+['Jan','Feb','Mar','Apr','May','June','July','Aug','Sep','Oct','Nov','Dec'][date.getMonth()]+" "+date.getFullYear(); if (pointsMode == true) { text({ctx:holder.completed[pageIndex].ctx,left:0,top:16,width:450,height:100,textArray:['<><>Page Completed!<>'+br+'<><>Completed on '+pages[pageIndex].prevDate+br+'Click to practise again for an extra point'],align:'center'}); } else { text({ctx:holder.completed[pageIndex].ctx,left:0,top:28,width:450,height:100,textArray:['<><>Page Completed!<>'+br+'<><>Completed on '+pages[pageIndex].prevDate],align:'center'}); text({ctx:holder.completed[pageIndex].ctx,left:450-100,top:0,width:100,height:30,textArray:['<><>'+times+'<>Dismiss'],align:'center',vertAlign:'middle'}); } holder.completed[pageIndex].style.pointerEvents = 'auto'; holder.completed[pageIndex].style.zIndex = 10000000; addListener(holder.completed[pageIndex],function() { hideObj(holder.completed[pageIndex]); }); } else { pages[pageIndex].maxPoints = Number(pages[pageIndex].points); pages[pageIndex].points = Number(pages[pageIndex].points); } pages[pageIndex].completed = false; pages[pageIndex].stars = []; var l = 650+100-(pages[pageIndex].maxPoints-1)*17.5; if (pointsMode == true) { for (var s = 0; s < pages[pageIndex].maxPoints; s++) { var star = newctx({rect:[l+s*35-17.5,45-17.5,35,35],z:100000000}).canvas; star.color = ['#FC3','#000']; star.draw = function() { this.ctx.clear(); this.ctx.beginPath(); this.ctx.lineWidth = 4; this.ctx.strokeStyle = this.color[1]; drawStar({ctx:this.ctx,c:[17.5,17.5],r:12}); this.ctx.closePath(); this.ctx.stroke(); this.ctx.beginPath(); this.ctx.fillStyle = this.color[0]; drawStar({ctx:this.ctx,c:[17.5,17.5],r:12}); this.ctx.fill(); } star.draw(); star.click = function() { do { var color = ['#FC3','#F00','#33F','#3FF','#0C0','#CCC'][ran(0,5)]; } while(this.color[0] == color); this.color[0] = color; this.draw(); } star.show = true; pages[pageIndex].stars[s] = star; } } var feedbackButton = textCanvas([1130,90,50,50],['<><>!'],'#FC9').canvas; feedbackButton.style.zIndex = 1000; addListenerStart(feedbackButton,toggleFeedback); holder.feedbackButton[pageIndex] = feedbackButton; window.p = page[pageIndex] = {}; mathsInput[pageIndex] = []; canvases[pageIndex] = []; loadScript('pages/'+filename+'.js',function() { page[pageIndex] = p; callback(); },errorCallback); } function reloadPage() { for (var c = 0; c < canvases[pageIndex].length; c++) { canvases[pageIndex][c].data[100] = canvases[pageIndex][c].data[0]; canvases[pageIndex][c].data[101] = canvases[pageIndex][c].data[1]; resizeCanvas3(canvases[pageIndex][c]); canvases[pageIndex][c].style.zIndex = canvases[pageIndex][c].z; } for (var m = 0; m < mathsInput[pageIndex].length; m++) { setMathsInputText(mathsInput[pageIndex][m],[""]); } if (!un(page[pageIndex].dragSnapPos)) { for (var d = 0; d < page[pageIndex].dragSnapPos.length; d++) { page[pageIndex].dragSnapPos[d][4] = null; } } p = page[pageIndex]; if (!un(page[pageIndex].reload)) { page[pageIndex].reload(); } else if (!un(page[pageIndex].taskPageAutoLoad)) { taskPageAutoReload(page[pageIndex]); } if (!un(page[pageIndex].clear)) { page[pageIndex].clear(); } removeFeedback(); } function shuffleTableCells(obj) { var cells = []; for (var r = 0; r < obj.cells.length; r++) { for (var c = 0; c < obj.cells[r].length; c++) { cells.push(obj.cells[r][c]); } } cells = shuffleArray(cells); for (var r = 0; r < obj.cells.length; r++) { for (var c = 0; c < obj.cells[r].length; c++) { obj.cells[r][c] = cells.shift(); } } return obj; } function taskPageAutoLoad(p) { //console.log(p); p.ctx1 = newctx(); p.ctx2 = newctx({z:1000}); var paths = p.paths; var shuffleInputs = []; var shufflePos = []; var dragCheckMode = 'none'; var dragCanvasCount = 0; var dragAreaCount = 0; var dragSnapAreaCount = 0; for (var p2 = 0; p2 < paths.length; p2++) { var path = paths[p2]; if (un(path.isInput)) continue; if (path.isInput.type == 'drag') { dragCanvasCount++; } else if (path.isInput.type == 'dragArea') { if (path.isInput.snap == true) { dragSnapAreaCount++; } else { dragAreaCount++; } } } if (dragCanvasCount > 0) { if (dragSnapAreaCount > 0) { dragCheckMode = 'dragArea'; } else { dragCheckMode = 'dragCanvas'; } } for (var p2 = 0; p2 < paths.length; p2++) { var path = paths[p2]; if (un(path.isInput)) continue; for (var o = 0; o < path.obj.length; o++) { var obj = path.obj[o]; if (obj.type == 'text2' && path.isInput.type == 'text') { obj.draw = false; if (typeof p.inputs == 'undefined') p.inputs = []; var input = createMathsInput2({left:obj.rect[0],top:obj.rect[1],width:obj.rect[2],height:obj.rect[3],fontSize:32,algText:boolean(path.isInput.algText,false)}); input.pathObj = obj; input.type = 'text'; if (!un(path.isInput.tickStyle)) input.tickStyle = path.isInput.tickStyle; p.inputs.push(input); } else if (obj.type == 'table2' && path.isInput.type == 'select') { if (typeof p.inputs == 'undefined') p.inputs = []; obj.isInput = path.isInput; var multiSelect = boolean(path.isInput.multiSelect,false); var checkSelectCount = boolean(path.isInput.checkSelectCount,true); var shuffle = boolean(path.isInput.shuffle,false); var input = {type:'select',buttons:[],multiSelect:multiSelect,checkSelectCount:checkSelectCount,shuffle:shuffle}; p.inputs.push(input); if (shuffle == true) shuffleTableCells(obj); var yPos = obj.top; for (var r = 0; r < obj.cells.length; r++) { var xPos = obj.left; for (var c = 0; c < obj.cells[r].length; c++) { var button = newctx({rect:[xPos,yPos,obj.widths[c],obj.heights[r]],pE:true,z:100}).canvas; button.input = input; button.cell = obj.cells[r][c]; button.row = r; button.col = c; button.obj = obj; addListener(button,taskPageSelectButtonClick); input.buttons.push(button); obj.cells[r][c].toggle = false; xPos += obj.widths[c]; } yPos += obj.heights[r]; } } else if (path.isInput.type == 'drag') { updateBorder(path); var rect = path.tightBorder; rect[0] -= 3; rect[1] -= 3; rect[2] += 6; rect[3] += 6; var dragCanvas = newctx({rect:rect,drag:true,pe:true}).canvas; dragCanvas.ctx.translate(-rect[0],-rect[1]); for (var o = 0; o < path.obj.length; o++) { drawObjToCtx(dragCanvas.ctx,path,path.obj[o],1,1,0,0); } if (dragCheckMode == 'dragCanvas') { if (typeof p.inputs == 'undefined') p.inputs = []; p.inputs.push({type:'drag',canvas:dragCanvas,shuffle:path.isInput.shuffle,value:path.isInput.value}); } if (typeof p.dragCanvases == 'undefined') p.dragCanvases = []; p.dragCanvases.push({canvas:dragCanvas,shuffle:path.isInput.shuffle,value:path.isInput.value}); if (path.isInput.shuffle == true) { shuffleInputs.push(dragCanvas); shufflePos.push([rect[0],rect[1],shufflePos.length]); } paths.splice(p2,1); p2--; } else if (path.isInput.type == 'dragArea') { updateBorder(path); var rect = path.tightBorder; rect[0] -= 3; rect[1] -= 3; rect[2] += 6; rect[3] += 6; if (typeof p.dragAreas == 'undefined') p.dragAreas = []; p.dragAreas.push({rect:rect,value:path.isInput.value,snap:path.isInput.snap}); if (dragCheckMode == 'dragArea') { if (typeof p.inputs == 'undefined') p.inputs = []; p.inputs.push({type:'dragArea',rect:rect,value:path.isInput.value}); } if (path.isInput.snap == true) { if (typeof p.dragSnapPos == 'undefined') p.dragSnapPos = []; p.dragSnapPos.push(clone(rect.slice(0,4))); } } } } if (shuffleInputs.length > 0) { shufflePos = shuffleArray(shufflePos); for (var i = 0; i < shuffleInputs.length; i++) { shuffleInputs[i].data[0] = shufflePos[i][0]; shuffleInputs[i].data[1] = shufflePos[i][1]; shuffleInputs[i].data[100] = shufflePos[i][0]; shuffleInputs[i].data[101] = shufflePos[i][1]; shuffleInputs[i].style.zIndex = shufflePos[i][2]+10; shuffleInputs[i].z = shufflePos[i][2]+10; resizeCanvas(shuffleInputs[i]); } } taskPageAutoDrawPaths(p); if (!un(p.keyboard)) addKeyboard(p.keyboard); } function taskPageAutoDrawPaths(p) { p.ctx1.clear(); for (var p2 = 0; p2 < p.paths.length; p2++) { for (var o = 0; o < p.paths[p2].obj.length; o++) { var obj = p.paths[p2].obj[o]; if (boolean(obj.draw,true) == true) { drawObjToCtx(p.ctx1,p.paths[p2],obj); } } } } function taskPageSelectButtonClick(e) { var cells = e.target.obj.cells; var cell = e.target.cell; if (cell.toggle == true) { delete cell.toggle; } else if (e.target.input.multiSelect == true) { cell.toggle = true; } else { for (var r = 0; r < cells.length; r++) { for (var c = 0; c < cells[r].length; c++) { if (r == e.target.row && c == e.target.col) { cells[r][c].toggle = true; } else { delete cells[r][c].toggle; } } } } taskPageAutoDrawPaths(page[pageIndex]); } function taskPageAutoCheck(p) { var checkVars = {check:true,a:[],qs:p.inputs.length}; for (var q = 0; q < p.inputs.length; q++) { var input = p.inputs[q]; if (input.type == 'text') { var answer = false; if (input.stringJS !== "") { var obj = input.pathObj; var ans = removeTags(clone(input.richText)); for (var a = 0; a < obj.ans.length; a++) { if (arraysEqual(ans,removeTags(clone(obj.ans[a])))) { answer = true; break; } } } checkVars.a[q] = {type:'text',check:answer}; } else if (input.type == 'select') { var answer = []; var toggleCount = 0; var ansCount = 0; for (var b = 0; b < input.buttons.length; b++) { var cell = input.buttons[b].cell; var ans = boolean(cell.ans,false); if (ans == true) ansCount++; var toggle = boolean(cell.toggle,false); if (toggle == true) toggleCount++; answer[b] = {toggle:toggle,answer:ans}; } if (input.checkSelectCount == true) { if (toggleCount < ansCount || toggleCount == 0) { checkVars.check = false; checkVars.fb = "You need to select more answers."; } else if (toggleCount > ansCount) { checkVars.check = false; checkVars.fb = "You have selected too many answers."; } } checkVars.a[q] = {type:'select',check:answer}; } else if (input.type == 'drag') { var check = false; var hit = false; for (var a = 0; a < p.dragAreas.length; a++) { var rect = p.dragAreas[a].rect; if (hitTestRect2(input.canvas,rect[0],rect[1],rect[2],rect[3])) { hit = true; if (input.value == p.dragAreas[a].value) check = true; break; } } if (hit == false) { checkVars.check = false; checkVars.fb = "You need to drag all the boxes into position."; } checkVars.a[q] = {type:'dragArea',check:check}; } else if (input.type == 'dragArea') { var check = false; var hit = false; for (var d = 0; d < p.dragCanvases.length; d++) { var rect = input.rect; if (hitTestRect2(p.dragCanvases[d].canvas,rect[0],rect[1],rect[2],rect[3])) { hit = true; if (input.value == p.dragCanvases[d].value) check = true; break; } } if (hit == false) { checkVars.check = false; checkVars.fb = "You need to drag boxes into the positions."; } checkVars.a[q] = {type:'dragArea',check:check}; } } return checkVars; } function taskPageAutoMark(p,r) { p.ctx2.clear(); for (var q = 0; q < p.inputs.length; q++) { if (p.inputs[q].type !== 'text') continue; var data = p.inputs[q].data; if (p.inputs[q].tickStyle == 'small') { var mult = 0.6; var l2 = data[100]+data[102]-40*mult-3; var t2 = data[101]+data[103]-50*mult-3; if (r.m[q] == 1) { drawTick(p.ctx2,40*mult,50*mult,'#060',l2,t2,7*mult); } else { drawCross(p.ctx2,40*mult,50*mult,'#F00',l2,t2,7*mult); } p.inputs[q].markPos = [l2,t2,40*mult,50*mult]; p.inputs[q].markctx = p.ctx2; } else { var l2 = data[100]+data[102]+15; var t2 = data[101]+0.5*data[103]-25; if (r.m[q] == 1) { drawTick(p.ctx2,40,50,'#060',l2,t2,7); } else { drawCross(p.ctx2,40,50,'#F00',l2,t2,7); } p.inputs[q].markPos = [l2,t2,40,50]; p.inputs[q].markctx = p.ctx2; } } } function taskPageAutoReload(p) { p.ctx2.clear(); } function checkPage() { if (!un(holder.checkPageIndex) && holder.checkPageIndex > -1) return; holder.checkPageIndex = pageIndex; deselectMathsInput(); if (typeof page[holder.checkPageIndex].check == 'function') { var c = page[holder.checkPageIndex].check(); var checkFileName = String(pages[holder.checkPageIndex].filename); } else if (!un(page[holder.checkPageIndex].taskPageAutoLoad)) { var c = taskPageAutoCheck(page[holder.checkPageIndex]); var checkFileName = 'autoCheck'; } else { delete holder.checkPageIndex; return; } if (c.check == false) { if (!un(c.fb)) { drawFeedback(c.fb); } delete holder.checkPageIndex; } else { hideObj(holder.disablePeCanvas); hideObj(holder.check); var xmlHttp = new XMLHttpRequest(); xmlHttp.open("post", "pages/"+checkFileName+".php", true); xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlHttp.errorCallback = function() { Notifier.error('Error connecting to the server. Please try again shortly...'); hideObj(holder.disablePeCanvas); delete holder.checkPageIndex; setTimeout(function() { if (boolean(page[pageIndex].showHolderCheckButton,true) == true) { showObj(holder.check); } else { hideObj(holder.check); } },2000); }; xmlHttp.onerror = xmlHttp.errorCallback; xmlHttp.onreadystatechange = function() { if (this.readyState !== 4) return; if (this.status >= 400) { if (typeof this.errorCallback == 'function') this.errorCallback(); delete holder.checkPageIndex; return; } if (!un(document.origin) && document.origin.indexOf('localhost') > -1) console.log(this.responseText); var response = JSON.parse(this.responseText); if (!un(document.origin) && document.origin.indexOf('localhost') > -1) console.log('check php response:',response); pages[holder.checkPageIndex].pageLogKey = response.pageLogKey; if (un(pages[holder.checkPageIndex].checkCount)) pages[holder.checkPageIndex].checkCount = 0; pages[holder.checkPageIndex].checkCount++; p = page[holder.checkPageIndex]; if (!un(p.mark)) { p.mark(response); } else if (!un(p.taskPageAutoLoad)) { taskPageAutoMark(p,response); } if (typeof taskLogData !== 'undefined' && taskLogData !== null) { taskLogData.percentage = response.percentage; taskLogData.totalTime = response.timeSpent; taskLogData.status = response.status; } if (response.correct == 1) { pages[holder.checkPageIndex].completed = true; hideObj(holder.feedbackButton[holder.checkPageIndex]); hideObj(holder.feedback[holder.checkPageIndex]); holder.canvas.ctx.clearRect(650,20,200,50); removeFeedback(); if (Number(response.percentage) == 100) { showTaskCompleteMessage(); } else { reportHandler(); } if (boolean(page[holder.checkPageIndex].allowInteractionAfterCompletion,false) == false) { for (var c = 0; c < canvases[holder.checkPageIndex].length; c++) { canvases[holder.checkPageIndex][c].style.pointerEvents = 'none'; } for (var m = 0; m < mathsInput[holder.checkPageIndex].length; m++) { mathsInput[holder.checkPageIndex][m].cursorCanvas.style.pointerEvents = 'none'; } if (!un(draw) && !un(draw.cursorCanvas)) { pages[holder.checkPageIndex].drawMode = 'none'; changeDrawMode('none'); } } if (pointsMode == true) { window.count = 0; window.int = setCorrectingInterval(function() { var star = pages[holder.checkPageIndex].stars[window.count]; star.data[100] = Math.max(star.data[100]-9,613-17.5); resizeCanvas3(star); if (star.data[100] <= 613-17.5) { userPoints++; drawPoints(); window.count++; if (window.count == pages[holder.checkPageIndex].points) { clearCorrectingInterval(window.int); setTimeout(function() { for (s = 0; s < pages[holder.checkPageIndex].maxPoints; s++) { var star = pages[holder.checkPageIndex].stars[s]; if (s < pages[holder.checkPageIndex].points) { star.show = true; star.data[100] = 600-(pages[holder.checkPageIndex].points-1)*17.5+s*35-17.5; star.data[101] = 360; resizeCanvas3(star); star.style.pointerEvents = 'auto'; addListener(star,star.click); } else { star.show = false; hideObj(star); } } if (!un(holder.completed[holder.checkPageIndex])) { hideObj(holder.completed[holder.checkPageIndex]); } holder.completed[holder.checkPageIndex] = textCanvas([600-450/2,285,450,130],[''],['#F6F','#6FF','#FF6','#6F6','#66F','#F66'].ran()).canvas; showObj(holder.completed[holder.checkPageIndex]); text({ctx:holder.completed[holder.checkPageIndex].ctx,left:0,top:12,width:450,height:100,textArray:['<><>Page Completed!'],align:'center'}); holder.completed[holder.checkPageIndex].style.pointerEvents = 'auto'; holder.completed[holder.checkPageIndex].style.zIndex = 10000000; addListener(holder.completed[holder.checkPageIndex],function() { hideObj(holder.completed[holder.checkPageIndex]); for (var s = 0; s < pages[holder.checkPageIndex].stars.length; s++) { hideObj(pages[holder.checkPageIndex].stars[s]); } }); hideObj(holder.disablePeCanvas); showPage(); },800); } } },1000/26); } else { if (!un(holder.completed[holder.checkPageIndex])) { hideObj(holder.completed[holder.checkPageIndex]); } holder.completed[holder.checkPageIndex] = textCanvas([600-450/2,285,450,130],[''],['#F6F','#6FF','#FF6','#6F6','#66F','#F66'].ran()).canvas; var ctx = holder.completed[holder.checkPageIndex].ctx; text({ctx:ctx,left:0,top:12,width:450,height:100,textArray:['<><>Page Completed!'],align:'center'}); ctx.beginPath(); ctx.lineWidth = 4; ctx.strokeStyle = '#000'; drawStar({ctx:ctx,c:[450/2-35,90],r:12}); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = '#FC3'; drawStar({ctx:ctx,c:[450/2-35,90],r:12}); ctx.fill(); ctx.beginPath(); ctx.lineWidth = 4; ctx.strokeStyle = '#000'; drawStar({ctx:ctx,c:[450/2,90],r:12}); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = '#FC3'; drawStar({ctx:ctx,c:[450/2,90],r:12}); ctx.fill(); ctx.beginPath(); ctx.lineWidth = 4; ctx.strokeStyle = '#000'; drawStar({ctx:ctx,c:[450/2+35,90],r:12}); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = '#FC3'; drawStar({ctx:ctx,c:[450/2+35,90],r:12}); ctx.fill(); holder.completed[holder.checkPageIndex].style.pointerEvents = 'auto'; holder.completed[holder.checkPageIndex].style.zIndex = 100000; hideObj(holder.disablePeCanvas); if (holder.checkPageIndex === pageIndex) { addListener(holder.completed[holder.checkPageIndex],function() { hideObj(holder.completed[holder.checkPageIndex]); }); showPage(); if (Number(response.percentage) < 100) { showObj(holder.completed[holder.checkPageIndex]); } else { hideObj(holder.completed[holder.checkPageIndex]); } } } } else { hideObj(holder.disablePeCanvas); if (holder.checkPageIndex === pageIndex) { setTimeout(function() { if (boolean(page[pageIndex].showHolderCheckButton,true) == true) { showObj(holder.check); } else { hideObj(holder.check); } },4000); if (pointsMode == true && pages[holder.checkPageIndex].points > 1) { pages[holder.checkPageIndex].points--; var star = pages[holder.checkPageIndex].stars[pages[holder.checkPageIndex].points]; star.color = ['#CFF','#999']; star.draw(); } if (!un(response.fb)) { drawFeedback(response.fb); } } } delete holder.checkPageIndex; } c.points = pages[holder.checkPageIndex].points; if (!un(pages[holder.checkPageIndex].pageLogKey)) c.pageLogKey = pages[holder.checkPageIndex].pageLogKey; c.userKey = userKey; c.userType = userType; c.pageId = pages[holder.checkPageIndex].pageid; c.checkCount = pages[holder.checkPageIndex].checkCount || 0; c.pageIds = []; c.browserInfo = getBrowserInfo(); c.timeSpent = Math.round(TimeMe.getTimeOnPageInSeconds('page')/60); for (var p = 0; p < pages.length; p++) { c.pageIds.push(pages[p].pageid); } if (typeof taskLogData !== 'undefined' && taskLogData !== null) { c.tasksLogId = taskLogData.taskNumber; } if (!un(document.origin) && document.origin.indexOf('localhost') > -1) console.log(c); console.log(c, "c="+encodeURIComponent(JSON.stringify(c))); xmlHttp.send("c="+encodeURIComponent(JSON.stringify(c))); } } function drawPoints() { holder.canvas.ctx.clearRect(250,20,390,50); text({ctx:holder.canvas.ctx,left:252,width:386,top:22,height:46,vertAlign:'middle',textArray:['<>'+userName],box:{type:'loose',radius:8,color:'#CFF',borderColor:'#000',borderWidth:4,padding:10}}); if (pointsMode == true) { text({ctx:holder.canvas.ctx,left:252,width:386,top:22,height:46,align:'right',vertAlign:'middle',textArray:['<><><>'+userPoints+' '],allowSpaces:true}); holder.canvas.ctx.beginPath(); holder.canvas.ctx.lineWidth = 4; holder.canvas.ctx.strokeStyle = '#000'; drawStar({ctx:holder.canvas.ctx,c:[613,45],r:12}); holder.canvas.ctx.closePath(); holder.canvas.ctx.stroke(); holder.canvas.ctx.beginPath(); holder.canvas.ctx.fillStyle = '#00F'; drawStar({ctx:holder.canvas.ctx,c:[613,45],r:12}); holder.canvas.ctx.fill(); } } function drawFeedback(txt) { if (typeof txt == 'string') txt = [txt]; txt.unshift('<>'); if (un(holder.feedback[pageIndex])) { holder.feedback[pageIndex] = newctx({pe:true,z:100000}).canvas; addListenerEnd(holder.feedback[pageIndex],toggleFeedback); } holder.feedback[pageIndex].fb = true; var fb = holder.feedback[pageIndex]; showObj(holder.feedbackButton[pageIndex]); var size = text({ctx:fb.ctx,textArray:txt,align:'center',measureOnly:true,left:800,top:90+5,width:400,height:610,box:{type:'tight',color:'#FC9',borderColor:'#000',borderWidth:4,radius:8,padding:15}}); fb.data[100] = 1120 - size.tightRect[2]; fb.data[101] = 90; fb.data[102] = size.tightRect[2]; fb.data[103] = size.tightRect[3]; fb.width = size.tightRect[2]; fb.height = size.tightRect[3]; resizeCanvas3(fb); textBox(fb.ctx,[0,0,size.tightRect[2],size.tightRect[3]],txt,'#FC9'); showObj(holder.feedback[pageIndex]); }; function toggleFeedback() { if (un(holder.feedback[pageIndex])) return; if (holder.feedback[pageIndex].parentNode == container) { hideObj(holder.feedback[pageIndex]); } else { showObj(holder.feedback[pageIndex]); } }; function removeFeedback() { if (!un(holder.feedback[pageIndex])) { holder.feedback[pageIndex].fb = false; hideObj(holder.feedbackButton[pageIndex]); hideObj(holder.feedback[pageIndex]); } } var taskCompleteMessage; function loadTaskCompleteMessage() { //create purple background taskCompleteMessage = newctx({rect:[20,94,1150,576],vis:false,z:1000000,pE:true,page:false}).canvas; taskCompleteMessage.style.backgroundColor = "#C6F"; taskCompleteMessage.style.borderRadius = "5px"; taskCompleteMessage.style.border = "4px solid black" taskCompleteMessage.style.cursor = "auto"; //addListener(taskCompleteMessage,dismissTaskCompleteMessage); taskCompleteMessage.starYellow = new Image; taskCompleteMessage.starYellowPointy = new Image; taskCompleteMessage.starWhite6points = new Image; taskCompleteMessage.starYellow.src = "../Images/starYellow.png"; taskCompleteMessage.starYellowPointy.src = "../Images/starYellowPointy.png"; taskCompleteMessage.starWhite6points.src = "../Images/starWhite6points.png"; taskCompleteMessage.stars = []; //create dismiss button var dismiss = newctx({rect:[1050, 120, 110, 26],vis:false,z:10000001,pE:true,page:false}).canvas; dismiss.ctx.font = "30px Arial"; dismiss.ctx.fillStyle = "#FFF"; dismiss.ctx.textAlign = "center"; dismiss.ctx.textBaseline = "middle"; dismiss.ctx.fillText("Dismiss", 55, 13); //addListener(dismiss, dismissTaskCompleteMessage) taskCompleteMessage.stars.push(dismiss); for (var i = 0; i < 9; i++) { var l = [100,750,700,300,950,900,820,1000,500][i]-6; var t = [150,120,400,120,300,120,250,500,100][i]; var w = [126,126,252,189,189,126,126,126,252][i]; var star = newctx({rect:[l,t,w,w],vis:false,z:100000002+i,page:false}).canvas; star.style.cursor = "auto"; taskCompleteMessage.stars.push(star); } resize(); } function showTaskCompleteMessage() { if (un(taskCompleteMessage)) loadTaskCompleteMessage(); hideObj(holder.completed[pageIndex]); showObj(taskCompleteMessage); for (i = 0; i < taskCompleteMessage.stars.length; i++) { showObj(taskCompleteMessage.stars[i]); taskCompleteMessage.stars[i].style.zIndex = 1000000; } taskCompleteMessage.ctx.fillStyle = "#FFF"; taskCompleteMessage.ctx.textAlign = "center"; taskCompleteMessage.ctx.textBaseline = "middle"; if (userType == 'Pupil') { taskCompleteMessage.ctx.font = "110px Hobo"; taskCompleteMessage.ctx.fillText("Task Complete!", 350, 275); taskCompleteMessage.ctx.font = "55px Hobo"; taskCompleteMessage.ctx.fillText("Well done, " + userName, 350, 420); taskCompleteMessage.ctx.font = "55px Hobo"; taskCompleteMessage.ctx.fillText("Your result has been logged", 350, 490); } else { taskCompleteMessage.ctx.font = "110px Hobo"; taskCompleteMessage.ctx.fillText("Task Complete!", 350, 375); } taskCompleteMessage.interval = setInterval(function(){taskCompleteMessage.rotate()},25); taskCompleteMessage.rotate = function() { for (i = 1; i < taskCompleteMessage.stars.length; i++) { taskCompleteMessage.stars[i].ctx.clear(); taskCompleteMessage.stars[i].ctx.translate(taskCompleteMessage.stars[i].data[2] / 2, taskCompleteMessage.stars[i].data[3] / 2); taskCompleteMessage.stars[i].ctx.rotate(Math.PI / 180); taskCompleteMessage.stars[i].ctx.translate(taskCompleteMessage.stars[i].data[2] / -2, taskCompleteMessage.stars[i].data[3] / -2); } taskCompleteMessage.stars[1].ctx.drawImage(taskCompleteMessage.starYellow,20,20,86,86); taskCompleteMessage.stars[2].ctx.drawImage(taskCompleteMessage.starYellow,20,20,86,86); taskCompleteMessage.stars[3].ctx.drawImage(taskCompleteMessage.starYellow,60,60,172,172); taskCompleteMessage.stars[4].ctx.drawImage(taskCompleteMessage.starWhite6points,24,33,141,123); taskCompleteMessage.stars[5].ctx.drawImage(taskCompleteMessage.starWhite6points,24,33,141,123); taskCompleteMessage.stars[6].ctx.drawImage(taskCompleteMessage.starYellowPointy,20,21,86,84); taskCompleteMessage.stars[7].ctx.drawImage(taskCompleteMessage.starYellowPointy,20,21,86,84); taskCompleteMessage.stars[8].ctx.drawImage(taskCompleteMessage.starYellowPointy,20,21,86,84); taskCompleteMessage.stars[9].ctx.drawImage(taskCompleteMessage.starYellowPointy,40,42,152,148); } addListener(window,dismissTaskCompleteMessage); } function dismissTaskCompleteMessage() { hideObj(taskCompleteMessage); for (i = 0; i < taskCompleteMessage.stars.length; i++) { hideObj(taskCompleteMessage.stars[i]); } if (!un(taskCompleteMessage.interval)) { clearInterval(taskCompleteMessage.interval); } removeListener(window,dismissTaskCompleteMessage); } function createHorizPos(num,width,left,right) { if (typeof left == 'undefined') left = width; if (typeof right == 'undefined') right = width; var space = (1200 - num * width - left - right) / (num-1); var arr = []; for (var i = 0; i < num; i++) { arr[i] = left+i*(width+space); } return arr; } function createVertPos(num,height,top,bottom) { if (typeof top == 'undefined') top = height; if (typeof bottom == 'undefined') bottom = height; var space = (620 - num * height - top - bottom) / (num-1); var arr = []; for (var i = 0; i < num; i++) { arr[i] = 80+top+i*(height+space); } return arr; } function swipedetect(el, callback){ var touchsurface = el, swipedir, startX, startY, distX, distY, dist, threshold = 150, //required min distance traveled to be considered swipe restraint = 100, // maximum distance allowed at the same time in perpendicular direction allowedTime = 400, // maximum time allowed to travel that distance elapsedTime, startTime, handleswipe = callback || function(swipedir){} touchsurface.addEventListener('touchstart', function(e){ var touchobj = e.changedTouches[0] swipedir = 'none' dist = 0 startX = touchobj.pageX startY = touchobj.pageY startTime = new Date().getTime() // record time when finger first makes contact with surface e.preventDefault() }, false) touchsurface.addEventListener('touchmove', function(e){ e.preventDefault() // prevent scrolling when inside DIV }, false) touchsurface.addEventListener('touchend', function(e){ var touchobj = e.changedTouches[0] distX = touchobj.pageX - startX // get horizontal dist traveled by finger while in contact with surface distY = touchobj.pageY - startY // get vertical dist traveled by finger while in contact with surface elapsedTime = new Date().getTime() - startTime // get time elapsed if (elapsedTime <= allowedTime){ // first condition for awipe met if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint){ // 2nd condition for horizontal swipe met swipedir = (distX < 0)? 'left' : 'right' // if dist traveled is negative, it indicates left swipe } else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint){ // 2nd condition for vertical swipe met swipedir = (distY < 0)? 'up' : 'down' // if dist traveled is negative, it indicates up swipe } } if (e.target.drag !== true) handleswipe(swipedir) e.preventDefault() }, false) } swipedetect (canvas, function(swipedir){ // swipedir contains either "none", "left", "right", "top", or "down" if (swipedir == 'left') { nextPage(); } else if (swipedir == 'right') { prevPage(); } }) } function getBrowserInfo() { /** * JavaScript Client Detection * (C) viazenetti GmbH (Christian Ludwig) */ var unknown = '-'; // screen var screenSize = ''; if (screen.width) { width = (screen.width) ? screen.width : ''; height = (screen.height) ? screen.height : ''; screenSize += '' + width + " x " + height; } // browser var nVer = navigator.appVersion; var nAgt = navigator.userAgent; var browser = navigator.appName; var version = '' + parseFloat(navigator.appVersion); var majorVersion = parseInt(navigator.appVersion, 10); var nameOffset, verOffset, ix; // Opera if ((verOffset = nAgt.indexOf('Opera')) != -1) { browser = 'Opera'; version = nAgt.substring(verOffset + 6); if ((verOffset = nAgt.indexOf('Version')) != -1) { version = nAgt.substring(verOffset + 8); } } // Opera Next if ((verOffset = nAgt.indexOf('OPR')) != -1) { browser = 'Opera'; version = nAgt.substring(verOffset + 4); } // Edge else if ((verOffset = nAgt.indexOf('Edge')) != -1) { browser = 'Microsoft Edge'; version = nAgt.substring(verOffset + 5); } // MSIE else if ((verOffset = nAgt.indexOf('MSIE')) != -1) { browser = 'Microsoft Internet Explorer'; version = nAgt.substring(verOffset + 5); } // Chrome else if ((verOffset = nAgt.indexOf('Chrome')) != -1) { browser = 'Chrome'; version = nAgt.substring(verOffset + 7); } // Safari else if ((verOffset = nAgt.indexOf('Safari')) != -1) { browser = 'Safari'; version = nAgt.substring(verOffset + 7); if ((verOffset = nAgt.indexOf('Version')) != -1) { version = nAgt.substring(verOffset + 8); } } // Firefox else if ((verOffset = nAgt.indexOf('Firefox')) != -1) { browser = 'Firefox'; version = nAgt.substring(verOffset + 8); } // MSIE 11+ else if (nAgt.indexOf('Trident/') != -1) { browser = 'Microsoft Internet Explorer'; version = nAgt.substring(nAgt.indexOf('rv:') + 3); } // Other browsers else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) { browser = nAgt.substring(nameOffset, verOffset); version = nAgt.substring(verOffset + 1); if (browser.toLowerCase() == browser.toUpperCase()) { browser = navigator.appName; } } // trim the version string if ((ix = version.indexOf(';')) != -1) version = version.substring(0, ix); if ((ix = version.indexOf(' ')) != -1) version = version.substring(0, ix); if ((ix = version.indexOf(')')) != -1) version = version.substring(0, ix); majorVersion = parseInt('' + version, 10); if (isNaN(majorVersion)) { version = '' + parseFloat(navigator.appVersion); majorVersion = parseInt(navigator.appVersion, 10); } // mobile version var mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer); // cookie var cookieEnabled = (navigator.cookieEnabled) ? true : false; if (typeof navigator.cookieEnabled == 'undefined' && !cookieEnabled) { document.cookie = 'testcookie'; cookieEnabled = (document.cookie.indexOf('testcookie') != -1) ? true : false; } // system var os = unknown; var clientStrings = [ {s:'Windows 10', r:/(Windows 10.0|Windows NT 10.0)/}, {s:'Windows 8.1', r:/(Windows 8.1|Windows NT 6.3)/}, {s:'Windows 8', r:/(Windows 8|Windows NT 6.2)/}, {s:'Windows 7', r:/(Windows 7|Windows NT 6.1)/}, {s:'Windows Vista', r:/Windows NT 6.0/}, {s:'Windows Server 2003', r:/Windows NT 5.2/}, {s:'Windows XP', r:/(Windows NT 5.1|Windows XP)/}, {s:'Windows 2000', r:/(Windows NT 5.0|Windows 2000)/}, {s:'Windows ME', r:/(Win 9x 4.90|Windows ME)/}, {s:'Windows 98', r:/(Windows 98|Win98)/}, {s:'Windows 95', r:/(Windows 95|Win95|Windows_95)/}, {s:'Windows NT 4.0', r:/(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/}, {s:'Windows CE', r:/Windows CE/}, {s:'Windows 3.11', r:/Win16/}, {s:'Android', r:/Android/}, {s:'Open BSD', r:/OpenBSD/}, {s:'Sun OS', r:/SunOS/}, {s:'Linux', r:/(Linux|X11)/}, {s:'iOS', r:/(iPhone|iPad|iPod)/}, {s:'Mac OS X', r:/Mac OS X/}, {s:'Mac OS', r:/(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/}, {s:'QNX', r:/QNX/}, {s:'UNIX', r:/UNIX/}, {s:'BeOS', r:/BeOS/}, {s:'OS/2', r:/OS\/2/}, {s:'Search Bot', r:/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/} ]; for (var id in clientStrings) { var cs = clientStrings[id]; if (cs.r.test(nAgt)) { os = cs.s; break; } } var osVersion = unknown; if (/Windows/.test(os)) { var a = /Windows (.*)/.exec(os) if (a instanceof Array) { osVersion = a[1]; } os = 'Windows'; } switch (os) { case 'Mac OS X': var a = /Mac OS X (10[\.\_\d]+)/.exec(nAgt); if (a instanceof Array) { osVersion = a[1]; } break; case 'Android': var a = /Android ([\.\_\d]+)/.exec(nAgt); if (a instanceof Array) { osVersion = a[1]; } break; case 'iOS': var a = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer); if (a instanceof Array) { osVersion = a[1] + '.' + a[2] + '.' + (a[3] | 0); } break; } window.browserinfo = { screen: screenSize, browser: browser, browserVersion: version, browserMajorVersion: majorVersion, mobile: mobile, os: os, osVersion: osVersion, cookies: cookieEnabled, }; return os+" "+osVersion+" "+browser+" "+version+" "+screenSize+" mobile:"+mobile+" cookies:"+cookieEnabled; } function stopDefaultBackspaceBehaviour(e) { if (e.keyCode == 8 && e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && e.target.nodeName !== 'TD') { e.preventDefault ? e.preventDefault() : e.returnValue = false; } } function xWindowToCanvas(xCoord) { return mainCanvasWidth * ((xCoord - canvasMetrics.left) / (canvasDisplayWidth)); } function xCanvasToWindow(xCoord) { return canvasMetrics.left + (xCoord / mainCanvasWidth) * canvasDisplayWidth; } function yWindowToCanvas(yCoord) { return mainCanvasHeight * ((yCoord - canvasMetrics.top) / canvasDisplayHeight); } function yCanvasToWindow(yCoord) { return canvasMetrics.top + (yCoord / mainCanvasHeight) * canvasDisplayHeight; } function addListener(toButton, yourFunction) { toButton.addEventListener("touchend", yourFunction, false) toButton.addEventListener("mouseup", yourFunction, false) } function removeListener(toButton, yourFunction) { toButton.removeEventListener("touchend", yourFunction, false) toButton.removeEventListener("mouseup", yourFunction, false) } function addListenerStart(toButton, yourFunction) { toButton.addEventListener("touchstart", yourFunction, false) toButton.addEventListener("mousedown", yourFunction, false); } function removeListenerStart(toButton, yourFunction) { toButton.removeEventListener("touchstart", yourFunction, false) toButton.removeEventListener("mousedown", yourFunction, false); } function addListenerMove(toButton, yourFunction) { toButton.addEventListener("touchmove", yourFunction, false) toButton.addEventListener("mousemove", yourFunction, false) } function removeListenerMove(toButton, yourFunction) { toButton.removeEventListener("touchmove", yourFunction, false) toButton.removeEventListener("mousemove", yourFunction, false) } function addListenerEnd(toButton, yourFunction) { toButton.addEventListener("touchend", yourFunction, false) toButton.addEventListener("mouseup", yourFunction, false); } function removeListenerEnd(toButton, yourFunction) { toButton.removeEventListener("touchend", yourFunction, false) toButton.removeEventListener("mouseup", yourFunction, false); } function resize() { var totalWidth = mainCanvasWidth + mainCanvasMargins[0] + mainCanvasMargins[2]; var totalHeight = mainCanvasHeight + mainCanvasMargins[1] + mainCanvasMargins[3]; var aspectRatio = totalWidth / totalHeight; if (window.innerWidth / window.innerHeight > aspectRatio) { var totalDisplayWidth = window.innerHeight * aspectRatio; var totalDisplayHeight = window.innerHeight; } else { var totalDisplayWidth = window.innerWidth; var totalDisplayHeight = window.innerWidth / aspectRatio; } canvasDisplayWidth = totalDisplayWidth * (mainCanvasWidth / totalWidth); canvasDisplayHeight = totalDisplayHeight * (mainCanvasHeight / totalHeight); canvasDisplayLeft = (window.innerWidth - totalDisplayWidth) / 2 + mainCanvasMargins[0] * (totalDisplayWidth/totalWidth); canvasDisplayTop = (window.innerHeight - totalDisplayHeight) / 2 + mainCanvasMargins[1] * (totalDisplayHeight/totalHeight); //canvas.style.left = canvasDisplayLeft + 'px'; //canvas.style.top = canvasDisplayTop + 'px'; //canvas.style.top = '0px'; canvas.style.width = canvasDisplayWidth + 'px'; canvas.style.height = canvasDisplayHeight + 'px'; canvasDisplayRect = canvas.getBoundingClientRect(); if (typeof inactiveBox !== 'undefined') resizeCanvas(inactiveBox, 400, 290, 400, 120); if (boolean(isTask,true) == true) { resizeCanvas3(holder.prev); resizeCanvas3(holder.next); resizeCanvas3(holder.reload); resizeCanvas3(holder.canvas); resizeCanvas3(holder.check); resizeCanvas3(holder.home); resizeCanvas3(holder.home2); resizeCanvas3(holder.loading); resizeCanvas3(holder.summary); resizeCanvas3(holder.summary2); resizeCanvas3(holder.disablePeCanvas); for (var i = 0; i < holder.feedback.length; i++) { if (!un(holder.feedback[i])) resizeCanvas3(holder.feedback[i]); } for (var i = 0; i < holder.feedbackButton.length; i++) { if (!un(holder.feedbackButton[i])) resizeCanvas3(holder.feedbackButton[i]); } for (var i = 0; i < holder.completed.length; i++) { if (!un(holder.completed[i])) resizeCanvas3(holder.completed[i]); } if (pageIndex < pages.length) { if (!un(pages[pageIndex].stars)) { for (var s = 0; s < pages[pageIndex].stars.length; s++) { resizeCanvas3(pages[pageIndex].stars[s]); } } } } if (!un(canvases[pageIndex])) { for (var c = 0; c < canvases[pageIndex].length; c++) { resizeCanvas3(canvases[pageIndex][c]); } } if (!un(taskCompleteMessage)) { resizeCanvas3(taskCompleteMessage); for (var c = 0; c < taskCompleteMessage.stars.length; c++) { resizeCanvas3(taskCompleteMessage.stars[c]); } } if (!un(mathsInput[pageIndex])) { for (var m = 0; m < mathsInput[pageIndex].length; m++) { resizeCanvas3(mathsInput[pageIndex][m].canvas); resizeCanvas3(mathsInput[pageIndex][m].cursorCanvas); } } if (!un(slider[pageIndex])) { for (var s = 0; s < slider[pageIndex].length; s++) { resizeCanvas3(slider[pageIndex][s].backCanvas); resizeCanvas3(slider[pageIndex][s].sliderCanvas); resizeCanvas3(slider[pageIndex][s].labelCanvas); } } for (var j = 0; j < keyboard.length; j++) { if (typeof keyboard[j] !== 'undefined') { resizeCanvas3(keyboardButton1); resizeCanvas3(keyboardButton2); resizeCanvas(keyboard[j], keyboardData[j][100], keyboardData[j][101], keyboardData[j][2], keyboardData[j][3]); for (var i = 0; i -1) { var pos = closestPos; if (typeof pos[4] !== 'undefined' && pos[4] !== null) { pos[4].data[100] = pos[4].data[0]; pos[4].data[101] = pos[4].data[1]; resizeCanvas3(pos[4]); } dragObj.data[100] = pos[0]; dragObj.data[101] = pos[1]; resizeCanvas3(dragObj); pos[4] = dragObj; } } if (typeof dragObj.ondragstop == 'function') dragObj.ondragstop(); if (typeof dragObj.dragStop == 'function') dragObj.dragStop(); dragObj = null; } function showObj(obj, hideAfter) { if (un(obj)) return; if (!isElement(obj)) { if (obj instanceof Array) { for (var i = 0; i < obj.length; i++) { showObj(obj[i]); } } else if (typeof obj == 'object') { for (var i in obj) { showObj(obj[i]); } } return; } if (!un(draw) && !un(draw.div) && draw.drawCanvas.indexOf(obj) > -1) { draw.div.children[0].appendChild(obj); } else { container.appendChild(obj); resizeCanvas3(obj); } obj.vis = true; if (typeof hideAfter == 'number') { setTimeout(function () { hideObj(obj) }, hideAfter); } } function hideObj(obj) { if (un(obj)) return; if (!isElement(obj)) { if (obj instanceof Array) { for (var i = 0; i < obj.length; i++) { hideObj(obj[i]); } } else if (typeof obj == 'object') { for (var i in obj) { hideObj(obj[i]); } } return; } obj.vis = false; if (obj.parentNode == container) { container.removeChild(obj) } else if (!un(draw) && !un(draw.div) && draw.drawCanvas.indexOf(obj) > -1 && !un(obj.parentNode)) { obj.parentNode.removeChild(obj); } }