Edit D:\app\Administrator\product\11.2.0\dbhome_1\apex\images\editor\codearea.xbl.xml
<?xml version="1.0"?> <bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <binding id="codearea" display="html:div"> <content> <html:div id="body"> <html:pre id="one-char"><html:span>X</html:span></html:pre> <html:pre id="canvas"><html:textarea id="clipboard" readonly="true" style="position:absolute;width:30px;height:30px;visibility:hidden;z-index:-1000"></html:textarea></html:pre> <html:pre id="cursors"><html:span id="cursor"> </html:span><html:span id="col-cursor"> </html:span><html:span id="line-cursor"> </html:span><html:span id="selection-plane"><html:span id="start-of-selection" style="display:none"> </html:span><html:span id="end-of-selection" style="display:none"> </html:span></html:span></html:pre> <html:pre id="left-margin"><html:span id="line-cursor-in-margin"> </html:span></html:pre> </html:div> <html:div style="display: none"><children/></html:div> </content> <implementation> <property name="formattedCode" onget="return this.codeArea.getFormattedCode();" readonly="true" /> <property name="value" onget="return this.codeArea.getValue();" onset="return this.codeArea.setValue(val);" /> <property name="readOnly" onget="return this.codeArea.getReadOnly();" onset="return this.codeArea.setReadOnly(val);" /> <property name="selection" onget="return this.codeArea.getSelection();" readonly="true" /> <method name="createCodeRange"> <body>return this.codeArea.createCodeRange();</body> </method> <method name="getLineByNumber"> <parameter name="number" /> <body>return this.codeArea.getLineByNumber(number);</body> </method> <method name="findNext"> <parameter name="s" /> <parameter name="flags" /> <body>return this.codeArea.findNext(s, flags);</body> </method> <method name="findPrevious"> <parameter name="s" /> <parameter name="flags" /> <body>return this.codeArea.findPrevious(s, flags);</body> </method> <method name="findAll"> <parameter name="s" /> <parameter name="flags" /> <body>return this.codeArea.findAll(s, flags);</body> </method> <method name="getAction"> <parameter name="name" /> <body>return this.actions[name];</body> </method> <method name="createAction"> <parameter name="_perform" /> <parameter name="options" /> <body>return this.codeArea.createAction(_perform, options);</body> </method> <method name="addEventListener"> <parameter name="eventName" /> <parameter name="handler" /> <parameter name="useCapture" /> <body>return this.codeArea.addEventListener(eventName, handler, useCapture);</body> </method> <constructor><![CDATA[ var crossBrowser = { uid:0, getOwnerDocument: function(el) { if (el.ownerDocument) return el.ownerDocument; else { while (el.parentNode) el = el.parentNode; return el.document; } }, getUniqueId: function(el) { if (!el.uniqueID) { if (el.id) el.uniqueID = el.id else { el.uniqueID = ('__uid' + this.uid++); el.id = el.uniqueID; } } return el.uniqueID; }, getIFrameDocument: function(iframe) { if (iframe.contentWindow) return iframe.contentWindow.document; else if (iframe.contentDocument) return iframe.contentDocument; else { var iframes = comp.getElementsByTagName('iframe'); for (var i=0; i<iframes.length; i++) if (iframes[i] == iframe) return window.frames[i].document; //alert(window.frames[0].comp.location.href); } // else // return null; }, getInnerText: function(el) { if (typeof comp.body.innerText == 'string') return el.innerText; else { var html = el.innerHTML; var txt = html.replace(/<[^>]+>/g, ''); return txt; } }, getCurrentStyleAttribute: function(el, attr) { var val = 'inherit'; while (el && ((val == 'inherit') || (val == 'transparent'))) { if (typeof el.currentStyle == 'object') val = el.currentStyle[attr]; else { var cssVal = null; switch (attr) { case "margin": case "padding": cssVal = ""; var composites = { "top":1, "right":1, "bottom":1, "left":1 }; for (var direction in composites) { var singleVal = this.__getMozStyleAttribute(el, attr + "-" + direction); cssVal += singleVal + " "; } break; default: cssVal = this.__getMozStyleAttribute(el, attr); break; } val = cssVal; } el = el.parentNode; } return val; }, __getMozStyleAttribute : function(el, attr) { var cssAttr = attr.replace(/([A-Z])/g, function(s){ return "-" + s.toLowerCase(); }); return window.getComputedStyle(el, "").getPropertyValue(cssAttr); }, setStyleAttribute: function(el, attr, value) { // See if this style attr is stored // if so: a runtimeStyle attr is overriding it if (el.storedStyle && typeof(el.storedStyle[attr]) != 'undefined') // Override stored value el.storedStyle[attr] = value; else // Override live value el.style[attr] = value; }, removeStyleAttribute: function(el, attr) { // See if this style attr is stored // if so: a runtimeStyle attr is overriding it if (el.storedStyle && typeof(el.storedStyle[attr]) != 'undefined') // Override the stored attribute with a null value el.storedStyle[attr] = null; else if (el.style.removeAttribute) // Remove the style attribute el.style.removeAttribute(attr); else el.style[attr] = ''; }, setRuntimeStyleAttribute: function(el, attr, value) { if (!el.storedStyle) el.storedStyle = {}; if (typeof(el.storedStyle[attr]) == 'undefined') el.storedStyle[attr] = el.style[attr]; el.style[attr] = value; }, removeRuntimeStyleAttribute: function(el, attr) { //if (attr == 'overflow') //alert(el.storedStyle[attr] + ', ' + ((el.storedStyle[attr])?'xxx':'yyy')); //el.storedStyle[attr] = 'visible'; if (el.storedStyle) { if (el.storedStyle[attr]) el.style[attr] = el.storedStyle[attr]; else if (typeof(el.storedStyle[attr]) != 'undefined') if (el.style.removeAttribute) el.style.removeAttribute(attr); else el.style[attr] = ''; delete el.storedStyle[attr]; } }, // returns node.xml, because the crap called safari can't do it and doesn't allow dom prototyping either, woohoo, praise safari getXML : function(node) { if (typeof node.xml == 'string') return node.xml; // duh return new XMLSerializer().serializeToString(node); }, getOuterHTML: function(el) { if (typeof el.outerHTML == 'string') return el.outerHTML; else { var div = document.createElement('div'); div.appendChild(el.cloneNode(true)); return div.innerHTML; } }, getNthChildElement: function(el, n) { el = el.firstChild; while (el && (el.nodeType != 1) && (n>=0)) { if (el.nodeType == 1) n--; el = el.nextSibling; } return el; }, // returns node.text getText : function(node) { if (typeof node.text == 'string') return node.text; if (!node.firstChild) return ""; return node.firstChild.nodeValue; }, // sets node.text setText : function(node, text) { if (typeof node.text == 'string') node.text = text; else { while (node.firstChild) node.removeChild(node.firstChild); node.appendChild(this.getOwnerDocument(node).createTextNode(text)); } }, appendHTML : function(el, html) { if (el.insertAdjacentHTML) el.insertAdjacentHTML("beforeend", html); else { var div = document.createElement("div"); div.innerHTML = html; while (div.firstChild) el.appendChild(div.firstChild); } }, // returns box element getBoundingClientRect : function(el) { if (typeof el.getBoundingClientRect != 'undefined') return el.getBoundingClientRect(); else { var rect = { left: 0, top: 0, right: 0, bottom: 0 }; var tempElt = el; while (tempElt) { rect.top += (tempElt.offsetTop || 0) - (tempElt.scrollTop || 0); rect.left += (tempElt.offsetLeft || 0) - (tempElt.scrollLeft || 0); tempElt = tempElt.offsetParent; } rect.bottom = rect.top + el.offsetHeight; rect.right = rect.left + el.offsetWidth; return rect; } }, // gets the position relative to top/left of #body getBoundingBodyRect : function(el) { var box = { top : 0, left : 0, width : el.offsetWidth, height : el.offsetHeight }; var opEl = el; while (opEl && (opEl.getAttribute("id") != "body")) { box.left += opEl.offsetLeft; box.top += opEl.offsetTop; opEl = opEl.offsetParent; } box.right = box.left + box.width; box.bottom = box.top + box.height; if ((el.nodeName.toLowerCase() == 'li') && (this.getCurrentStyleAttribute(el, 'display') == 'block')) { var corrWidth = 20; box.left -= corrWidth; box.width += corrWidth; } return box; }, // swap nodes swapNode : function(el1, el2) { if (typeof el1.swapNode != 'undefined') el1.swapNode(el2); else { var temp = document.createElement("div"); var pn = el1.parentNode; pn.replaceChild(temp, el1); el2.parentNode.replaceChild(el1, el2); pn.replaceChild(el2, temp); temp = null; } }, pasteText: function(s) { var rng = this.getSelectionRange(); if (!rng) return; if (typeof rng.setText != 'undefined') { rng.setText(s); return; } else { var sel = window.getSelection(); sel.removeAllRanges(); var textNode = rng.setText(s); rng = this.createRange(); rng.moveToElementText(textNode); rng.collapse(); sel.addRange(rng.rng); } }, getSelectionRange: function() { if (typeof comp.selection == 'object') { var sel = comp.selection; var rngs = sel.createRangeCollection(); return rngs.length > 0 ? new IERange(rngs.item(0)) : false; } else { var sel = window.getSelection(); return sel.rangeCount > 0 ? new MozRange(sel.getRangeAt(0)) : false; } }, setInputSelectionRange: function(inp, start, end) { if (inp.createTextRange) { var tr = inp.createTextRange(); tr.move('character', start); tr.moveEnd('character', end - start); tr.select(); } else { inp.selectionStart = start; inp.selectionEnd = end; } }, getInputSelectionStart: function(inp) { if (typeof comp.selection == 'object') { var sel = comp.selection; var rng = sel.createRange(); rng.collapse(); rng.moveStart("character", -10000); return rng.text.length; } else return inp.selectionStart; }, getInputSelectionEnd: function(inp) { if (typeof comp.selection == 'object') { var sel = comp.selection; var rng = sel.createRange(); rng.moveStart("character", -10000); return rng.text.length; } else return inp.selectionEnd; }, unselect: function() { if (comp.selection && comp.selection.empty) comp.selection.empty(); else { var sel = window.getSelection(); sel.removeAllRanges(); } }, createRange: function() { if (comp.body.createTextRange) { var rng = comp.body.createTextRange(); rng.collapse(); return new IERange(rng); } else { var rng = document.createRange(); rng.setStart(comp.body, 0); rng.setEnd(comp.body, 0); return new MozRange(rng); } }, getStyleSheetNode: function(doc, ssID) { if (comp.all && window.createPopup) return comp.getElementById(ssID); else { for (var i=0; i<comp.styleSheets.length; i++) { var ss = comp.styleSheets[i]; if (ss.ownerNode.id == ssID) return ss.ownerNode; } return null; } }, getXMLHTTP: function () { if (window.XMLHttpRequest) return new XMLHttpRequest(); else if (window.ActiveXObject) { var XMLHTTPPROGIDS = [ "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ]; for (var i=0; i<XMLHTTPPROGIDS.length; i++) { try { return new ActiveXObject(XMLHTTPPROGIDS[i]); } catch (e) {} } } return null; }, isPreceding: function(el1, el2) { if (typeof el1.sourceIndex == 'number') { return el1.sourceIndex < el2.sourceIndex; } else { return !!(el2.compareDocumentPosition(el1) & 0x02); } }, addClass: function(el, className) { var s = ' '; var cc = s + el.className + s; if (cc.indexOf(s + className + s) == -1) el.className += s + className; }, removeClass: function(el, className) { var s = ' '; var cc = s + el.className + s; el.className = cc.replace(s + className + s, ''); } }; function MozRange (rng) { this.rng = rng; } MozRange.prototype = { moveToElementText: function (elt) { this.rng.selectNode(elt); }, select: function () { var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(this.rng.cloneRange()); }, collapse: function (toStart) { this.rng.collapse(toStart); }, pasteHTML: function (html) { if (this.rng.length) { var ddiv = document.createElement('div'); ddiv.innerHTML = html; var dimg = ddiv.firstChild; this.rng(0).parentNode.insertBefore(dimg, this.rng(0)); this.rng(0).parentNode.removeChild(this.rng(0)); this.rng.remove(0); this.rng.addElement(dimg); } else { if (this.parentElement().nodeName.toLowerCase() == 'textarea') { var ta = oip.canvas.curView.ta; var pos1 = ta.selectionStart; var pos2 = ta.selectionEnd; var pos3 = pos1 + html.length; var newText = ta.value.substring(0, pos1) + html + ta.value.substring(pos2, ta.value.length); ta.value = newText; ta.setSelectionRange(pos1, pos3); } else { var doc = this.parentElement().ownerDocument; doc.execCommand('inserthtml', false, html); } } }, getParentElement: function () { var parent = this.rng.commonAncestorContainer; if (parent.nodeType == 3) return parent.parentNode; else return parent; }, getText: function () { var root = document.createElement("x"); root.appendChild(this.rng.cloneContents()); return root.innerText; }, setText: function (s) { var t = comp.createTextNode(s); this.rng.deleteContents(); this.rng.insertNode(t); return t; }, setStartByChars: function(node, chars) { this.setPosByChars(node, chars, this.rng.setStart); }, setEndByChars: function(node, chars) { this.setPosByChars(node, chars, this.rng.setEnd); }, setPosByChars: function(node, chars, method) { var xpe = new XPathEvaluator(); var iter = crossBrowser.xpe.evaluate("descendant::text()", node, crossBrowser.nsr, null, null); var l = 0; var n; var s=''; while (n = iter.iterateNext()) { var nl = n.textContent.length; if (l + nl >= chars) break; l+=nl; } var offset = chars - l; if (!n) { // reached end of line n = node; offset = node.childNodes.length; } if (method == this.rng.setStart && this.rng.comparePoint(n, offset) == 1) { // requesting to set start after end which Mozilla doesn't allow // bring start to current end this.rng.collapse(false); // set end instead method = this.rng.setEnd; } method.call(this.rng, n, offset); }, duplicate: function() { return new MozRange(this.rng.cloneRange()); } }; function IERange (rng) { this.rng = rng; } IERange.prototype = { moveToElementText: function (elt) { this.rng.moveToElementText(elt); }, select: function () { this.rng.select(); }, collapse: function (toStart) { this.rng.collapse(toStart); }, pasteHTML: function (html) { if (this.rng.length) { var ddiv = document.createElement('div'); ddiv.innerHTML = html; var dimg = ddiv.firstChild; this.rng(0).parentNode.insertBefore(dimg, this.rng(0)); this.rng(0).parentNode.removeChild(this.rng(0)); this.rng.remove(0); this.rng.addElement(dimg); } else this.rng.pasteHTML(html); }, getParentElement: function () { if (this.rng.parentElement) return this.rng.parentElement(); else if (this.rng.length) return this.rng(0); else return null; }, getHTMLText: function () { return this.rng.htmlText; }, getText: function () { return this.rng.text; }, setText: function (s) { this.rng.text = s; }, setStartByChars: function(node, offset) { this.setPosByChars(node, offset, "Start"); }, setEndByChars: function(node, offset) { this.setPosByChars(node, offset, "End"); }, setPosByChars: function(node, offset, point) { var l = node.innerText.length; if (offset >= l) offset = l; var rng = comp.body.createTextRange(); rng.moveToElementText(node); //rng.select(); if (offset || !l) rng.moveStart("character", offset); else { rng.moveStart("character", 1); rng.moveStart("character", -1); } this.rng.setEndPoint(point + "ToStart", rng); }, execCommand: function(cmd, ui) { if (this.rng.execCommand) this.rng.execCommand(cmd, ui); }, duplicate: function() { return new IERange(this.rng.duplicate()); }, getBoundingWidth: function() { return this.rng.boundingWidth; }, toString: function() { return "IERange: " + this.rng.text; } }; if (window.XPathEvaluator) { crossBrowser.xpe = new XPathEvaluator(); crossBrowser.nsr = crossBrowser.xpe.createNSResolver(document); Node.prototype.__defineGetter__("innerText", function() { var xpRes = crossBrowser.xpe.evaluate("descendant::text()", this, crossBrowser.nsr, null, null); var a = []; var n; while (n = xpRes.iterateNext()) a.push(n.nodeValue); return a.join(''); }); Node.prototype.__defineSetter__("innerText", function(text) { return this.textContent = text; }); }; function LinkedList() { this.__hash = {}; } LinkedList.prototype = { __hash: null, firstItem: null, lastItem: null, curItem: null, add: function(item) { item.prevItem = this.lastItem; item.nextItem = null; if (this.lastItem) this.lastItem.nextItem = item; else this.firstItem = item; this.lastItem = item; if (typeof(item.id) != 'undefined') this.__hash[item.id] = item; }, remove: function(item) { if (item.prevItem) item.prevItem.nextItem = item.nextItem; if (item.nextItem) item.nextItem.prevItem = item.prevItem; if (item == this.firstItem) this.firstItem = item.nextItem; if (item == this.lastItem) this.lastItem = item.prevItem; if (typeof(item.id) != 'undefined') delete this.__hash[item.id]; }, reset: function(item) { if (item && (item != this.firstItem) && (this.firstItem != this.lastItem)) { // Close loop this.firstItem.prevItem = this.lastItem; this.lastItem.nextItem = this.firstItem; // Store new endpoints this.firstItem = item; this.lastItem = item.prevItem; // Open loop if (item.prevItem) item.prevItem.nextItem = null; item.prevItem = null; } return this.curItem = this.firstItem; // return this.curItem; }, getNextItem: function() { if (this.curItem) this.curItem = this.curItem.nextItem; return this.curItem; }, getItemById: function(id) { return this.__hash[id]; }, hasNextItem: function() { return (this.curItem && this.curItem.nextItem); }, hasItems: function() { return (this.firstItem != null); } }; function Shredder() { } Shredder.prototype = { RUN_ONCE_REQUIRED: 1, RUN_ONCE: 2, RUN_MANY: 3, DEFAULT_RUN_MODE: 2, __queues: [null, new LinkedList(), new LinkedList(), new LinkedList()], __maxRunTime: 30, __intervalTime: 1, __ih: null, __isRunning: false, __curTime: null, extend: function(shred, runMode) { for (var m in Shred.prototype) if (!shred[m]) shred[m] = Shred.prototype[m]; if (!runMode) runMode = this.DEFAULT_RUN_MODE; shred.setRunMode(runMode); }, __prepareRun: function() { if (!shredder.__ih) shredder.__ih = setInterval(shredder.__runTasks, shredder.__intervalTime); }, __stopRunning: function() { clearInterval(shredder.__ih); shredder.__ih = null; }, i:0, __runTasks: function() { shredder.__isRunning = true; var tStart = +new Date(); var tNow = tStart; var tEnd = tStart + shredder.__maxRunTime; var hasActiveTask = false; var runMode = shredder.RUN_ONCE_REQUIRED; modeLoop: while (true) { var didRun = false; var curList = shredder.__queues[runMode]; if (curList.hasItems()) { if (runMode > shredder.RUN_ONCE_REQUIRED) curList.reset(curList.getNextItem()); var shred = curList.firstItem; while (shred) { // Run the next shred. if (shred.__active) { hasActiveTask = true; didRun = true; shred.run(tStart); } if (runMode > shredder.RUN_ONCE_REQUIRED) { // See if it is time to stop. if (new Date() >= tEnd) break modeLoop; } shred = shred.nextItem; } } // See if there were running tasks. if (runMode >= shredder.RUN_MANY && !didRun) break modeLoop; // See if it is time to stop. if (new Date() >= tEnd) break modeLoop; // Determine next runMode. if (runMode < shredder.RUN_MANY) runMode++; } if (!hasActiveTask) shredder.__stopRunning(); shredder.__isRunning = false; } }; function Shred() { } Shred.prototype = { __active: false, __runMode: null, setRunMode: function(newMode) { // First remove from old mode queue. if (this.__runMode) shredder.__queues[this.__runMode].remove(this); // Store the new settings. this.__runMode = newMode; // Add this shred. shredder.__queues[newMode].add(this); }, start: function() { shredder.__prepareRun(); this.__active = true; }, stop: function() { this.__active = false; }, run: function(t) { } }; var shredder = new Shredder(); // sorteren op attrName en dan op element // dan kan ik colors overslaan als stap te klein function Animator(anims, modifiers) { this.anims = anims; this.modifiers = modifiers; this.delay = modifiers.delay; this.duration = modifiers.duration; this.runCount = 0; this.skipCount = 0; if (!document.body.runtimeStyle) modifiers.useRuntimeStyle = false; this.styleCollectionName = (modifiers.useRuntimeStyle?'runtimeStyle':'style'); // Start with a prevPhase of 0 to prevent rendering of phase == 0 which is the start value. this.prevPhase = 0; var bitDepth = 10; var numSteps = 1 << bitDepth; var bitDepthColor = 6; var numStepsColor = 1 << bitDepthColor; var code = [ 'this.runCount++\n', 'var tPhase = (t - this.tStart)/this.duration;\n', 'if (t - this.tPrev > 200)\n', '{\n', ' this.tStart += (t - this.tPrev);\n', ' this.tStop += (t - this.tPrev);\n', ' this.tPrev = t;\n', ' return;\n', '}\n', 'this.tPrev = t;\n', 'if (tPhase >= 1)\n', '{\n', ' this.run = this.finish;\n', ' var phase = ', numSteps, ';\n', ' var phaseColor = ', numStepsColor, ';\n', '}\n', 'else\n', '{\n', ' var f = ', this.profiles[modifiers.profile], ';\n', ' var phase = Math.round(', numSteps, '*f);\n', ' var phaseColor = Math.round(', numStepsColor, '*f);\n', '}\n', 'if (phase == this.prevPhase)\n', '{\n', ' this.skipCount++;\n', ' return;\n', '}\n', 'this.prevPhase = phase;\n' ]; var numAnims = anims.length; var codeByRange = []; for (var i=0; i<numAnims; i++) { var anim = anims[i]; if (!anim.el.uniqueID) anim.el.uniqueID = 'moz_' + this.uid++; for (var attrName in anim.targetState) { var attrValue = anim.targetState[attrName]; // Special treatment for non-IE if (!anim.el.currentStyle) { var attrNameMozilla = attrName.replace(/([A-Z])/g, function(s1){ return '-' + s1.toLowerCase(); }); switch (attrName) { case 'alpha': attrName = 'MozOpacity'; attrNameMozilla = '-moz-opacity'; break; case 'gradient': continue; break; } } // Store whatever is needed to set the value of this attribute switch (attrName) { case 'scrollTop': case 'scrollLeft': this[anim.el.uniqueID + 'el'] = anim.el; break; case 'top': case 'right': case 'bottom': case 'left': case 'width': case 'height': case 'color': case 'backgroundColor': case 'borderTopColor': case 'borderRightColor': case 'borderBottomColor': case 'borderLeftColor': case 'clip': case 'MozOpacity': this[anim.el.uniqueID + 'elStyle'] = anim.el[this.styleCollectionName]; break; case 'alpha': this[anim.el.uniqueID + 'alpha'] = anim.el.filters.item("DXImageTransform.Microsoft.Alpha"); break; case 'gradient': this[anim.el.uniqueID + 'gradient'] = anim.el.filters.item("progid:DXImageTransform.Microsoft.gradient"); break; } // Get the start value for this attribute var vStart = this.getCurrentStyleAttribute(anim.el, attrName); // Determine these variables to store in the codeByRange sparse array. // The line of code that sets the new value. var codeLine; // The least amount the phase needs to increase to make the value set by this animation increase by 1. var relPhase; // The absolute amount that this animation will change its value. var absRange; // Add code to function to set current value of attribute switch (attrName) { case 'top': case 'right': case 'bottom': case 'left': case 'width': case 'height': case 'MozOpacity': var relRange = attrValue - vStart; absRange = Math.abs(relRange); relPhase = Math.ceil((1 << bitDepth) / absRange); codeLine = [ 'this.', anim.el.uniqueID, 'elStyle.', attrName, '=(', Math.floor(numSteps*(vStart+0.5)), '+phase*', relRange, ')>> ', bitDepth, ';\n' ].join(""); break; case 'color': case 'backgroundColor': case 'borderTopColor': case 'borderRightColor': case 'borderBottomColor': case 'borderLeftColor': attrValue = this.__castColor(attrValue); var rRange = Math.floor(attrValue[0] - vStart[0]); var gRange = Math.floor(attrValue[1] - vStart[1]); var bRange = Math.floor(attrValue[2] - vStart[2]); absRange = Math.max(Math.abs(rRange), Math.abs(gRange), Math.abs(bRange)); relPhase = Math.ceil((1 << bitDepthColor) / absRange) << (bitDepth - bitDepthColor); if (anim.el.currentStyle) codeLine = [ 'this.', anim.el.uniqueID, 'elStyle.', attrName, '=', '((', Math.floor(numStepsColor*(vStart[0]+0.5)), '+phaseColor*', rRange, ') >> ', bitDepthColor, ' << 16) | ', '((', Math.floor(numStepsColor*(vStart[1]+0.5)), '+phaseColor*', gRange, ') >> ', bitDepthColor, ' << 8) | ', '((', Math.floor(numStepsColor*(vStart[2]+0.5)), '+phaseColor*', bRange, ') >> ', bitDepthColor, ');\n' ].join(''); else codeLine = ['this.', anim.el.uniqueID, 'elStyle.', attrName, '=["rgb(",', '(', Math.floor(numStepsColor*(vStart[0]+0.5)), '+phaseColor*', rRange, ')>> ', bitDepthColor, ',",", ', '(', Math.floor(numStepsColor*(vStart[1]+0.5)), '+phaseColor*', gRange, ')>> ', bitDepthColor, ',",", ', '(', Math.floor(numStepsColor*(vStart[2]+0.5)), '+phaseColor*', bRange, ')>> ', bitDepthColor, ', ")"].join("");\n'].join(''); break; case 'alpha': var relRange = Math.floor(attrValue-vStart); absRange = Math.abs(relRange); relPhase = Math.round((1 << bitDepth) / absRange); codeLine = ['this.', anim.el.uniqueID, 'alpha.opacity=(', numSteps*(vStart+0.5), '+phase*', relRange, ') >> ', bitDepth, ';\n'].join(''); break; case 'gradient': attrValue = [ this.__castColor(attrValue[0]), this.__castColor(attrValue[1]) ]; var rRange = Math.floor(attrValue[0][0] - vStart[0][0]); var gRange = Math.floor(attrValue[0][1] - vStart[0][1]); var bRange = Math.floor(attrValue[0][2] - vStart[0][2]); absRange = Math.max(Math.abs(rRange), Math.abs(gRange), Math.abs(bRange)); relPhase = Math.ceil((1 << bitDepthColor) / absRange) << (bitDepth - bitDepthColor); codeLine = ['this.', anim.el.uniqueID, 'gradient.startColorStr=', '((', vStart[0][0], '+phase*', rRange, ') << 16) | ', '((', vStart[0][1], '+phase*', gRange, ') << 8) | ', ' (', vStart[0][2], '+phase*', bRange, ');\n'].join(''); break; case 'scrollTop': case 'scrollLeft': var relRange = Math.floor(attrValue-vStart); absRange = Math.abs(relRange); relPhase = Math.ceil((1 << bitDepth) / absRange); codeLine = ['this.', anim.el.uniqueID, 'el.', attrName, '=(', numSteps*(vStart+0.5), '+phase*', relRange, ') >> ', bitDepth, ';\n'].join(''); break; case 'clip': var lRange = attrValue[0] - vStart[0]; var tRange = attrValue[1] - vStart[1]; var wRange = attrValue[2] - vStart[2]; var hRange = attrValue[3] - vStart[3]; absRange = Math.max(Math.abs(lRange), Math.abs(tRange), Math.abs(wRange), Math.abs(hRange)); relPhase = Math.ceil((1 << bitDepth) / absRange); codeLine = ['this.', anim.el.uniqueID, 'elStyle.clip=["rect(", ', '((', numSteps*(vStart[0]+0.5), ' + phase*', lRange, ')>> ', bitDepth, '), " " + ', '((', numSteps*(vStart[1]+0.5), ' + phase*', tRange, ')>> ', bitDepth, '), " " + ', '((', numSteps*(vStart[2]+0.5), ' + phase*', wRange, ')>> ', bitDepth, '), " " + ', '((', numSteps*(vStart[3]+0.5), ' + phase*', hRange, ')>> ', bitDepth, '), ")"].join("");\n'].join(''); break; } // No use to store this code if does nothing. if (absRange == 0) continue; // Store in codeByRange array. if (!codeByRange[relPhase]) codeByRange[relPhase] = [] codeByRange[relPhase].push(codeLine); } } var sortedIndexes = []; for (var relPhase in codeByRange) sortedIndexes.push(relPhase); sortedIndexes.sort(function (a, b) { return a - b; }); for (var i = 0; i < sortedIndexes.length; i++) { this["prevRenderPhase" + sortedIndexes[i]] = 0; if (sortedIndexes[i] > 1) { code.push( "if (tPhase >= 1 || phase - this.prevRenderPhase", sortedIndexes[i], " >= ", sortedIndexes[i], "){\n" ); } code.push(codeByRange[sortedIndexes[i]].join("")); if (sortedIndexes[i] > 1) code.push("this.prevRenderPhase", sortedIndexes[i], "=phase;\n", "}\n"); } // Create function //window.open().document.write('<pre>' + code.join('') + '</pre>'); this.__run = Function('t', code.join('')); if (typeof(profiler) != 'undefined') profiler.wrapFunction(this, "__run", "Animator"); if (typeof(shredder) != 'undefined') { shredder.extend(this); this.setRunMode(shredder.RUN_ONCE_REQUIRED); } else { var me = this; this.stop = function() { this.stopped = true; }; this.start = function() { this.stopped = false; var me = this; setTimeout(function(){ me.runAlone(); }, 0); }; } this.start(); } Animator.prototype = { profiles: { 0:'tPhase', 1:'tPhase*tPhase', 2:'(2 - tPhase)*tPhase', 3:'(1 - Math.cos(' + Math.PI + ' * tPhase) / 2.0', 4:'(tPhase < 0.5 ? Math.exp(3*Math.log(tPhase*2))/2 : 1-Math.exp(3*Math.log((1-tPhase)*2))/2)' }, uid:1, __wait: function(t) { if (t >= this.tStart) this.run = this.__run; }, run: function(t) { this.tStart = +new Date() + this.delay; this.tStop = this.tStart + this.duration; this.tPrev = this.tStart; if (t >= this.tStart) this.run = this.__run; else this.run = this.__wait; }, finish: function(t) { if (this.finished) return; this.finished = true; if (this.modifiers.removeAfterwards || this.modifiers.finishAlways) { for (var i=0; i<this.anims.length; i++) { var anim = this.anims[i]; for (var attrName in anim.targetState) { switch (attrName) { case 'alpha': // if (this.modifiers.finishAlways) // break; case 'gradient': // if (this.modifiers.finishAlways) // break; case 'scrollTop': case 'scrollLeft': if (this.modifiers.finishAlways) anim.el[attrName] = anim.targetState[attrName]; break; default: if (this.modifiers.finishAlways) anim.el[this.styleCollectionName][attrName] = anim.targetState[attrName]; if (this.modifiers.removeAfterwards) anim.el[this.styleCollectionName][attrName] = null; } } } } if (this.modifiers.endCode) this.modifiers.endCode(this.anims); this.stop(); }, cnt:1, runAlone: function() { //window.status = this.cnt++; this.run(+new Date()); if (!this.stopped) { var me = this; setTimeout(function(){ me.runAlone(); }, 0); } }, __colors: { "aqua":"#00FFFF","azure":"#F0FFFF","beige":"#F5F5DC", "black":"#000000","blue":"#0000FF","brown":"#A52A2A", "cyan":"#00FFFF","darkblue":"#00008B","darkcyan":"#008B8B", "darkgray":"#A9A9A9","darkgreen":"#006400","darkred":"#8B0000", "fuchsia":"#FF00FF","gold":"#FFD700","gray":"#808080", "green":"#008000","indigo":"#4B0082","lightblue":"#ADD8E6", "lightcyan":"#E0FFFF","lightgreen":"#90EE90","lightgrey":"#D3D3D3", "lightyellow":"#FFFFE0","lime":"#00FF00","magenta":"#FF00FF", "maroon":"#800000","navy":"#000080","orange":"#FFA500", "pink":"#FFC0CB","purple":"#800080","red":"#FF0000", "silver":"#C0C0C0","steelblue":"#4682B4","turquoise":"#40E0D0", "violet":"#EE82EE","white":"#FFFFFF","yellow":"#FFFF00" }, __castColor: function(c) { c = this.__colors[c] || c; if (typeof(c) == 'object') return c; if (c.indexOf('#') == 0) return [ parseInt(c.substring(1, 3), 16), parseInt(c.substring(3, 5), 16), parseInt(c.substring(5, 7), 16) ]; if (c.indexOf('rgb(') == 0) { var cs = c.substring(4, c.length - 1).split(','); return [ parseInt(cs[0]), parseInt(cs[1]), parseInt(cs[2]) ]; } return null; }, getCurrentStyleAttribute: function(el, attrName) { return this.getAttribute(el, 'currentStyle', attrName); }, getStyleAttribute: function(el, attrName) { return this.getAttribute(el, 'currentStyle', attrName); switch (attrName) { case 'top': case 'right': case 'bottom': case 'left': case 'MozOpacity': case 'width': case 'height': return parseInt(el.style[attrName]); break; case 'scrollTop': case 'scrollLeft': return el[attrName]; break; case 'clip': return [ parseInt(el.style.clipTop), parseInt(el.style.clipRight), parseInt(el.style.clipBottom), parseInt(el.style.clipLeft) ]; break; case 'alpha': return el.filters.item("DXImageTransform.Microsoft.Alpha").opacity; break; case 'gradient': return [ el.filters.item("DXImageTransform.Microsoft.Gradient").startColorStr, el.filters.item("DXImageTransform.Microsoft.Gradient").endColorStr ]; break; case 'color': case 'backgroundColor': case 'borderTopColor': case 'borderRightColor': case 'borderBottomColor': case 'borderLeftColor': return this.__castColor(el.style[attrName]); break; } }, getRuntimeStyleAttribute: function(el, attrName) { return this.getAttribute(el, 'runtimeStyle', attrName); }, getAttribute: function(el, styleName, attrName) { switch (attrName) { case 'top': case 'right': case 'bottom': case 'left': case 'MozOpacity': if (!document.defaultView) { var v = parseInt(el[styleName][attrName]); if (isNaN(v)) return 0 else return v; } else return parseInt(document.defaultView.getComputedStyle(el, "").getPropertyValue(attrNameMozilla)); break; case 'width': return el.offsetWidth; break; case 'height': return el.offsetHeight; break; case 'scrollTop': case 'scrollLeft': return el[attrName]; break; case 'clip': if (!document.defaultView) return [ parseInt(el[styleName].clipTop), parseInt(el[styleName].clipRight), parseInt(el[styleName].clipBottom), parseInt(el[styleName].clipLeft) ]; else return [ parseInt(document.defaultView.getComputedStyle(el, "").getPropertyValue('clip-top')), parseInt(document.defaultView.getComputedStyle(el, "").getPropertyValue('clip-right')), parseInt(document.defaultView.getComputedStyle(el, "").getPropertyValue('clip-bottom')), parseInt(document.defaultView.getComputedStyle(el, "").getPropertyValue('clip-left')) ]; break; case 'alpha': return el.filters.item("DXImageTransform.Microsoft.Alpha").opacity; break; case 'gradient': debugger; return [ el.filters.item("DXImageTransform.Microsoft.Gradient").startColorStr, el.filters.item("DXImageTransform.Microsoft.Gradient").endColorStr ]; break; case 'color': case 'backgroundColor': case 'borderTopColor': case 'borderRightColor': case 'borderBottomColor': case 'borderLeftColor': if (!document.defaultView) return this.__castColor(el[styleName][attrName]); else return this.__castColor(document.defaultView.getComputedStyle(el, "").getPropertyValue(attrNameMozilla)); break; } }, getCalculatedProperty:function(el, prop) { switch(prop) { case 'visibility': //TODO // geef opacity terug!!!!!! while (el.currentStyle[prop] == 'inherit') { if (el.nodeName.toLowerCase() == 'body') return 'visible'; else el = el.parentNode; } return el.currentStyle[prop]; case 'display': return el.currentStyle[prop]; case 'opacity': return this.__getOpacity(el); case "width": return el.offsetWidth; case "height": return el.offsetHeight; case "scrollTop": case "scrollLeft": return el[prop]; case "color": case "backgroundColor": case "borderColor": return this.__getCalculatedColor(el, prop); default: var val = parseInt(el.currentStyle[prop]); if (isNaN(val)) return 0; else return val; } }, __getCalculatedColor:function(el, prop) { v = el.currentStyle[prop]; for (var el2 = el; (v == 'transparent') && el2; el2 = el2.parentNode) v = el2.currentStyle[prop]; v = this.__colors[v.toLowerCase()] || v; if (v.indexOf('rgb(') == 0) { cs = v.substring(4, v.length-1).split(','); v = this.__RGBtoHex(parseInt(cs[0]), parseInt(cs[1]), parseInt(cs[2])); } if (v.charAt(0) != "#") v = "#ffffff"; return v; } }; function Modifiers() { this.delay = 0; this.duration = 300; this.profile = this.SLOWFASTSLOW; this.useRuntimeStyle = false; this.removeAfterwards = false; this.finishAlways = false; this.endCode = null; } Modifiers.prototype = { LINEAR:0, ACCERATING:1, DECELERATING:2, NORMAL:3, SLOWFASTSLOW:4 }; var eventCenter = { debugNextEvent: false, lastClickEvent:null, activate: function() { this.active = true; }, deactivate: function() { this.active = false; }, __attachedEvents:[], attachEvent: function(el, evtType, hnd, isPublic) { // for IE if (el.attachEvent) { var type = evtType.toLowerCase(); var hndWrapper = function(evt) { var result = hnd.call(el, evt); if (result === false) { evt.returnValue = false; evt.cancelBubble = true; } else if (isPublic === true && window.parentDoc) { //debugger; //alert(element.ownerDocument.getElementById('pe' + evtType.substring(2).toLowerCase())); var evtSpawner = 'pe' + evtType.substring(2).toLowerCase(); var evtObject = parentDoc.createEventObject(evt); parentDoc.getElementById(evtSpawner).fire(evtObject); if (evt.keyCode != evtObject.keyCode) { evt.keyCode = evtObject.keyCode; }; //} catch (e) {}; evt.cancelBubble = evtObject.cancelBubble; result = evt.returnValue = evtObject.returnValue; } return result; }; el.attachEvent(type, hndWrapper); } // for Mozilla / Netscape else if (el.addEventListener) { var type = evtType.substring(2).toLowerCase(); var hndWrapper = function(nnevent) { var evt = { type:type, srcElement:nnevent.target, currentTarget:nnevent.currentTarget, x:nnevent.clientX, y:nnevent.clientY, clientX:nnevent.clientX, clientY:nnevent.clientY, keyCode:nnevent.keyCode, charCode:nnevent.charCode, button:{'0':1,'1':4,'2':2}[nnevent.button], ctrlKey:nnevent.ctrlKey, shiftKey:nnevent.shiftKey, altKey:nnevent.altKey, fromElement:nnevent.relatedTarget, toElement:nnevent.relatedTarget, nnevent:nnevent }; window.event = evt; var result = hnd.call(el, evt); if (result === false) { nnevent.preventDefault(); nnevent.stopPropagation(); } if (evt.cancelBubble) { nnevent.stopPropagation(); } return result; }; el.addEventListener(type, hndWrapper, false); } } }; var selection = { range: null, curCol: 0, curX: 0, curLine: null, cursorVisible: false, rangeSelectionVisible: false, imeEnabled: false, setRange: function(rng, className) { this.range = rng; this.show(className); }, getRange: function() { return this.range.duplicate(); }, show: function(className) { // codeArea.focus(); this.curCol = this.range.endCol; if (this.curLine != this.range.endLine) { this.curLine = this.range.endLine; this.curLineNumber = this.curLine.getLineNumber(); } this.curClassName = className; this.positionCursor(); if (this.range.isCollapsed()) { this.showCursor(); if (this.imeEnabled) this.curLine.showIMEInput(this.curCol); } else { this.hideCursor(); var oldSelection = this.rangeSelectionVisible; this.rangeSelectionVisible = this.range.duplicate(); this.rangeSelectionVisible.drawSelection(className, oldSelection); } }, hide: function() { if (this.rangeSelectionVisible) { this.rangeSelectionVisible.hideSelection(); this.rangeSelectionVisible = false; } }, replaceContent: function(s) { this.hide(); this.range.replaceContent(s); this.show(); }, updateFromBrowser: function(isReverse) { var rng = crossBrowser.getSelectionRange(); if (!rng) return; var cRng = new CodeRange(); cRng.moveToTextRange(rng, isReverse); this.setRange(cRng); }, moveCursorUp: function(modifiers) { this._moveCursorUp(modifiers); this.show(); }, _moveCursorUp: function(modifiers) { return this._moveCursorLine(this.curLine.prevLine, this.curLineNumber - 1, modifiers.shiftKey); }, moveCursorDown: function(modifiers) { this._moveCursorDown(modifiers); this.show(); }, _moveCursorDown: function(modifiers) { return this._moveCursorLine(this.curLine.nextLine, this.curLineNumber + 1, modifiers.shiftKey); }, moveCursorLeft: function(modifiers) { this._moveCursorLeft(modifiers); this.show(); }, _moveCursorLeft: function(modifiers) { var chars = this.curLine.getValue(); var l = chars.length; if (this.curCol > l) this.curCol = l; if (this.curCol == 0) { if (!this._moveCursorUp(modifiers)) return false; chars = this.curLine.getValue(); this.curCol = chars.length; } else { this.curCol--; } if (modifiers.ctrlKey) { if (chars.length != 0 && this.curCol == chars.length) this.curCol--; var n = this.curCol; while (n) { var pos = this.curLine.getNextCtrlStop(n); if (pos <= this.curCol) break; n--; } this.curCol = n ? pos : 0; } return this._moveCursorCol(this.curCol, modifiers.shiftKey); }, moveCursorRight: function(modifiers) { this._moveCursorRight(modifiers); this.show(); }, _moveCursorRight: function(modifiers) { if (this.curCol >= this.curLine.getLength()) { if (modifiers.stayOnLine || !this._moveCursorDown(modifiers)) return false; this.curCol = 0; } else { this.curCol++; } if (modifiers.ctrlKey) this.curCol = this.curLine.getNextCtrlStop(this.curCol||1); return this._moveCursorCol(this.curCol, modifiers.shiftKey); }, moveCursorHome: function(modifiers) { this._moveCursorHome(modifiers); this.show(); }, _moveCursorHome: function(modifiers) { if (modifiers.ctrlKey) this._moveCursorLine(codeArea.BOF.nextLine, 1, modifiers.shiftKey); var homeCol = this.curLine.getSmartHomeCol(); if (homeCol == this.curCol) homeCol = 0; return this._moveCursorCol(homeCol, modifiers.shiftKey); }, moveCursorEnd: function(modifiers) { this._moveCursorEnd(modifiers); this.show(); }, _moveCursorEnd: function(modifiers) { if (modifiers.ctrlKey) this._moveCursorLine(codeArea.EOF.prevLine, this.lineCount, modifiers.shiftKey); var endCol = Infinity; if (endCol == this.curCol) endCol = this.curLine.getSmartEndCol(); return this._moveCursorCol(endCol, modifiers.shiftKey); }, moveCursorPageUp: function(modifiers) { this._moveCursorPageUp(modifiers); this.show(); }, _moveCursorPageUp: function(modifiers) { var lines = Math.round(comp.body.clientHeight / codeArea.oneCharHeight); // codeArea.scrollIntoViewY(comp.body.scrollTop - lines * codeArea.oneCharHeight, 0); comp.body.scrollTop -= lines * codeArea.oneCharHeight; for (; lines; lines--) this._moveCursorUp(modifiers); }, moveCursorPageDown: function(modifiers) { this._moveCursorPageDown(modifiers); this.show(); }, _moveCursorPageDown: function(modifiers) { var lines = Math.round(comp.body.clientHeight / codeArea.oneCharHeight); comp.body.scrollTop += lines * codeArea.oneCharHeight; // codeArea.scrollIntoViewY(comp.body.scrollTop + lines * codeArea.oneCharHeight, 0); for (; lines; lines--) this._moveCursorDown(modifiers); }, moveCursorToPoint: function(clientX, clientY, endOnly) { var line = codeArea.getLineFromClientY(clientY); var col = codeArea.getColFromClientX(clientX, line); this._moveCursorLine(line, line.getLineNumber(), endOnly); this._moveCursorCol(col, endOnly); this.show(); }, _moveCursorLine: function(line, lineNumber, endOnly) { if (line == codeArea.BOF || line == codeArea.EOF) return false; // update col for non fixed width characters if (this.curX) { var col = line.getColFromX(this.curX); if (col != this.curCol) { this.curCol = col; this.range.moveCol(col, endOnly); } } this.curLine = line; this.curLineNumber = lineNumber; this.range.moveLine(this.curLine, endOnly); this.showCurPos(); return true; }, _moveCursorCol: function(col, endOnly) { this.curCol = col; this.curX = this.curLine.getXFromCol(col); this.range.moveCol(this.curCol, endOnly); this.showCurPos(); return true; }, selectAll: function() { this._moveCursorHome({ctrlKey:true}); this._moveCursorEnd({ctrlKey:true,shiftKey:true}); this.show(); }, indent: function() { this.range.indent(); this.show(); }, unindent: function() { this.range.unindent(); this.show(); }, showCurPos: function() { // all code for debugging only var col = this.curLine.getLength()+1; if (this.curCol+1 <= col) col = this.curCol+1; else col = ">" + col; //window.status = this.curLineNumber + " " + col; }, positionCursor: function() { codeArea.positionCursorLine(this.curLine); codeArea.positionCursorCol(this.range.isLineRange ? 0 : this.curCol, this.curLine); }, updateCursor: function() { // reset blinking this.cursorBlinkState = 1; this.doCursorBlink(); }, showCursor: function() { this.updateCursor(); if (this.rangeSelectionVisible) { this.rangeSelectionVisible.hideSelection(); this.rangeSelectionVisible = false; } this.cursorVisible = true; this.showCursorState(); }, hideCursor: function() { this.cursorVisible = false; this.showCursorState(); }, showCursorState: function() { codeArea.cursor.style.display = this.cursorVisible && codeArea.hasFocus && !codeArea.readOnly ? 'block' : 'none'; }, doCursorBlink: function() { // no this clearTimeout(selection.doCursorBlinkTO); codeArea.cursor.style.visibility = selection.cursorBlinkState ? "visible" : "hidden"; selection.cursorBlinkState = 1 - selection.cursorBlinkState; /*var height = 1.2 * Math.min(1, Math.max(0, Math.sin(new Date / 500 * Math.PI))); codeArea.cursor.style.height = height + "em"; codeArea.cursor.style.marginTop = (1.2 - height) + "em"; var opacity = Math.min(1, Math.max(0, Math.sin(new Date / 500 * Math.PI))); codeArea.cursor.style.opacity = opacity;*/ selection.doCursorBlinkTO = setTimeout(selection.doCursorBlink, 500); }, switchIMEInput: function() { this.imeEnabled = !this.imeEnabled; if (this.imeEnabled) this.curLine.showIMEInput(this.curCol); return false; } }; function Action(o) { this.auxAction = o.auxAction; this.undoAction = o.undoAction; this.canCombine = o.canCombine; this._perform = o._perform; this.isPerformValid = o.isPerformValid; var me = this; this.perform = function() { if (!me.auxAction) { if (codeArea.readOnly) return; if (!me.undoAction) undoStack.addState(me); } return me._perform.apply(me, arguments); }; }; Action.prototype.isEnabled = function() { return (!this.isPerformValid || this.isPerformValid()) && (this.auxAction || !codeArea.readOnly); }; var actions = { typing: new Action({ canCombine: true, _perform: function(chr) { if (codeArea.overWrite && selection.range.isCollapsed()) selection._moveCursorRight({shiftKey:true, stayOnLine:true}); selection.replaceContent(chr); } }), deleteKey: new Action({ canCombine: true, _perform: function(evt) { if (selection.range.isCollapsed()) selection._moveCursorRight({shiftKey:true, ctrlKey: evt.ctrlKey, altKey: evt.altKey}); selection.replaceContent(""); } }), backspace: new Action({ canCombine: true, _perform: function(evt) { if (selection.range.isCollapsed()) selection._moveCursorLeft({shiftKey:true, ctrlKey: evt.ctrlKey, altKey: evt.altKey}); selection.replaceContent(""); } }), newLine: new Action({ _perform: function() { selection.replaceContent("\n"); } }), indent: new Action({ _perform: function() { selection.indent(); } }), unindent: new Action({ _perform: function() { selection.unindent(); } }), cut: new Action({ _perform: function() { actions.copy._perform(); selection.replaceContent(""); if (window.clipboardData) return false; // hide cursor after cut setTimeout(function () { codeArea.focus(); }, 0); // let Ctrl-X pass through return true; } }), copy: new Action({ auxAction: true, _perform: function() { var value = selection.getRange().getContent(); if (window.clipboardData) { window.clipboardData.setData("Text", value); return false; } // put the value in a textarea codeArea.clipboard.focus(); codeArea.clipboard.value = value; codeArea.clipboard.setSelectionRange(0, codeArea.clipboard.textLength); setTimeout(function () { codeArea.focus(); }, 0); // let Ctrl-C pass through return true; } }), paste: new Action({ _perform: function() { if (window.clipboardData) { var text = window.clipboardData.getData("Text"); text = text.replace(/\r\n?/g, '\n'); selection.replaceContent(text); return false; } // get the value from the textarea codeArea.clipboard.readOnly = false; codeArea.clipboard.style.visibility = "visible"; codeArea.clipboard.focus(); codeArea.clipboard.style.visibility = "hidden"; setTimeout(function () { codeArea.clipboard.readOnly = true; codeArea.clipboard.setSelectionRange(0, codeArea.clipboard.textLength); var text = codeArea.clipboard.value; text = text.replace(/\r\n?/g, '\n'); selection.replaceContent(text); codeArea.focus(); }, 0); // let Ctrl-V pass through return true; } }), undo: new Action({ undoAction: true, _perform: function() { undoStack.undo(); // Don't pass Ctrl-Z return false; }, isPerformValid: function() { return codeArea.canUndo; } }), redo: new Action({ undoAction: true, _perform: function() { undoStack.redo(); // Don't pass Ctrl-Y return false; }, isPerformValid: function() { return codeArea.canRedo; } }) }; function Line(nextLine, value) { this.id = "l" + Line.idCounter++; if (codeArea.isInitial) { this._value = value || ""; this.init(nextLine, value || ""); } else { undoStack.currentState.addCreatedLine(this); this.init(nextLine, " "); this.setValue(value || ""); } } Line.idCounter = 0; Line.INIT_HTML = "<font>\u00a0</font><span>\u00a0</span>\u00a0"; Line.prototype.init = function(nextLine, value) { codeArea.lines[this.id] = this; //if (Line.idCounter < 300) codeArea.updateLineCount(1); this.prevLine = nextLine.prevLine; nextLine.prevLine.nextLine = this; this.nextLine = nextLine; nextLine.prevLine = this; this.createHTML(nextLine, value); }; Line.prototype.createHTML = function(nextLine, value) { var div = document.createElement("div"); div.id = this.id; this.div = div; this.div.innerHTML = Line.INIT_HTML; codeArea.canvas.insertBefore(div, nextLine.div); this._setValue(value); //this.selectionDiv = codeArea.selectionPlane.appendChild(document.createElement("div")); //this.selectionClassName = ""; }; Line.prototype.del = function() { this._del(); undoStack.currentState.addDeletedLine(this); }; Line.prototype._del = function() { delete codeArea.lines[this.id]; codeArea.updateLineCount(-1); this.prevLine.nextLine = this.nextLine; this.nextLine.prevLine = this.prevLine; /*this.div.style.position = 'fixed'; this.div.style.top = "-1000px"; this.div.style.left = "-1000px";*/ codeArea.canvas.removeChild(this.div); delete this.div; }; Line.prototype.undel = function() { this.init(this.nextLine, this._value); }; Line.prototype.getValue = function() { return this._value; }; Line.prototype.setValue = function(v) { undoStack.currentState.addChangeValue({ line: this, oldValue: this._value, newValue: v }); return this._setValue(v); }; Line.prototype._setValue = function(v) { this._value = v; this.selectionStartCol = -1; this.div.firstChild.firstChild.nodeValue = v.replace(/([\s\u00a0]*)(.*)/, "$1"); this.div.firstChild.nextSibling.firstChild.nodeValue = v.replace(/([\s\u00a0]*)(.*)/, "$2"); //this.div.innerText = v; //this.div.innerHTML = v.replace(/&/g,'&').replace(/</g, '<').replace(/ /g, '\u00a0').replace(/([\s\u00a0]*)(.*)/, "<font>$1</font><span>$2</span>\u00a0"); if (!codeArea.isInitial) this.calculateGlyphWidths(); return v; }; Line.prototype.getLength = function() { return this._value.length; }; Line.prototype.getIndentSize = function(defaultToLength) { var m = this._value.match(/^(\s*)\S/); if (!m) // empty line return defaultToLength ? this.getLength() : null; return m[1].length; }; Line.prototype.getSmartHomeCol = function() { var homeCol = this.getIndentSize(); if (homeCol === null) homeCol = Math.min(this.getLength(), this.prevLine.getSmartHomeCol()); return homeCol; }; Line.prototype.getSmartEndCol = function() { var m = this._value.match(/^(.*\S)\s*$/); if (!m) // empty line return Math.min(this.getLength(), this.prevLine.getSmartHomeCol()); return m[1].length; }; Line.prototype.getNextCtrlStop = function(start) { var match = this._value.match(new RegExp(".{" + start + "}\\b\\s*")); return match ? match.index + match[0].length : this._value.length; }; Line.prototype.findNext = function(res, start) { var re = res[0]; re.lastIndex = start; var m = re.exec(this._value); return this.handlePartialFind(m, res); }; Line.prototype.findPrevious = function(res, start) { var re = res[0]; re.lastindex = 0; var m; for (var testM; (testM = re.exec(this._value)) && testM.index <= start; re.lastIndex = testM.index + 1) m = testM; return this.handlePartialFind(m, res); }; Line.prototype.handlePartialFind = function(m, res) { if (!m) return false; if (res.length == 1) return new CodeRange().moveToLine(this, m.index, m[0].length); var followingRange = this.nextLine.findNext(res.slice(1), 0); if (!followingRange) return false; followingRange.startLine = this; followingRange.startCol = m.index; return followingRange; } // delete from startCol to endCol // create new lines for \n in values Line.prototype.replaceContent = function(s, startCol, endCol) { if (!endCol && endCol!=0) endCol = this.getLength(); startCol = startCol || 0; var newVal = this._value.substr(0, startCol) + s; var lines = newVal.split("\n"); var lastIndex = lines.length - 1; var cursorCol = lines[lastIndex].length; lines[lastIndex] += this._value.substr(endCol); var lastLine = this; // possibly updated later if (lastIndex > 0) // multiple lines pasted { // calculate indentation insertion var startIndentSize = this.getIndentSize(true); var indentInsertionCount = Math.min(startCol, startIndentSize); var indentInsertionValue = this._value.substr(0, indentInsertionCount); cursorCol += indentInsertionCount; // create new lines for (var i=1; i<lines.length; i++) lastLine = new Line(lastLine.nextLine, indentInsertionValue + lines[i]); }; this.setValue(lines[0]); return { line: lastLine, col: cursorCol }; }; Line.prototype.getLineNumber = function() { var l = this; var nr = 0; while (l != codeArea.BOF) { l = l.prevLine; nr++; } return nr; }; Line.prototype.isPreceding = function(otherLine) { return crossBrowser.isPreceding(this.div, otherLine.div); }; Line.prototype.addClass = function(className) { crossBrowser.addClass(this.div, className); }; Line.prototype.removeClass = function(className) { crossBrowser.removeClass(this.div, className); }; Line.prototype.drawSelection = function(startCol, endCol, useElement, indentRemovalRE) { var className = ""; if (endCol > this.getLength()) { endCol = this.getLength() + 0.5; className = "linebreak-selected"; } if (indentRemovalRE) { var m = this._value.match(indentRemovalRE); if (startCol < m[0].length) startCol = m[0].length; } if (startCol > endCol) return; /* if (className != this.selectionClassName) { this.selectionDiv.className = className; this.selectionClassName = className; } if (this.selectionHidden !== false) { if (this.selectionHidden) this.selectionDiv.style.display = "block"; this.selectionHidden = false; this.selectionDiv.style.top = this.div.offsetTop; this.selectionDiv.style.height = codeArea.oneCharHeight; } if (this.selectionStartCol != startCol || this.selectionEndCol != endCol) { this.selectionDiv.style.width = this.getXFromCol(endCol) - this.getXFromCol(startCol); this.selectionDiv.style.left = this.getXFromCol(startCol); this.selectionStartCol = startCol; this.selectionEndCol = endCol; }*/ if (useElement == null) { if (this.selectionHidden !== false) this.addClass("selected"); if (startCol != this.selectionStartCol) { this.selectionStartCol = startCol; var indentX = this.getXFromCol(this.getIndentSize(true)); var startX = this.getXFromCol(startCol); var extraSel = (indentX - startX) + 'px'; var span = this.div.firstChild; span.style.borderRightWidth = extraSel; span.style.marginLeft = "-" + extraSel; } this.selectionHidden = false; } else { var width = this.getXFromCol(endCol) - this.getXFromCol(startCol); if (width > 0) { useElement.style.display = "block"; useElement.style.top = this.div.offsetTop; useElement.style.height = codeArea.oneCharHeight; useElement.style.width = width; useElement.style.left = this.getXFromCol(startCol); useElement.className = className; } else useElement.style.display = "none"; this.hideSelection(); } }; Line.prototype.hideSelection = function() { if (!this.selectionHidden) { //this.selectionDiv.style.display = "none"; this.removeClass("selected"); this.selectionHidden = true; var span = this.div.firstChild; span.style.borderRightWidth = span.style.marginLeft = "0px"; this.selectionStartCol = -1; } }; Line.prototype.scrollIntoView = function() { codeArea.scrollIntoViewX(0, this.getXFromCol(this.getLength())); codeArea.scrollIntoViewYAnimated(this.div.offsetTop, codeArea.oneCharHeight); }; var hasTabOrNonAscii = /[\t\u0100-\uffff]/; Line.prototype.calculateGlyphWidths = function() { this.totalWidth = []; this.isSuspicious = hasTabOrNonAscii.test(this._value); if (!this.isSuspicious) return; /*var rng = crossBrowser.createRange(); rng.setEndByChars(this.div, 0); rng.setStartByChars(this.div, 0); for (var i=0; i <= this._value.length; i++) { rng.setEndByChars(this.div, i); this.totalWidth[i] = rng.getBoundingWidth() / codeArea.oneCharWidth; }*/ var span = document.createElement("span"); codeArea.cursors.insertBefore(span, codeArea.cursors.firstChild); span.innerText = '\u00A0'; for (var i=0; i <= this._value.length; i++) { span.firstChild.nodeValue = this._value.substr(0, i); this.totalWidth[i] = span.offsetWidth / codeArea.oneCharWidth; } codeArea.cursors.removeChild(span); this.totalWidth[i - 0.5] = this.totalWidth[i - 1] + 0.5; }; Line.prototype.getColFromX = function(x) { if (!this.totalWidth) this.calculateGlyphWidths(); var col = x / codeArea.oneCharWidth; if (this.isSuspicious) { var minDist = Infinity; var length = this.getLength(); for (var i=0; i<length; i++) { var dist = Math.abs(col - this.totalWidth[i]); if (dist > minDist) return i-1; minDist = dist; } return length; } else { return Math.min(this.getLength()+0.5, Math.max(0, Math.round(col))); } }; Line.prototype.getXFromCol = function(col) { if (!this.totalWidth) this.calculateGlyphWidths(); col = Math.min(col, this.getLength()); return (this.isSuspicious ? this.totalWidth[col] : col) * codeArea.oneCharWidth; }; Line.prototype.showIMEInput = function(col) { this.div.innerHTML = "<input>"; var input = this.div.firstChild; input.readOnly = codeArea.readOnly; input.value = this._value; input.focus(); input.style.width = codeArea.canvas.offsetWidth + 'px'; input.style.imeMode = "active"; eventCenter.attachEvent(input, "onblur", onIMEInputBlur); eventCenter.attachEvent(input, "onkeydown", onIMEInputKeyDown); eventCenter.attachEvent(input, "onkeypress", onIMEInputKeyPress); crossBrowser.setInputSelectionRange(input, col, col); }; Line.prototype.hideIMEInput = function(imeInputValue) { this.div.innerHTML = Line.INIT_HTML; this.setValue(imeInputValue); }; Line.prototype.toString = function() { return "Line " + this.getLineNumber() + ": " + this.getValue(); }; function CodeRange() { this.endLine = this.startLine = codeArea.BOF.nextLine; this.endCol = this.startCol = 0; }; CodeRange.MOVE_END_ONLY = true; CodeRange.prototype.equals = function(cr) { return this.startCol == cr.startCol && this.endCol == cr.endCol && this.startLine == cr.startLine && this.endLine == cr.endLine; }; CodeRange.prototype.isCollapsed = function() { return this.startLine == this.endLine && this.endCol == this.startCol; }; CodeRange.prototype.collapse = function(toStart) { if (toStart) { this.endLine = this.startLine; this.endCol = this.startCol; } else { this.startLine = this.endLine; this.startCol = this.endCol; } return this; }; CodeRange.prototype.select = function(className) { selection.setRange(this, className); return this; }; // create range from start of line to end of line CodeRange.prototype.moveToLine = function(l, startCol, length) { this.endLine = this.startLine = l; if (isNaN(startCol)) { this.startCol = 0; this.endCol = Infinity; this.isLineRange = true; } else { this.startCol = startCol; this.endCol = startCol + (length || 0); } return this; }; CodeRange.prototype.moveToTextRange = function(rng, isReverse) { if (!rng.duplicate) return; var startPos = this.getPos(rng, true ^ isReverse); if (!startPos) return; var endPos = this.getPos(rng, false ^ isReverse); if (!endPos) return; this.startLine = startPos.line; this.startCol = startPos.col; this.endLine = endPos.line; this.endCol = endPos.col; return this; }; CodeRange.prototype.createTextRange = function() { var rng = crossBrowser.createRange(); rng.setEndByChars(this.endLine.div, this.endCol); rng.setStartByChars(this.startLine.div, this.startCol); return rng; }; CodeRange.prototype.getPos = function(rng, startOfRng) { rng = rng.duplicate(); rng.collapse(startOfRng); // find line div var parent = rng.getParentElement(); while (parent && parent.parentNode!=codeArea.canvas) parent = parent.parentNode; if (!parent) return; // find col rng.setStartByChars(parent, 0); return { line : codeArea.lines[parent.id], col : rng.getText().length }; }; // only change line values CodeRange.prototype.moveLine = function(line, endOnly) { this.endLine = line; if (!endOnly) { this.startLine = line; this.startCol = this.endCol; } return this; }; // only change col values CodeRange.prototype.moveCol = function(col, endOnly) { this.isLineRange = false; this.endCol = col; if (!endOnly) { this.startLine = this.endLine; this.startCol = col; } return this; }; CodeRange.prototype.duplicate = function() { var cr = new CodeRange(); cr.startLine = this.startLine; cr.endLine = this.endLine; cr.startCol = this.startCol; cr.endCol = this.endCol; cr.isLineRange = this.isLineRange; return cr; }; CodeRange.prototype.setStartBeforeEnd = function() { if (this.endLine.isPreceding(this.startLine) || (this.endLine == this.startLine && this.endCol < this.startCol)) { var l = this.endLine; this.endLine = this.startLine; this.startLine = l; var c = this.endCol; this.endCol = this.startCol; this.startCol = c; } return this; }; CodeRange.prototype.fixInfinitEnd = function() { if (this.endCol == Infinity) { if (this.startCol == Infinity && this.startLine == this.endLine) this.startCol = this.endCol = this.startLine.getLength(); else { if (this.endLine.nextLine == codeArea.EOF) { this.endCol = this.endLine.getLength(); } else { this.endCol = 0; this.endLine = this.endLine.nextLine; } } } return this; }; CodeRange.prototype.fixEmptyEnds = function() { if (!this.isCollapsed()) { if (this.startCol >= this.startLine.getLength()) { this.startCol = 0; this.startLine = this.startLine.nextLine; } if (this.endCol == 0) { this.endCol = Infinity; this.endLine = this.endLine.prevLine; } } return this; }; CodeRange.prototype.replaceContent = function(s) { this.setStartBeforeEnd(); this.fixInfinitEnd(); if (this.startLine == this.endLine) var newPos = this.startLine.replaceContent(s, this.startCol, this.endCol); else { // Remember text on the last line after the end of the selection. var extraFromLastLine = this.endLine.getValue().substr(this.endCol); // Remove all selected lines except the start line. var l = this.startLine; do { l = l.nextLine; l.del(); } while (l != this.endLine); // Insert new value. var newPos = this.startLine.replaceContent(s, this.startCol); // Add old text from last line newPos.line.setValue(newPos.line.getValue() + extraFromLastLine); } this.endLine = this.startLine = newPos.line; this.endCol = this.startCol = newPos.col; return this; }; CodeRange.prototype.getContent = function() { this.setStartBeforeEnd(); this.fixInfinitEnd(); if (this.startLine == this.endLine) return this.startLine.getValue().substring(this.startCol, this.endCol); else { // calculate indentation removal var startIndentSize = this.startLine.getIndentSize(true); var indentRemovalCount = Math.min(this.startCol, startIndentSize); var indentRemovalRE = new RegExp("^\\s{0,"+indentRemovalCount+"}"); var a = [this.startLine.getValue().substr(this.startCol)]; var l = this.startLine; do { l = l.nextLine; var v = l.getValue(); a.push(v.replace(indentRemovalRE, "")); } while (l != this.endLine); a[a.length-1] = a[a.length-1].substr(0, this.endCol - indentRemovalCount); return a.join("\n"); } }; CodeRange.prototype.indent = function() { this.setStartBeforeEnd(); this.fixEmptyEnds(); var indentInsertionValue = new Array(codeArea.settings.indentSize+1).join(" "); for (var l = this.startLine; l.prevLine != this.endLine; l = l.nextLine) l.setValue(indentInsertionValue + l.getValue()); if (!this.isCollapsed()) { this.startCol = 0; this.endCol = Infinity; } else { this.startCol += codeArea.settings.indentSize; this.endCol += codeArea.settings.indentSize; } return this; }; CodeRange.prototype.unindent = function() { this.setStartBeforeEnd(); this.fixEmptyEnds(); var indentRemovalRE = new RegExp("^\\s{0,"+codeArea.settings.indentSize+"}"); for (var l = this.startLine; l.prevLine != this.endLine; l = l.nextLine) l.setValue(l.getValue().replace(indentRemovalRE, "")); if (!this.isCollapsed()) { this.startCol = 0; this.endCol = Infinity; } else { // LAURENS: Make sure we never have a negative startCol or endCol. this.startCol = Math.max(0, this.startCol - codeArea.settings.indentSize); this.endCol = Math.max(0, this.endCol - codeArea.settings.indentSize); } return this; }; CodeRange.prototype.drawSelection = function(className, currentSelection) { codeArea.selectionPlane.className = className || ""; this.setStartBeforeEnd(); this.fixInfinitEnd(); // check select all if (this.startLine == codeArea.BOF.nextLine && this.startCol == 0 && this.endLine == codeArea.EOF.prevLine && this.endCol == this.endLine.getLength()) { if (currentSelection) currentSelection.hideSelection(); codeArea.canvas.className = "selectAll"; this.isSelectAll = true; return; } if (currentSelection) { if (currentSelection.isSelectAll) codeArea.canvas.className = ""; else { if (currentSelection.startLine.isPreceding(this.startLine)) for (var l = currentSelection.startLine; l != this.startLine; l = l.nextLine) l.hideSelection(); if (this.endLine.isPreceding(currentSelection.endLine)) for (var l = this.endLine; l != currentSelection.endLine; l = l.nextLine) l.nextLine.hideSelection(); } } if (this.startLine == this.endLine) { this.startLine.drawSelection(this.startCol, this.endCol, codeArea.startOfSelection); codeArea.endOfSelection.style.display = "none"; } else { // calculate indentation removal var startIndentSize = this.startLine.getIndentSize(true); var indentRemovalCount = Math.min(this.startCol, startIndentSize); var indentRemovalRE = new RegExp("^\\s{0,"+indentRemovalCount+"}"); this.startLine.drawSelection(this.startCol, Infinity, codeArea.startOfSelection); var l = this.startLine; while (l.nextLine != this.endLine) { l = l.nextLine; l.drawSelection(0, Infinity, null, indentRemovalRE); } this.endLine.drawSelection(0, this.endCol, codeArea.endOfSelection, indentRemovalRE); } return this; }; CodeRange.prototype.hideSelection = function() { // assuming start before end // this.setStartBeforeEnd(); if (this.isSelectAll) { codeArea.canvas.className = ""; this.isSelectAll = false; return; } codeArea.startOfSelection.style.display = "none"; codeArea.endOfSelection.style.display = "none"; var l = this.startLine; while (l != this.endLine) { l.hideSelection(); l = l.nextLine; } this.endLine.hideSelection(); return this; }; var undoStack = { // BOTTOM implements undoState where needed BOTTOM: { undo: function() { return false; }, addCreatedLine: function() {}, addDeletedLine: function() {}, addChangeValue: function() {}, combine: function() { return this; } }, TOP: { redo: function() { return false; } }, init: function() { this.currentState = this.BOTTOM; this.BOTTOM.nextState = this.TOP; this.BOTTOM.prevState = this.BOTTOM; this.TOP.prevState = this.BOTTOM; this.TOP.nextState = this.TOP; }, addState: function(action) { // try to combine the current state var lastCurrentState = this.currentState.combine(); this.currentState = new UndoState(action); lastCurrentState.nextState = this.currentState; this.currentState.prevState = lastCurrentState; // remove redo stack this.currentState.nextState = undoStack.TOP; codeArea.setProperty("canRedo", false); codeArea.setProperty("canUndo", true); }, undo: function() { // store current selection if (this.currentState.nextState == undoStack.TOP) this.currentState.nextState.selection = selection.getRange(); this.currentState = this.currentState.combine(); var result = this.currentState.undo(); codeArea.setProperty("canUndo", this.currentState != this.BOTTOM); codeArea.setProperty("canRedo", true); return result; }, redo: function() { var result = this.currentState.nextState.redo(); codeArea.setProperty("canUndo", true); codeArea.setProperty("canRedo", this.currentState.nextState != this.TOP); return result; } }; function UndoState(action) { this.action = action; this.canCombine = action.canCombine; this.selection = selection.getRange(); } UndoState.prototype.addCreatedLine = function(line) { // never combine line additions this.canCombine = false; if (!this.createdLines) this.createdLines = []; this.createdLines.push(line); }; UndoState.prototype.addDeletedLine = function(line) { // never combine line removals this.canCombine = false; if (!this.deletedLines) this.deletedLines = []; this.deletedLines.push(line); }; UndoState.prototype.addChangeValue = function(data) { if (!this.changedValues) this.changedValues = []; this.changedValues.push(data); }; UndoState.prototype.undo = function() { undoStack.currentState = this.prevState; if (this.deletedLines) for (var i=this.deletedLines.length-1; i>=0; i--) this.deletedLines[i].undel(); if (this.changedValues) for (var i=this.changedValues.length-1; i>=0; i--) { var data = this.changedValues[i]; data.line._setValue(data.oldValue); } if (this.createdLines) for (var i=this.createdLines.length-1; i>=0; i--) this.createdLines[i]._del(); this.selection.select(); }; UndoState.prototype.redo = function() { undoStack.currentState = this; if (this.createdLines) for (var i=this.createdLines.length-1; i>=0; i--) this.createdLines[i].undel(); if (this.changedValues) for (var i=this.changedValues.length-1; i>=0; i--) { var data = this.changedValues[i]; data.line._setValue(data.newValue); } if (this.deletedLines) for (var i=this.deletedLines.length-1; i>=0; i--) this.deletedLines[i]._del(); this.nextState.selection.select(); }; UndoState.prototype.combine = function() { if (!this.canCombine || !this.prevState.canCombine || this.action != this.prevState.action || !this.changedValues || !this.prevState.changedValues || this.changedValues.length != 1 || this.prevState.changedValues.length != 1 || this.changedValues[0].line != this.prevState.changedValues[0].line) return this; // combine with prevState var data = this.changedValues[0]; var prevData = this.prevState.changedValues[0]; if (prevData) prevData.newValue = data.newValue; else this.prevState.changedValues[0] = data; this.prevState.nextState = this.nextState; this.nextState.prevState = this.prevState; return this.prevState; }; var codeArea = { settings: { indentSize: 2 }, // BOF and EOF implement Line where needed (see also init) // BOF is the line before the first line BOF: { getIndentSize: function() { return 0; }, getSmartHomeCol: function() { return 0; }, div: null }, // EOF is the line after the last one EOF: { div: null, findNext: function() { return false; } }, lines: {}, lineCount: 0, lineNumberCount: 0, hasFocus: false, readOnly: true, handlers: {}, subscribedKeys: [], init: function() { undoStack.init(); this.leftMargin = comp.getElementById("left-margin"); this.canvas = comp.getElementById("canvas"); this.oneChar = comp.getElementById("one-char"); this.cursors = comp.getElementById("cursors"); this.cursor = comp.getElementById("cursor"); this.colCursor = comp.getElementById("col-cursor"); this.lineCursor = comp.getElementById("line-cursor"); this.lineCursorInMargin = comp.getElementById("line-cursor-in-margin"); this.selectionPlane = comp.getElementById("selection-plane"); this.startOfSelection = comp.getElementById("start-of-selection"); this.endOfSelection = comp.getElementById("end-of-selection"); this.clipboard = comp.getElementById("clipboard"); this.BOF.nextLine = this.EOF; this.EOF.prevLine = this.BOF; this.readLayoutMetrics(); this.setValue(""); this.updateLeftMargin(); setTimeout(this.checkFontSize, 200); }, setValue: function(s) { comp.body.removeChild(this.canvas); this.removeAllLines(); s = s.replace(/\r/g, ''); /*for (var i = 0; i<3; i++) s += s;*/ this.isInitial = true; new Line(this.EOF).replaceContent(s); this.isInitial = false; comp.body.insertBefore(this.canvas, null); new CodeRange().select(); }, getValue: function() { var all = new CodeRange(); all.moveLine(this.EOF.prevLine, CodeRange.MOVE_END_ONLY); all.moveCol(Infinity, CodeRange.MOVE_END_ONLY); return all.getContent(); }, setReadOnly: function(val) { if (!this.setProperty("readOnly", val)) return; this.readOnly = val; if (this.readOnly) crossBrowser.addClass(comp.body, "read-only"); else crossBrowser.removeClass(comp.body, "read-only"); selection.showCursorState(); this.fireActionUpdate(); }, getReadOnly: function() { return this.readOnly; }, getSelection: function() { return selection.range; }, getLineByNumber: function(number) { var l = this.BOF; do { l = l.nextLine; number --; } while (number > 0 && l != this.EOF); return (l != this.EOF) && l; }, createCodeRange: function() { return new CodeRange(); }, createFindRegExps: function(s, flags) { if (!s) return false; if (!flags) flags = {}; var reText = s; var reFlags = 'g'; if (!flags.regExp) reText = reText.replace(/(\\|\^|\$|\*|\+|\-|\?|\.|\(|\)|\!|\:|\=|\||\{|\}|\,|\[|\])/g, "\\$1"); else reText = reText.replace(/\\n/g, "\n"); if (flags.wholeWord) reText = '\\b' + reText + '\\b'; if (!flags.caseSensitive) reFlags += 'i'; var result = reText.replace(/\n/g, "$\n^"); result = result.split("\n"); for (var i=0; i<result.length; i++) try { result[i] = new RegExp(result[i], reFlags); } catch(e) { // TODO: user tried an invalid regexp find, throw error? return false; } return result; }, // returns coderange or false findNext: function(s, flags, fromLine, fromCol) { var res = this.createFindRegExps(s, flags); if (!res) return false; fromLine = fromLine || selection.range.endLine; fromCol = fromCol || (selection.range.startCol + (selection.range.isCollapsed() ? 0 : 1)); var line = fromLine; var col = fromCol; var foundRange = false; do { foundRange = line.findNext(res, col); if (foundRange) break; line = line.nextLine; col = 0; // always wrap search if (line == this.EOF) line = this.BOF.nextLine; } while (line != fromLine); if (!foundRange) // find again on fromLine, but from start foundRange = fromLine.findNext(res, 0); return foundRange; }, // returns coderange or false findPrevious: function(s, flags, fromLine, fromCol) { var res = this.createFindRegExps(s, flags, true); if (!res) return false; fromLine = fromLine || selection.range.startLine; fromCol = fromCol || (selection.range.startCol - (selection.range.isCollapsed() ? 0 : 1)); var line = fromLine; var col = fromCol; var foundRange = false; do { foundRange = line.findPrevious(res, col); if (foundRange) break; line = line.prevLine; col = Infinity; // always wrap search if (line == this.BOF) line = this.EOF.prevLine; } while (line != fromLine); if (!foundRange) // find again on fromLine, but from end foundRange = fromLine.findPrevious(res, Infinity); return foundRange; }, // returns array of coderanges findAll: function(s, flags) { var firstRng = this.findNext(s, flags); if (!firstRng) return []; var results = []; var rng = firstRng; do { results.push(rng); rng = this.findNext(s, flags, rng.startLine, rng.startCol + 1); } while (!rng.equals(firstRng)); return results; }, createAction: function(_perform, options) { var o = options || {}; o._perform = _perform; return new Action(o); }, addEventListener: function(name, handler, useCapture) { if (!this.handlers[name]) this.handlers[name] = []; this.handlers[name].push(handler); }, updateLeftMargin: function() { this.updateLeftMarginTO = false; // update left margin var a = []; while (this.lineCount > this.lineNumberCount) a.push(++this.lineNumberCount); if (a.length) crossBrowser.appendHTML(this.leftMargin, "<div>" + a.join("</div><div>") + "</div>"); while (this.lineCount < this.lineNumberCount) { this.leftMargin.removeChild(this.leftMargin.lastChild); this.lineNumberCount--; } this.updateLayout(); }, readLayoutMetrics: function() { this.leftMargin.style.width = ''; var w = Math.max(30, this.leftMargin.offsetWidth); this.leftMargin.style.width = w; comp.body.style.paddingLeft = w + "px"; this.firstColOffsetLeft = w + 2; this.selectionPlane.style.left = this.firstColOffsetLeft + 'px'; this.oneCharWidth = this.oneChar.firstChild.offsetWidth; this.oneCharHeight = this.oneChar.firstChild.offsetHeight; if (comp != comp.body) { this.canvas.style.lineHeight = this.oneCharHeight + 'px'; this.leftMargin.style.lineHeight = this.oneCharHeight + 'px'; } }, updateLayout: function() { this.readLayoutMetrics(); this.positionOnScroll(); // make sure the cursor is recalculated this.currentCursorLine = null; selection.hide(); selection.show(selection.curClassName); }, updateLineCount: function(delta) { this.lineCount += delta; if (!this.updateLeftMarginTO) this.updateLeftMarginTO = setTimeout(codeArea.updateLeftMarginTOH, 0); }, removeAllLines: function() { var line = this.BOF.nextLine; while (line != this.EOF) { line.del(); line = line.nextLine; } }, positionOnScroll: function() { this.cursorMaybeNotInView = true; this.currentScrollLeftBoundary = comp.body.scrollLeft; this.currentScrollRightBoundary = comp.body.scrollLeft + comp.body.clientWidth - codeArea.leftMargin.offsetWidth - this.oneCharWidth; if (comp == comp.body) { this.leftMargin.style.left = comp.body.scrollLeft + 'px'; this.lineCursor.style.left = comp.body.scrollLeft + 'px'; this.colCursor.style.top = comp.body.scrollTop + 'px'; } }, positionCursorLine: function(line) { if (line != this.currentCursorLine) { this.currentCursorLine = line; var cursorTop = line.div.offsetTop + 2; // position cursor this.cursor.style.top = cursorTop + 'px'; this.lineCursor.style.top = cursorTop + 'px'; this.lineCursorInMargin.style.top = cursorTop + 'px'; // Keep cursor in view and remember this top this.storedScrollTop = this.scrollIntoViewY(cursorTop, codeArea.oneCharHeight); if (this.storedScrollTop === false) this.storedScrollTop = comp.body.scrollTop; } else { if (this.cursorMaybeNotInView) { // restore stored scrollTop var cursorTop = line.div.offsetTop; var scrollTopTarget = this.scrollIntoViewY(cursorTop, this.oneCharHeight, this.storedScrollTop); if (scrollTopTarget === false) // Top is OK, store for next time this.storedScrollTop = comp.body.scrollTop; this.cursorMaybeNotInView = false; } } }, calculateScrollTop: function(top, height, suggestedTop) { var padding = 2; var scrollTop = comp.body.scrollTop + padding; var clientHeight = comp.body.clientHeight - 2*padding; var scrollBot = scrollTop + clientHeight; var bot = top + height; // is range in view if (top >= scrollTop && bot <= scrollBot) return false; // taller than view and part of range in view if (top <= scrollTop && bot >= scrollBot) return false; if (!isNaN(suggestedTop)) return suggestedTop; if (bot > scrollBot) return bot - padding - clientHeight; return top - padding; }, scrollIntoViewY: function(top, height, suggestedTop) { if (this.scrollTopAnimation) this.scrollTopAnimation.finish(); var scrollTopTarget = this.calculateScrollTop(top, height, suggestedTop); if (scrollTopTarget === false) return false; var diff = Math.abs(comp.body.scrollTop - scrollTopTarget); // Don't animate small steps if (diff <= this.oneCharHeight) return comp.body.scrollTop = scrollTopTarget; // LAURENS: Animated scrolling is disabled since it causes problems on long lines. comp.body.scrollTop = scrollTopTarget; this.positionOnScroll(); return scrollTopTarget; var modifiers = new Modifiers(); modifiers.duration = Math.max(100, Math.min(300, diff * 2)); modifiers.finishAlways = true; modifiers.endCode = function () {codeArea.positionOnScroll()}; this.scrollTopAnimation = new Animator( [ { el:comp.body, targetState:{ scrollTop:scrollTopTarget } } ], modifiers ); return scrollTopTarget; }, positionCursorCol: function(col, line) { var cursorLeft = line.getXFromCol(col); // position cursor this.cursor.style.left = this.colCursor.style.left = (this.firstColOffsetLeft + cursorLeft) + 'px'; // Keep cursor in view this.scrollIntoViewX(cursorLeft, 0); }, calculateScrollLeft: function(left, width, suggestedLeft) { var scrollLeft = this.currentScrollLeftBoundary; var clientWidth = comp.body.clientWidth; var scrollRight = this.currentScrollRightBoundary; var right = left + width; // is range in view if (left >= scrollLeft && right <= scrollRight) return false; // wider than view and part of range in view if (left <= scrollLeft && right >= scrollRight) return false; if (!isNaN(suggestedLeft)) return suggestedLeft; if (right > scrollRight) return right + clientWidth * (0.2 - 1); if (left < clientWidth * 0.35) return 0; return left - clientWidth * 0.2; }, scrollIntoViewX: function(left, width) { if (this.scrollLeftAnimation) this.scrollLeftAnimation.finish(); var scrollLeftTarget = this.calculateScrollLeft(left, width); if (scrollLeftTarget === false) return false; var diff = Math.abs(comp.body.scrollLeft - scrollLeftTarget); // Don't animate small steps if (diff <= this.oneCharWidth) return comp.body.scrollLeft = scrollLeftTarget; // LAURENS: Animated scrolling is disabled since it causes problems on long lines. comp.body.scrollLeft = scrollLeftTarget; this.positionOnScroll(); return scrollLeftTarget; // todo cache this var modifiers = new Modifiers(); modifiers.duration = Math.max(100, Math.min(300, diff * 2)); modifiers.finishAlways = true; modifiers.endCode = function () {codeArea.positionOnScroll()}; this.scrollLeftAnimation = new Animator( [ { el:comp.body, targetState:{ scrollLeft:scrollLeftTarget } } ], modifiers ); return scrollLeftTarget; }, updateLeftMarginTOH: function() { // no this codeArea.updateLeftMargin(); }, getLineFromClientY: function(y) { y += comp.body.scrollTop; if (comp == comp.body) { var rect = crossBrowser.getBoundingClientRect(element); y -= rect.top; } var bottom = 0; var l = this.BOF; do { l = l.nextLine; bottom += this.oneCharHeight; } while (l != this.EOF.prevLine && bottom < y); return l; }, getColFromClientX: function(x, line) { x += comp.body.scrollLeft; if (comp == comp.body) { var rect = crossBrowser.getBoundingClientRect(element); x -= rect.left; } return line.getColFromX(x - codeArea.firstColOffsetLeft); }, focus: function() { if (comp.body.focus) comp.body.focus(); else { this.clipboard.style.top = (1+comp.body.scrollTop) + 'px'; this.clipboard.style.left = (1+comp.body.scrollLeft) + 'px'; if (!this.clipboard.value) this.clipboard.value = 'x'; codeArea.clipboard.setSelectionRange(0, this.clipboard.value.length); this.clipboard.focus(); onFocus(); } }, subscribeOnKey: function(condition, callback) { condition.callback = callback; codeArea.subscribedKeys.push(condition); }, setProperty: function(name, value) { if (this[name] == value) return false; this[name] = value; this.fireActionUpdate(); return true; }, fireActionUpdate: function() { this.fireEvent("actionupdate"); }, fireEvent: function(eventName) { if (window.parentDoc) { var evtObject = parentDoc.createEventObject(); parentDoc.getElementById("pe"+eventName).fire(evtObject); } else { var handlers = this.handlers[eventName]; if (handlers) for (var i=0; i<handlers.length; i++) handlers[i].call(element, {}); } }, checkFontSize: function() { // setTimeout handler, no this if ( codeArea.oneChar.firstChild.offsetHeight != codeArea.oneCharHeight || codeArea.oneChar.firstChild.offsetWidth != codeArea.oneCharWidth ) codeArea.updateLayout(); // refire this function setTimeout(arguments.callee, 200); } }; function onKeyDown(evt) { if (!codeArea.hasFocus) return true; //window.status = element.id + ' onKeyDown: ' + evt.keyCode + ' ' + (comp.hasFocus && comp.hasFocus() ? 'has focus' : 'no focus') + ' ' + (new Date * 1); // in Mozilla, non-character keys are handled in onKeyPress if (evt.charCode == 0) return true; return passCommand(evt.keyCode, evt); } function onKeyPress(evt) { /*if (comp.hasFocus && !comp.hasFocus()) return true;*/ // evt.keyCode lijkt op Mozilla (Win) altijd 0 te zijn // voorlopig probeer ik hier evt.charCode -- Salar //window.status = element.id + ' onKeyDown: ' + evt.keyCode + ' ' + (comp.hasFocus && comp.hasFocus() ? 'has focus' : 'no focus') + ' ' + (new Date * 1); if (evt.charCode !== undefined) { if (evt.charCode == 0) return passCommand(evt.keyCode, evt); return passCharInput(evt.charCode, evt); } else { return passCharInput(evt.keyCode, evt) } } function passCharInput(charCode, evt) { switch (charCode) { case 13: actions.newLine.perform(); return false; default: if (charCode >= 32) { if (!evt.ctrlKey && !evt.altKey) { actions.typing.perform(String.fromCharCode(charCode)); return false; } else { var keyCode = charCode >= 97 ? charCode - 32 : charCode; return passCommand(keyCode, evt); } }; return true; } } function passCommand(keyCode, evt) { evt.modifiers = evt.shiftKey + (evt.ctrlKey << 1) + (evt.altKey << 2); switch (keyCode) { case 8: // backspace actions.backspace.perform(evt); return false; case 9: // tab // LAURENS: Insert whitespace if we're not in the indentation part of the line. if (selection.getRange().isCollapsed() && selection.curCol > selection.curLine.getIndentSize(true)) selection.replaceContent(" "); else if (evt.shiftKey) actions.unindent.perform(); else actions.indent.perform(); return false; case 13: actions.newLine.perform(); return false; case 27: element.focus(); return false; case 33: selection.moveCursorPageUp(evt); return false; case 34: selection.moveCursorPageDown(evt); return false; case 35: selection.moveCursorEnd(evt); return false; case 36: selection.moveCursorHome(evt); return false; case 37: selection.moveCursorLeft(evt); return false; case 38: selection.moveCursorUp(evt); return false; case 39: selection.moveCursorRight(evt); return false; case 40: selection.moveCursorDown(evt); return false; case 45: // insert switch (evt.modifiers) { case 0: codeArea.overWrite = !codeArea.overWrite; return false; case 1: //shift-only return actions.paste.perform(); case 2: //ctrl-only return actions.copy.perform(); } return true; case 46: // delete if (evt.shiftKey) return actions.cut.perform(); actions.deleteKey.perform(evt); return false; case 118: // F7 profiler.showTimers(); return false; break; case 119: // F8 profiler.resetTimers(); return false; break; case 145: // scroll lock if (!evt.ctrlKey) { codeArea.scrollLock = !codeArea.scrollLock; return false; } return true; default: if (evt.ctrlKey && !evt.shiftKey && !evt.altKey) { switch (keyCode) { case 65: // Ctrl-A selection.selectAll(); return false; case 67: // Ctrl-C return actions.copy.perform(); case 73: // Ctrl-I return selection.switchIMEInput(); case 86: // Ctrl-V return actions.paste.perform(); case 88: // Ctrl-X return actions.cut.perform(); case 89: // Ctrl-Y return actions.redo.perform(); case 90: // Ctrl-Z return actions.undo.perform(); }; }; // Find from custom mappings for (var sk, i = 0; i < codeArea.subscribedKeys.length; i++) { sk = codeArea.subscribedKeys[i]; if (sk.action == 'down' && (typeof sk.ctrl == 'undefined' || sk.ctrl == evt.ctrlKey) && (typeof sk.alt == 'undefined' || sk.alt == evt.altKey)) { if (typeof sk.code == 'number' && sk.code == keyCode) { evt.keyCode = 0; sk.callback(); return false; }; // later: sk.range, sk.list invoeren? }; }; return true; } } function onKeyUp(evt) { return false; } var selecting = false; var capturing = false; var lineSelecting = false; function onMouseDown(evt) { if (evt.button == 1) { selection.moveCursorToPoint(evt.clientX, evt.clientY, evt.shiftKey); selecting = true; } } function onMouseMove(evt) { if (typeof(evt.button) == "number" && evt.button != 1 && (selecting || lineSelecting)) onMouseUp(evt); if (selecting) { if (!capturing) { if (codeArea.canvas.setCapture) codeArea.canvas.setCapture(); capturing = true; } selection.moveCursorToPoint(evt.clientX, evt.clientY, true); } if (lineSelecting) { var line = codeArea.getLineFromClientY(evt.clientY); var cr = new CodeRange(); cr.startLine = lineSelecting.line; cr.endLine = line; if (cr.endLine.isPreceding(cr.startLine)) { cr.startCol = Infinity; cr.endCol = 0; } else { cr.startCol = 0; cr.endCol = Infinity; } cr.select(); } } function onMouseUp(evt) { if (!codeArea.hasFocus) codeArea.focus(); if (selecting) { selection.moveCursorToPoint(evt.clientX, evt.clientY, true); selecting = false; if (capturing) { if (document.releaseCapture) document.releaseCapture(); capturing = false; } } if (lineSelecting) { lineSelecting = false; } } function onMouseDownMargin(evt) { var line = codeArea.getLineFromClientY(evt.clientY); lineSelecting = {line: line}; // select line var cr = new CodeRange(); cr.moveToLine(line); cr.select(); comp.body.scrollLeft = 0; return false; } function onFocus(evt) { codeArea.hasFocus = true; selection.showCursorState(); } function onBlur(evt) { codeArea.hasFocus = false; selection.showCursorState(); } function onScroll(evt) { codeArea.positionOnScroll(); } function onResize(evt) { codeArea.positionOnScroll(); } function onContextMenu(evt) { return false; }; function onIMEInputKeyDown(evt) { // in Mozilla, non-character keys are handled in onKeyPress if (evt.charCode == 0) return true; return handleIMEInputCommand(this, evt.keyCode, evt); }; function onIMEInputKeyPress(evt) { if (evt.charCode !== undefined) { if (evt.charCode == 0) return handleIMEInputCommand(this, evt.keyCode, evt); } event.cancelBubble = true; return true; }; function handleIMEInputCommand(inp, keyCode, evt) { switch (true) { case keyCode == 13: // return case keyCode == 33: // page up case keyCode == 34: // page down case keyCode == 38: // up case keyCode == 40: // down case keyCode == 73 && evt.ctrlKey && !evt.shiftKey && !evt.altKey: // CTRL-I var col = crossBrowser.getInputSelectionStart(inp); selection._moveCursorCol(col); onIMEInputBlur.call(evt.srcElement); passCommand(keyCode, evt); return false; default: evt.cancelBubble=true; return true; } }; function onIMEInputBlur() { var line = codeArea.lines[this.parentNode.id]; line.hideIMEInput(this.value); }; function cancelEvent() { return false; }var comp = document.getAnonymousNodes(this)[0]; comp.body = comp; comp.getElementById = function(id) { var els = comp.body.getElementsByTagName('*'); for (var i = 0; i < els.length; i++) if (els[i].id == id) return els[i]; }; comp.createElement = document.createElement; comp.createRange = document.createRange; var element = comp.parentNode; this.codeArea = codeArea; this.actions = actions; eventCenter.activate(); codeArea.init(); //this.normalize(); codeArea.setValue(this.innerText); codeArea.setReadOnly(this.hasAttribute("readonly")); eventCenter.attachEvent(comp, "onscroll", onScroll); eventCenter.attachEvent(comp.body, "onkeydown", onKeyDown); eventCenter.attachEvent(comp.body, "onkeypress", onKeyPress); eventCenter.attachEvent(comp.body, "onkeyup", onKeyUp); eventCenter.attachEvent(comp.body, "onfocus", onFocus); eventCenter.attachEvent(comp.body, "onblur", onBlur); eventCenter.attachEvent(codeArea.canvas, "onmousedown", onMouseDown); eventCenter.attachEvent(comp, "onmousemove", onMouseMove); eventCenter.attachEvent(comp, "oncontextmenu", onContextMenu); eventCenter.attachEvent(comp, "onmouseup", onMouseUp); eventCenter.attachEvent(codeArea.leftMargin, "onmousedown", onMouseDownMargin); eventCenter.attachEvent(comp, "ondraggesture", cancelEvent); var onload = element.getAttribute("onload"); if (onload) codeArea.addEventListener("load", new Function("event", onload), false); var onactionupdate = element.getAttribute("onactionupdate"); if (onactionupdate) codeArea.addEventListener("actionupdate", new Function("event", onactionupdate), false); codeArea.fireEvent("load"); var spaces = ' '; var zeros = '00000000000000000000'; //var tracer = new ActiveXObject("tracer.tracer"); var traceable = {}; function Profiler() { for (var i = 0; i <= 10; i++) this.regExps[i] = new RegExp(".{"+i+"}$"); /* window._alert = window.alert; window.alert = function(s) {window._alert(s)}; this.wrapFunction(window, 'alert', 'window'); window._confirm = window.confirm; window.confirm = function(s) {return window._confirm(s)}; this.wrapFunction(window, 'confirm', 'window');*/ // this.wrapFunction(this, 'renderTimersBranch', 'profiler'); // this.wrapFunction(this, 'tToString', 'profiler'); // this.wrapFunction(this, 'tToString2', 'profiler'); } Profiler.pData = {}; Profiler.nData = {}; Profiler.prototype = { subscribeConstructors: function(constructors) { for (var i = 0; i < constructors.length; i++) this.subscribeConstructor(constructors[i]); }, subscribeConstructor: function(constructor) { if (constructor.hasBeenProfiled) return; constructor.hasBeenProfiled = true; var cName = (''+constructor).match(/function (\w+)/i)[1]; this.subscribeObject(constructor, cName); this.subscribeObject(constructor.prototype, cName.replace(/^([A-Z])(([A-Z]*)([A-Z]))?/, function(m, m1, m2, m3, m4) {return m1.toLowerCase()+(m2?m3.toLowerCase()+m4:"")})); this.wrapConstructor(window, cName); }, subscribeObject:function(obj, objName) { if (!objName) objName = 'NN'; var functionNames = []; for (var propName in obj) if (typeof(obj[propName]) == 'function') functionNames.push(propName); for (var i=0; i<functionNames.length; i++) this.wrapFunction(obj, functionNames[i], objName); }, wrapConstructor:function(obj, constructorName) { var label = "new " + constructorName; var f = obj[constructorName]; obj[constructorName] = function() { try { tStart(label); return new f(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14], arguments[15], arguments[16], arguments[17], arguments[18], arguments[19], arguments[20], arguments[21], arguments[22], arguments[23], arguments[24], arguments[25]); } finally { tStop(label); } }; // Copy props. for (var propName in f) obj[constructorName][propName] = f[propName]; }, wrapFunction:function(obj, functionName, objName) { var label = objName + '.' + functionName; var f = obj[functionName]; obj[functionName] = function() { try { tStart(label); return f.apply(this, arguments); } finally { tStop(label); } }; }, showTimers: function () { var lines = []; lines.push('<h1>P'+'rofiler Results</h1>'); lines.push('<'+'script>function cl(){var div=this.nextSibling;if (div.nodeName.toLowerCase()=="div") div.style.display = (div.style.display=="none")?"":"none";var sep=this.getElementsByTagName("kbd")[0];sep.innerHTML = (sep.innerHTML=="+")?"-":"+";}</'+'script>'); lines.push('<style>pre,div{margin:0;cursor:hand;padding:0} u{text-decoration:none;border-top:1px solid #eee}</style>'); lines.push('<pre> total time = count x avg time / local time</pre>'); // Profiler.nData = {}; // var pData = Profiler.pData; // Profiler.pData = {}; this.renderTimersBranch(lines, Profiler.pData, '', 0); //Profiler.pData = pData; lines.push("<hr />"); lines.push('<pre>tot local time = count x avg local time</pre>'); var dataArray = []; for (var label in Profiler.nData) dataArray.push(Profiler.nData[label]); dataArray = dataArray.sort(function(d1, d2) { return d2.t - d1.t; }); for (var i=0; i<dataArray.length; i++) { var lData = dataArray[i]; lines.push('<pre><u>'); lines.push(this.tToString(lData.t, 10)); lines.push(' ms ='); lines.push(this.tToString(lData.count, 5)); lines.push(' x'); lines.push(this.tToString2(lData.t/lData.count, 7)); lines.push(' ms > '); lines.push(lData.label); lines.push('</u></pre>'); } var w = window.open(); w.document.write(lines.join('')); w.document.close(); // alert(s); }, renderTimersBranch: function (lines, pData, indent, step) { var color = this.getColor(step); var dataArray = []; for (var label in pData) if (label != "__p__") dataArray.push(pData[label]); dataArray = dataArray.sort(function(d1, d2) { return d2.t - d1.t; }); var total = 0; var nextIndent = indent + '<span style="' + color + '"> </span><u> </u>'; for (var i=0; i<dataArray.length; i++) { var lData = dataArray[i]; var branch = []; var branchtotal = this.renderTimersBranch(branch, lData.pData, nextIndent, step+1); localTime = lData.t-branchtotal; if (!Profiler.nData[lData.label]) Profiler.nData[lData.label] = { label:lData.label, count:0, t:0 }; Profiler.nData[lData.label].t += localTime; Profiler.nData[lData.label].count += lData.count; var sep = branch.length?"+":"<"; lines.push('<pre id=p onclick="cl.call(this)"><u>'); lines.push(this.tToString(lData.t, 10)); lines.push(' ms ='); lines.push(this.tToString(lData.count, 5)); lines.push(' x'); lines.push(this.tToString(lData.t/lData.count, 7)); lines.push(' ms / '); lines.push(this.tToString2(localTime, 7)); lines.push(' ms </u>'); lines.push(indent); lines.push('<kbd style="'); lines.push(color); lines.push(';border-top:1px solid white">'); lines.push(sep); lines.push('</kbd> '); lines.push(lData.label); lines.push('</pre>'); lines.push('<div style="display:none">'); lines.push(branch.join('')); lines.push('</div>'); total += lData.t; } return total; }, getColor: function (step) { if (step & 1 == 0) return 'background: #DCDCDC'; else return 'background: #EBEBEB'; }, resetTimers: function() { Profiler.pData = {}; Profiler.nData = {}; }, regExps: {}, tToString: function (t, l) { var regExp = this.regExps[l]; var s=''; while (t>1000) { t/=10;s+='0'; } t = Math.floor(t) + s; return (spaces+t).match(regExp)[0]; //return spaces.substring(0, l-t.length) + t; }, tToString2: function (t, l) { var regExp = this.regExps[l+2]; var a = Math.floor(t); t = '' + a + '.' + Math.floor(10*(t-a)); return (spaces+t).match(regExp)[0]; //return spaces.substring(0, l+2-t.length) + t; } }; function tStart(label) { var lData = Profiler.pData[label]; if (!lData) lData = Profiler.pData[label] = { label:label, count:0, t:0 }; lData.startT = +new Date(); if (!lData.pData) lData.pData = {__p__: Profiler.pData}; Profiler.pData = lData.pData; } function tStop(label) { Profiler.pData = Profiler.pData.__p__||Profiler.pData; var lData = Profiler.pData[label]; if (!lData) return; lData.count++; lData.t += (new Date() - lData.startT); } var profiler = new Profiler(); profiler.subscribeConstructor(Line); profiler.subscribeConstructor(Action); profiler.subscribeConstructor(CodeRange); profiler.subscribeConstructor(UndoState); profiler.subscribeConstructor(MozRange); profiler.subscribeObject(codeArea, "codeArea"); profiler.subscribeObject(undoStack, "undoStack"); profiler.subscribeObject(crossBrowser, "crossBrowser"); ]]></constructor> </implementation> <resources> <stylesheet src="scripts/xbl.css" /> </resources> <handlers> <handler event="keypress">if(event.keyCode==13) codeArea.canvas.focus();</handler> </handlers> </binding> </bindings>
Ms-Dos/Windows
Unix
Write backup
jsp File Browser version 1.2 by
www.vonloesch.de