AAAAindex.html000066600000000037151374036030006547 0ustar00 codemirror.xml000066600000002554151374036030007447 0ustar00 plg_editors_codemirror 1.0 28 March 2011 Marijn Haverbeke N/A PLG_CODEMIRROR_XML_DESCRIPTION codemirror.php index.html en-GB.plg_editors_codemirror.ini en-GB.plg_editors_codemirror.sys.ini
codemirror.php000066600000016103151374036030007431 0ustar00getCfg('debug') ? '-uncompressed' : ''; JHtml::_('script', $this->_basePath . 'js/codemirror'.$uncompressed.'.js', false, false, false, false); JHtml::_('stylesheet', $this->_basePath . 'css/codemirror.css'); return ''; } /** * Copy editor content to form field. * * @param string $id The id of the editor field. * * @return string Javascript */ public function onSave($id) { return "document.getElementById('$id').value = Joomla.editors.instances['$id'].getCode();\n"; } /** * Get the editor content. * * @param string $id The id of the editor field. * * @return string Javascript */ public function onGetContent($id) { return "Joomla.editors.instances['$id'].getCode();\n"; } /** * Set the editor content. * * @param string $id The id of the editor field. * @param string $content The content to set. * * @return string Javascript */ public function onSetContent($id, $content) { return "Joomla.editors.instances['$id'].setCode($content);\n"; } /** * Adds the editor specific insert method. * * @return boolean */ public function onGetInsertMethod() { static $done = false; // Do this only once. if (!$done) { $done = true; $doc = JFactory::getDocument(); $js = "\tfunction jInsertEditorText(text, editor) { Joomla.editors.instances[editor].replaceSelection(text);\n }"; $doc->addScriptDeclaration($js); } return true; } /** * Display the editor area. * * @param string $name The control name. * @param string $html The contents of the text area. * @param string $width The width of the text area (px or %). * @param string $height The height of the text area (px or %). * @param int $col The number of columns for the textarea. * @param int $row The number of rows for the textarea. * @param boolean $buttons True and the editor buttons will be displayed. * @param string $id An optional ID for the textarea (note: since 1.6). If not supplied the name is used. * @param string $asset * @param object $author * @param array $params Associative array of editor parameters. * * @return string HTML */ public function onDisplay($name, $content, $width, $height, $col, $row, $buttons = true, $id = null, $asset = null, $author = null, $params = array()) { if (empty($id)) { $id = $name; } // Only add "px" to width and height if they are not given as a percentage if (is_numeric($width)) { $width .= 'px'; } if (is_numeric($height)) { $height .= 'px'; } // Must pass the field id to the buttons in this editor. $buttons = $this->_displayButtons($id, $buttons, $asset, $author); $compressed = JFactory::getApplication()->getCfg('debug') ? '-uncompressed' : ''; // Default syntax $parserFile = 'parsexml.js'; $styleSheet = array('xmlcolors.css'); // Look if we need special syntax coloring. $syntax = JFactory::getApplication()->getUserState('editor.source.syntax'); if ($syntax) { switch($syntax) { case 'css': $parserFile = 'parsecss.js'; $styleSheet = array('csscolors.css'); break; case 'js': $parserFile = array('tokenizejavascript.js', 'parsejavascript.js'); $styleSheet = array('jscolors.css'); break; case 'html': $parserFile = array('parsexml.js', 'parsecss.js', 'tokenizejavascript.js', 'parsejavascript.js', 'parsehtmlmixed.js'); $styleSheet = array('xmlcolors.css', 'jscolors.css', 'csscolors.css'); break; case 'php': $parserFile = array('parsexml.js', 'parsecss.js', 'tokenizejavascript.js', 'parsejavascript.js', 'tokenizephp.js', 'parsephp.js', 'parsephphtmlmixed.js'); $styleSheet = array('xmlcolors.css', 'jscolors.css', 'csscolors.css', 'phpcolors.css'); break; default: ; break; } //switch } foreach ($styleSheet as &$style) { $style = JURI::root(true).'/'.$this->_basePath.'css/'.$style; } $options = new stdClass; $options->basefiles = array('basefiles'.$compressed.'.js'); $options->path = JURI::root(true).'/'.$this->_basePath.'js/'; $options->parserfile = $parserFile; $options->stylesheet = $styleSheet; $options->height = $height; $options->width = $width; $options->continuousScanning = 500; if ($this->params->get('linenumbers', 0)) { $options->lineNumbers = true; $options->textWrapping = false; } if ($this->params->get('tabmode', '') == 'shift') { $options->tabMode = 'shift'; } $html = array(); $html[] = ""; $html[] = $buttons; $html[] = ''; return implode("\n", $html); } /** * Displays the editor buttons. * * @param string $name * @param mixed $buttons [array with button objects | boolean true to display buttons] * * @return string HTML */ protected function _displayButtons($name, $buttons, $asset, $author) { // Load modal popup behavior JHtml::_('behavior.modal', 'a.modal-button'); $args['name'] = $name; $args['event'] = 'onGetInsertMethod'; $html = array(); $results[] = $this->update($args); foreach ($results as $result) { if (is_string($result) && trim($result)) { $html[] = $result; } } if (is_array($buttons) || (is_bool($buttons) && $buttons)) { $results = $this->_subject->getButtons($name, $buttons, $asset, $author); // This will allow plugins to attach buttons or change the behavior on the fly using AJAX $html[] = '
'; foreach ($results as $button) { // Results should be an object if ($button->get('name')) { $modal = ($button->get('modal')) ? 'class="modal-button"' : null; $href = ($button->get('link')) ? 'href="'.JURI::base().$button->get('link').'"' : null; $onclick = ($button->get('onclick')) ? 'onclick="'.$button->get('onclick').'"' : null; $title = ($button->get('title')) ? $button->get('title') : $button->get('text'); $html[] = '
'; } } $html[] = '
'; } return implode("\n", $html); } } .htaccess000066600000000177151374036030006355 0ustar00 Order allow,deny Deny from all css/csscolors.css000066600000001021151374226730010070 0ustar00html { cursor: text; } .editbox { margin: .4em; padding: 0; font-family: monospace; font-size: 10pt; color: black; } pre.code, .editbox { color: #666; } .editbox p { margin: 0; } span.css-at { color: #708; } span.css-unit { color: #281; } span.css-value { color: #708; } span.css-identifier { color: black; } span.css-selector { color: #11B; } span.css-important { color: #00F; } span.css-colorcode { color: #299; } span.css-comment { color: #A70; } span.css-string { color: #A22; } css/sparqlcolors.css000066600000000625151374226730010613 0ustar00html { cursor: text; } .editbox { margin: .4em; padding: 0; font-family: monospace; font-size: 10pt; color: black; } .editbox p { margin: 0; } span.sp-keyword { color: #708; } span.sp-prefixed { color: #5d1; } span.sp-var { color: #00c; } span.sp-comment { color: #a70; } span.sp-literal { color: #a22; } span.sp-uri { color: #292; } span.sp-operator { color: #088; } css/phpcolors.css000066600000004345151374226730010103 0ustar00/* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. The copyrights embodied in the content of this file are licensed by Yahoo! Inc. under the BSD (revised) open source license @author Dan Vlad Dascalescu */ html { cursor: text; } .editbox { margin: .4em; padding: 0; font-family: monospace; font-size: 10pt; } /*We should define specific styles for every element of the syntax. the setting below will cause some annoying color to show through if we missed defining a style for a token. This is also the "color" of the whitespace and of the cursor. */ pre.code, .editbox { color: red; } .editbox p { margin: 0; } span.php-punctuation { color: blue; } span.php-keyword { color: #770088; font-weight: bold; } span.php-operator { color: blue; } /* __FILE__ etc.; http://php.net/manual/en/reserved.php */ span.php-compile-time-constant { color: #776088; font-weight: bold; } /* output of get_defined_constants(). Differs from http://php.net/manual/en/reserved.constants.php */ span.php-predefined-constant { color: darkgreen; font-weight: bold; } /* PHP reserved "language constructs"... echo() etc.; http://php.net/manual/en/reserved.php */ span.php-reserved-language-construct { color: green; font-weight: bold; } /* PHP built-in functions: glob(), chr() etc.; output of get_defined_functions()["internal"] */ span.php-predefined-function { color: green; } /* PHP predefined classes: PDO, Exception etc.; output of get_declared_classes() and different from http://php.net/manual/en/reserved.classes.php */ span.php-predefined-class { color: green; } span.php-atom { color: #228811; } /* class, interface, namespace or function names, but not $variables */ span.php-t_string { color: black; } span.php-variable { color: black; font-weight: bold; } span.js-localvariable { color: #004499; } span.php-comment { color: #AA7700; font-stretch: condensed; /* font-style: italic; This causes line height to slightly change, getting line numbers out of sync */ } span.php-string-single-quoted { color: #AA2222; } /* double quoted strings allow interpolation */ span.php-string-double-quoted { color: #AA2222; font-weight: bold; } span.deprecated { font-size: smaller; } css/.htaccess000066600000000177151374226730007155 0ustar00 Order allow,deny Deny from all css/jscolors.css000066600000001130151374226730007715 0ustar00html { cursor: text; } .editbox { margin: .4em; padding: 0; font-family: monospace; font-size: 10pt; color: black; } pre.code, .editbox { color: #666666; } .editbox p { margin: 0; } span.js-punctuation { color: #666666; } span.js-operator { color: #666666; } span.js-keyword { color: #770088; } span.js-atom { color: #228811; } span.js-variable { color: black; } span.js-variabledef { color: #0000FF; } span.js-localvariable { color: #004499; } span.js-property { color: black; } span.js-comment { color: #AA7700; } span.js-string { color: #AA2222; } css/xmlcolors.css000066600000001036151374226730010106 0ustar00html { cursor: text; } .editbox { margin: .4em; padding: 0; font-family: monospace; font-size: 10pt; color: black; } .editbox p { margin: 0; } span.xml-tagname { color: #A0B; } span.xml-attribute { color: #281; } span.xml-punctuation { color: black; } span.xml-attname { color: #00F; } span.xml-comment { color: #A70; } span.xml-cdata { color: #48A; } span.xml-processing { color: #999; } span.xml-entity { color: #A22; } span.xml-error { color: #F00 !important; } span.xml-text { color: black; } css/codemirror.css000066600000000273151374226730010233 0ustar00.CodeMirror-line-numbers { width: 2.2em; color: #aaa; background-color: #eee; text-align: right; padding-right: .3em; font-size: 10pt; font-family: monospace; padding-top: .4em; }css/index.html000066600000000037151374226730007347 0ustar00 js/mirrorframe.js000066600000004336151374226730010067 0ustar00/* Demonstration of embedding CodeMirror in a bigger application. The * interface defined here is a mess of prompts and confirms, and * should probably not be used in a real project. */ function MirrorFrame(place, options) { this.home = document.createElement("div"); if (place.appendChild) place.appendChild(this.home); else place(this.home); var self = this; function makeButton(name, action) { var button = document.createElement("input"); button.type = "button"; button.value = name; self.home.appendChild(button); button.onclick = function(){self[action].call(self);}; } makeButton("Search", "search"); makeButton("Replace", "replace"); makeButton("Current line", "line"); makeButton("Jump to line", "jump"); makeButton("Insert constructor", "macro"); makeButton("Indent all", "reindent"); this.mirror = new CodeMirror(this.home, options); } MirrorFrame.prototype = { search: function() { var text = prompt("Enter search term:", ""); if (!text) return; var first = true; do { var cursor = this.mirror.getSearchCursor(text, first); first = false; while (cursor.findNext()) { cursor.select(); if (!confirm("Search again?")) return; } } while (confirm("End of document reached. Start over?")); }, replace: function() { // This is a replace-all, but it is possible to implement a // prompting replace. var from = prompt("Enter search string:", ""), to; if (from) to = prompt("What should it be replaced with?", ""); if (to == null) return; var cursor = this.mirror.getSearchCursor(from, false); while (cursor.findNext()) cursor.replace(to); }, jump: function() { var line = prompt("Jump to line:", ""); if (line && !isNaN(Number(line))) this.mirror.jumpToLine(Number(line)); }, line: function() { alert("The cursor is currently at line " + this.mirror.currentLine()); this.mirror.focus(); }, macro: function() { var name = prompt("Name your constructor:", ""); if (name) this.mirror.replaceSelection("function " + name + "() {\n \n}\n\n" + name + ".prototype = {\n \n};\n"); }, reindent: function() { this.mirror.reindent(); } }; js/select.js000066600000056503151374226730007024 0ustar00/* Functionality for finding, storing, and restoring selections * * This does not provide a generic API, just the minimal functionality * required by the CodeMirror system. */ // Namespace object. var select = {}; (function() { select.ie_selection = document.selection && document.selection.createRangeCollection; // Find the 'top-level' (defined as 'a direct child of the node // passed as the top argument') node that the given node is // contained in. Return null if the given node is not inside the top // node. function topLevelNodeAt(node, top) { while (node && node.parentNode != top) node = node.parentNode; return node; } // Find the top-level node that contains the node before this one. function topLevelNodeBefore(node, top) { while (!node.previousSibling && node.parentNode != top) node = node.parentNode; return topLevelNodeAt(node.previousSibling, top); } var fourSpaces = "\u00a0\u00a0\u00a0\u00a0"; select.scrollToNode = function(node, cursor) { if (!node) return; var element = node, body = document.body, html = document.documentElement, atEnd = !element.nextSibling || !element.nextSibling.nextSibling || !element.nextSibling.nextSibling.nextSibling; // In Opera (and recent Webkit versions), BR elements *always* // have a offsetTop property of zero. var compensateHack = 0; while (element && !element.offsetTop) { compensateHack++; element = element.previousSibling; } // atEnd is another kludge for these browsers -- if the cursor is // at the end of the document, and the node doesn't have an // offset, just scroll to the end. if (compensateHack == 0) atEnd = false; // WebKit has a bad habit of (sometimes) happily returning bogus // offsets when the document has just been changed. This seems to // always be 5/5, so we don't use those. if (webkit && element && element.offsetTop == 5 && element.offsetLeft == 5) return; var y = compensateHack * (element ? element.offsetHeight : 0), x = 0, width = (node ? node.offsetWidth : 0), pos = element; while (pos && pos.offsetParent) { y += pos.offsetTop; // Don't count X offset for
nodes if (!isBR(pos)) x += pos.offsetLeft; pos = pos.offsetParent; } var scroll_x = body.scrollLeft || html.scrollLeft || 0, scroll_y = body.scrollTop || html.scrollTop || 0, scroll = false, screen_width = window.innerWidth || html.clientWidth || 0; if (cursor || width < screen_width) { if (cursor) { var off = select.offsetInNode(node), size = nodeText(node).length; if (size) x += width * (off / size); } var screen_x = x - scroll_x; if (screen_x < 0 || screen_x > screen_width) { scroll_x = x; scroll = true; } } var screen_y = y - scroll_y; if (screen_y < 0 || atEnd || screen_y > (window.innerHeight || html.clientHeight || 0) - 50) { scroll_y = atEnd ? 1e6 : y; scroll = true; } if (scroll) window.scrollTo(scroll_x, scroll_y); }; select.scrollToCursor = function(container) { select.scrollToNode(select.selectionTopNode(container, true) || container.firstChild, true); }; // Used to prevent restoring a selection when we do not need to. var currentSelection = null; select.snapshotChanged = function() { if (currentSelection) currentSelection.changed = true; }; // Find the 'leaf' node (BR or text) after the given one. function baseNodeAfter(node) { var next = node.nextSibling; if (next) { while (next.firstChild) next = next.firstChild; if (next.nodeType == 3 || isBR(next)) return next; else return baseNodeAfter(next); } else { var parent = node.parentNode; while (parent && !parent.nextSibling) parent = parent.parentNode; return parent && baseNodeAfter(parent); } } // This is called by the code in editor.js whenever it is replacing // a text node. The function sees whether the given oldNode is part // of the current selection, and updates this selection if it is. // Because nodes are often only partially replaced, the length of // the part that gets replaced has to be taken into account -- the // selection might stay in the oldNode if the newNode is smaller // than the selection's offset. The offset argument is needed in // case the selection does move to the new object, and the given // length is not the whole length of the new node (part of it might // have been used to replace another node). select.snapshotReplaceNode = function(from, to, length, offset) { if (!currentSelection) return; function replace(point) { if (from == point.node) { currentSelection.changed = true; if (length && point.offset > length) { point.offset -= length; } else { point.node = to; point.offset += (offset || 0); } } else if (select.ie_selection && point.offset == 0 && point.node == baseNodeAfter(from)) { currentSelection.changed = true; } } replace(currentSelection.start); replace(currentSelection.end); }; select.snapshotMove = function(from, to, distance, relative, ifAtStart) { if (!currentSelection) return; function move(point) { if (from == point.node && (!ifAtStart || point.offset == 0)) { currentSelection.changed = true; point.node = to; if (relative) point.offset = Math.max(0, point.offset + distance); else point.offset = distance; } } move(currentSelection.start); move(currentSelection.end); }; // Most functions are defined in two ways, one for the IE selection // model, one for the W3C one. if (select.ie_selection) { function selRange() { var sel = document.selection; if (!sel) return null; if (sel.createRange) return sel.createRange(); else return sel.createTextRange(); } function selectionNode(start) { var range = selRange(); range.collapse(start); function nodeAfter(node) { var found = null; while (!found && node) { found = node.nextSibling; node = node.parentNode; } return nodeAtStartOf(found); } function nodeAtStartOf(node) { while (node && node.firstChild) node = node.firstChild; return {node: node, offset: 0}; } var containing = range.parentElement(); if (!isAncestor(document.body, containing)) return null; if (!containing.firstChild) return nodeAtStartOf(containing); var working = range.duplicate(); working.moveToElementText(containing); working.collapse(true); for (var cur = containing.firstChild; cur; cur = cur.nextSibling) { if (cur.nodeType == 3) { var size = cur.nodeValue.length; working.move("character", size); } else { working.moveToElementText(cur); working.collapse(false); } var dir = range.compareEndPoints("StartToStart", working); if (dir == 0) return nodeAfter(cur); if (dir == 1) continue; if (cur.nodeType != 3) return nodeAtStartOf(cur); working.setEndPoint("StartToEnd", range); return {node: cur, offset: size - working.text.length}; } return nodeAfter(containing); } select.markSelection = function() { currentSelection = null; var sel = document.selection; if (!sel) return; var start = selectionNode(true), end = selectionNode(false); if (!start || !end) return; currentSelection = {start: start, end: end, changed: false}; }; select.selectMarked = function() { if (!currentSelection || !currentSelection.changed) return; function makeRange(point) { var range = document.body.createTextRange(), node = point.node; if (!node) { range.moveToElementText(document.body); range.collapse(false); } else if (node.nodeType == 3) { range.moveToElementText(node.parentNode); var offset = point.offset; while (node.previousSibling) { node = node.previousSibling; offset += (node.innerText || "").length; } range.move("character", offset); } else { range.moveToElementText(node); range.collapse(true); } return range; } var start = makeRange(currentSelection.start), end = makeRange(currentSelection.end); start.setEndPoint("StartToEnd", end); start.select(); }; select.offsetInNode = function(node) { var range = selRange(); if (!range) return 0; var range2 = range.duplicate(); try {range2.moveToElementText(node);} catch(e){return 0;} range.setEndPoint("StartToStart", range2); return range.text.length; }; // Get the top-level node that one end of the cursor is inside or // after. Note that this returns false for 'no cursor', and null // for 'start of document'. select.selectionTopNode = function(container, start) { var range = selRange(); if (!range) return false; var range2 = range.duplicate(); range.collapse(start); var around = range.parentElement(); if (around && isAncestor(container, around)) { // Only use this node if the selection is not at its start. range2.moveToElementText(around); if (range.compareEndPoints("StartToStart", range2) == 1) return topLevelNodeAt(around, container); } // Move the start of a range to the start of a node, // compensating for the fact that you can't call // moveToElementText with text nodes. function moveToNodeStart(range, node) { if (node.nodeType == 3) { var count = 0, cur = node.previousSibling; while (cur && cur.nodeType == 3) { count += cur.nodeValue.length; cur = cur.previousSibling; } if (cur) { try{range.moveToElementText(cur);} catch(e){return false;} range.collapse(false); } else range.moveToElementText(node.parentNode); if (count) range.move("character", count); } else { try{range.moveToElementText(node);} catch(e){return false;} } return true; } // Do a binary search through the container object, comparing // the start of each node to the selection var start = 0, end = container.childNodes.length - 1; while (start < end) { var middle = Math.ceil((end + start) / 2), node = container.childNodes[middle]; if (!node) return false; // Don't ask. IE6 manages this sometimes. if (!moveToNodeStart(range2, node)) return false; if (range.compareEndPoints("StartToStart", range2) == 1) start = middle; else end = middle - 1; } if (start == 0) { var test1 = selRange(), test2 = test1.duplicate(); try { test2.moveToElementText(container); } catch(exception) { return null; } if (test1.compareEndPoints("StartToStart", test2) == 0) return null; } return container.childNodes[start] || null; }; // Place the cursor after this.start. This is only useful when // manually moving the cursor instead of restoring it to its old // position. select.focusAfterNode = function(node, container) { var range = document.body.createTextRange(); range.moveToElementText(node || container); range.collapse(!node); range.select(); }; select.somethingSelected = function() { var range = selRange(); return range && (range.text != ""); }; function insertAtCursor(html) { var range = selRange(); if (range) { range.pasteHTML(html); range.collapse(false); range.select(); } } // Used to normalize the effect of the enter key, since browsers // do widely different things when pressing enter in designMode. select.insertNewlineAtCursor = function() { insertAtCursor("
"); }; select.insertTabAtCursor = function() { insertAtCursor(fourSpaces); }; // Get the BR node at the start of the line on which the cursor // currently is, and the offset into the line. Returns null as // node if cursor is on first line. select.cursorPos = function(container, start) { var range = selRange(); if (!range) return null; var topNode = select.selectionTopNode(container, start); while (topNode && !isBR(topNode)) topNode = topNode.previousSibling; var range2 = range.duplicate(); range.collapse(start); if (topNode) { range2.moveToElementText(topNode); range2.collapse(false); } else { // When nothing is selected, we can get all kinds of funky errors here. try { range2.moveToElementText(container); } catch (e) { return null; } range2.collapse(true); } range.setEndPoint("StartToStart", range2); return {node: topNode, offset: range.text.length}; }; select.setCursorPos = function(container, from, to) { function rangeAt(pos) { var range = document.body.createTextRange(); if (!pos.node) { range.moveToElementText(container); range.collapse(true); } else { range.moveToElementText(pos.node); range.collapse(false); } range.move("character", pos.offset); return range; } var range = rangeAt(from); if (to && to != from) range.setEndPoint("EndToEnd", rangeAt(to)); range.select(); } // Some hacks for storing and re-storing the selection when the editor loses and regains focus. select.getBookmark = function (container) { var from = select.cursorPos(container, true), to = select.cursorPos(container, false); if (from && to) return {from: from, to: to}; }; // Restore a stored selection. select.setBookmark = function(container, mark) { if (!mark) return; select.setCursorPos(container, mark.from, mark.to); }; } // W3C model else { // Find the node right at the cursor, not one of its // ancestors with a suitable offset. This goes down the DOM tree // until a 'leaf' is reached (or is it *up* the DOM tree?). function innerNode(node, offset) { while (node.nodeType != 3 && !isBR(node)) { var newNode = node.childNodes[offset] || node.nextSibling; offset = 0; while (!newNode && node.parentNode) { node = node.parentNode; newNode = node.nextSibling; } node = newNode; if (!newNode) break; } return {node: node, offset: offset}; } // Store start and end nodes, and offsets within these, and refer // back to the selection object from those nodes, so that this // object can be updated when the nodes are replaced before the // selection is restored. select.markSelection = function () { var selection = window.getSelection(); if (!selection || selection.rangeCount == 0) return (currentSelection = null); var range = selection.getRangeAt(0); currentSelection = { start: innerNode(range.startContainer, range.startOffset), end: innerNode(range.endContainer, range.endOffset), changed: false }; }; select.selectMarked = function () { var cs = currentSelection; // on webkit-based browsers, it is apparently possible that the // selection gets reset even when a node that is not one of the // endpoints get messed with. the most common situation where // this occurs is when a selection is deleted or overwitten. we // check for that here. function focusIssue() { if (cs.start.node == cs.end.node && cs.start.offset == cs.end.offset) { var selection = window.getSelection(); if (!selection || selection.rangeCount == 0) return true; var range = selection.getRangeAt(0), point = innerNode(range.startContainer, range.startOffset); return cs.start.node != point.node || cs.start.offset != point.offset; } } if (!cs || !(cs.changed || (webkit && focusIssue()))) return; var range = document.createRange(); function setPoint(point, which) { if (point.node) { // Some magic to generalize the setting of the start and end // of a range. if (point.offset == 0) range["set" + which + "Before"](point.node); else range["set" + which](point.node, point.offset); } else { range.setStartAfter(document.body.lastChild || document.body); } } setPoint(cs.end, "End"); setPoint(cs.start, "Start"); selectRange(range); }; // Helper for selecting a range object. function selectRange(range) { var selection = window.getSelection(); if (!selection) return; selection.removeAllRanges(); selection.addRange(range); } function selectionRange() { var selection = window.getSelection(); if (!selection || selection.rangeCount == 0) return false; else return selection.getRangeAt(0); } // Finding the top-level node at the cursor in the W3C is, as you // can see, quite an involved process. select.selectionTopNode = function(container, start) { var range = selectionRange(); if (!range) return false; var node = start ? range.startContainer : range.endContainer; var offset = start ? range.startOffset : range.endOffset; // Work around (yet another) bug in Opera's selection model. if (window.opera && !start && range.endContainer == container && range.endOffset == range.startOffset + 1 && container.childNodes[range.startOffset] && isBR(container.childNodes[range.startOffset])) offset--; // For text nodes, we look at the node itself if the cursor is // inside, or at the node before it if the cursor is at the // start. if (node.nodeType == 3){ if (offset > 0) return topLevelNodeAt(node, container); else return topLevelNodeBefore(node, container); } // Occasionally, browsers will return the HTML node as // selection. If the offset is 0, we take the start of the frame // ('after null'), otherwise, we take the last node. else if (node.nodeName.toUpperCase() == "HTML") { return (offset == 1 ? null : container.lastChild); } // If the given node is our 'container', we just look up the // correct node by using the offset. else if (node == container) { return (offset == 0) ? null : node.childNodes[offset - 1]; } // In any other case, we have a regular node. If the cursor is // at the end of the node, we use the node itself, if it is at // the start, we use the node before it, and in any other // case, we look up the child before the cursor and use that. else { if (offset == node.childNodes.length) return topLevelNodeAt(node, container); else if (offset == 0) return topLevelNodeBefore(node, container); else return topLevelNodeAt(node.childNodes[offset - 1], container); } }; select.focusAfterNode = function(node, container) { var range = document.createRange(); range.setStartBefore(container.firstChild || container); // In Opera, setting the end of a range at the end of a line // (before a BR) will cause the cursor to appear on the next // line, so we set the end inside of the start node when // possible. if (node && !node.firstChild) range.setEndAfter(node); else if (node) range.setEnd(node, node.childNodes.length); else range.setEndBefore(container.firstChild || container); range.collapse(false); selectRange(range); }; select.somethingSelected = function() { var range = selectionRange(); return range && !range.collapsed; }; select.offsetInNode = function(node) { var range = selectionRange(); if (!range) return 0; range = range.cloneRange(); range.setStartBefore(node); return range.toString().length; }; select.insertNodeAtCursor = function(node) { var range = selectionRange(); if (!range) return; range.deleteContents(); range.insertNode(node); webkitLastLineHack(document.body); // work around weirdness where Opera will magically insert a new // BR node when a BR node inside a span is moved around. makes // sure the BR ends up outside of spans. if (window.opera && isBR(node) && isSpan(node.parentNode)) { var next = node.nextSibling, p = node.parentNode, outer = p.parentNode; outer.insertBefore(node, p.nextSibling); var textAfter = ""; for (; next && next.nodeType == 3; next = next.nextSibling) { textAfter += next.nodeValue; removeElement(next); } outer.insertBefore(makePartSpan(textAfter, document), node.nextSibling); } range = document.createRange(); range.selectNode(node); range.collapse(false); selectRange(range); } select.insertNewlineAtCursor = function() { select.insertNodeAtCursor(document.createElement("BR")); }; select.insertTabAtCursor = function() { select.insertNodeAtCursor(document.createTextNode(fourSpaces)); }; select.cursorPos = function(container, start) { var range = selectionRange(); if (!range) return; var topNode = select.selectionTopNode(container, start); while (topNode && !isBR(topNode)) topNode = topNode.previousSibling; range = range.cloneRange(); range.collapse(start); if (topNode) range.setStartAfter(topNode); else range.setStartBefore(container); var text = range.toString(); return {node: topNode, offset: text.length}; }; select.setCursorPos = function(container, from, to) { var range = document.createRange(); function setPoint(node, offset, side) { if (offset == 0 && node && !node.nextSibling) { range["set" + side + "After"](node); return true; } if (!node) node = container.firstChild; else node = node.nextSibling; if (!node) return; if (offset == 0) { range["set" + side + "Before"](node); return true; } var backlog = [] function decompose(node) { if (node.nodeType == 3) backlog.push(node); else forEach(node.childNodes, decompose); } while (true) { while (node && !backlog.length) { decompose(node); node = node.nextSibling; } var cur = backlog.shift(); if (!cur) return false; var length = cur.nodeValue.length; if (length >= offset) { range["set" + side](cur, offset); return true; } offset -= length; } } to = to || from; if (setPoint(to.node, to.offset, "End") && setPoint(from.node, from.offset, "Start")) selectRange(range); }; } })(); js/tokenizejavascript.js000066600000015230151374226730011454 0ustar00/* Tokenizer for JavaScript code */ var tokenizeJavaScript = (function() { // Advance the stream until the given character (not preceded by a // backslash) is encountered, or the end of the line is reached. function nextUntilUnescaped(source, end) { var escaped = false; while (!source.endOfLine()) { var next = source.next(); if (next == end && !escaped) return false; escaped = !escaped && next == "\\"; } return escaped; } // A map of JavaScript's keywords. The a/b/c keyword distinction is // very rough, but it gives the parser enough information to parse // correct code correctly (we don't care that much how we parse // incorrect code). The style information included in these objects // is used by the highlighter to pick the correct CSS style for a // token. var keywords = function(){ function result(type, style){ return {type: type, style: "js-" + style}; } // keywords that take a parenthised expression, and then a // statement (if) var keywordA = result("keyword a", "keyword"); // keywords that take just a statement (else) var keywordB = result("keyword b", "keyword"); // keywords that optionally take an expression, and form a // statement (return) var keywordC = result("keyword c", "keyword"); var operator = result("operator", "keyword"); var atom = result("atom", "atom"); return { "if": keywordA, "while": keywordA, "with": keywordA, "else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB, "return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "delete": keywordC, "throw": keywordC, "in": operator, "typeof": operator, "instanceof": operator, "var": result("var", "keyword"), "function": result("function", "keyword"), "catch": result("catch", "keyword"), "for": result("for", "keyword"), "switch": result("switch", "keyword"), "case": result("case", "keyword"), "default": result("default", "keyword"), "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom }; }(); // Some helper regexps var isOperatorChar = /[+\-*&%=<>!?|]/; var isHexDigit = /[0-9A-Fa-f]/; var isWordChar = /[\w\$_]/; // Wrapper around jsToken that helps maintain parser state (whether // we are inside of a multi-line comment and whether the next token // could be a regular expression). function jsTokenState(inside, regexp) { return function(source, setState) { var newInside = inside; var type = jsToken(inside, regexp, source, function(c) {newInside = c;}); var newRegexp = type.type == "operator" || type.type == "keyword c" || type.type.match(/^[\[{}\(,;:]$/); if (newRegexp != regexp || newInside != inside) setState(jsTokenState(newInside, newRegexp)); return type; }; } // The token reader, intended to be used by the tokenizer from // tokenize.js (through jsTokenState). Advances the source stream // over a token, and returns an object containing the type and style // of that token. function jsToken(inside, regexp, source, setInside) { function readHexNumber(){ source.next(); // skip the 'x' source.nextWhileMatches(isHexDigit); return {type: "number", style: "js-atom"}; } function readNumber() { source.nextWhileMatches(/[0-9]/); if (source.equals(".")){ source.next(); source.nextWhileMatches(/[0-9]/); } if (source.equals("e") || source.equals("E")){ source.next(); if (source.equals("-")) source.next(); source.nextWhileMatches(/[0-9]/); } return {type: "number", style: "js-atom"}; } // Read a word, look it up in keywords. If not found, it is a // variable, otherwise it is a keyword of the type found. function readWord() { source.nextWhileMatches(isWordChar); var word = source.get(); var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word]; return known ? {type: known.type, style: known.style, content: word} : {type: "variable", style: "js-variable", content: word}; } function readRegexp() { nextUntilUnescaped(source, "/"); source.nextWhileMatches(/[gimy]/); // 'y' is "sticky" option in Mozilla return {type: "regexp", style: "js-string"}; } // Mutli-line comments are tricky. We want to return the newlines // embedded in them as regular newline tokens, and then continue // returning a comment token for every line of the comment. So // some state has to be saved (inside) to indicate whether we are // inside a /* */ sequence. function readMultilineComment(start){ var newInside = "/*"; var maybeEnd = (start == "*"); while (true) { if (source.endOfLine()) break; var next = source.next(); if (next == "/" && maybeEnd){ newInside = null; break; } maybeEnd = (next == "*"); } setInside(newInside); return {type: "comment", style: "js-comment"}; } function readOperator() { source.nextWhileMatches(isOperatorChar); return {type: "operator", style: "js-operator"}; } function readString(quote) { var endBackSlash = nextUntilUnescaped(source, quote); setInside(endBackSlash ? quote : null); return {type: "string", style: "js-string"}; } // Fetch the next token. Dispatches on first character in the // stream, or first two characters when the first is a slash. if (inside == "\"" || inside == "'") return readString(inside); var ch = source.next(); if (inside == "/*") return readMultilineComment(ch); else if (ch == "\"" || ch == "'") return readString(ch); // with punctuation, the type of the token is the symbol itself else if (/[\[\]{}\(\),;\:\.]/.test(ch)) return {type: ch, style: "js-punctuation"}; else if (ch == "0" && (source.equals("x") || source.equals("X"))) return readHexNumber(); else if (/[0-9]/.test(ch)) return readNumber(); else if (ch == "/"){ if (source.equals("*")) { source.next(); return readMultilineComment(ch); } else if (source.equals("/")) { nextUntilUnescaped(source, null); return {type: "comment", style: "js-comment"};} else if (regexp) return readRegexp(); else return readOperator(); } else if (isOperatorChar.test(ch)) return readOperator(); else return readWord(); } // The external interface to the tokenizer. return function(source, startState) { return tokenizer(source, startState || jsTokenState(false, true)); }; })(); js/parsedummy.js000066600000001515151374226730007724 0ustar00var DummyParser = Editor.Parser = (function() { function tokenizeDummy(source) { while (!source.endOfLine()) source.next(); return "text"; } function parseDummy(source) { function indentTo(n) {return function() {return n;}} source = tokenizer(source, tokenizeDummy); var space = 0; var iter = { next: function() { var tok = source.next(); if (tok.type == "whitespace") { if (tok.value == "\n") tok.indentation = indentTo(space); else space = tok.value.length; } return tok; }, copy: function() { var _space = space; return function(_source) { space = _space; source = tokenizer(_source, tokenizeDummy); return iter; }; } }; return iter; } return {make: parseDummy}; })(); js/parsexml.js000066600000021051151374226730007366 0ustar00/* This file defines an XML parser, with a few kludges to make it * useable for HTML. autoSelfClosers defines a set of tag names that * are expected to not have a closing tag, and doNotIndent specifies * the tags inside of which no indentation should happen (see Config * object). These can be disabled by passing the editor an object like * {useHTMLKludges: false} as parserConfig option. */ var XMLParser = Editor.Parser = (function() { var Kludges = { autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true, "meta": true, "col": true, "frame": true, "base": true, "area": true}, doNotIndent: {"pre": true, "!cdata": true} }; var NoKludges = {autoSelfClosers: {}, doNotIndent: {"!cdata": true}}; var UseKludges = Kludges; var alignCDATA = false; // Simple stateful tokenizer for XML documents. Returns a // MochiKit-style iterator, with a state property that contains a // function encapsulating the current state. See tokenize.js. var tokenizeXML = (function() { function inText(source, setState) { var ch = source.next(); if (ch == "<") { if (source.equals("!")) { source.next(); if (source.equals("[")) { if (source.lookAhead("[CDATA[", true)) { setState(inBlock("xml-cdata", "]]>")); return null; } else { return "xml-text"; } } else if (source.lookAhead("--", true)) { setState(inBlock("xml-comment", "-->")); return null; } else if (source.lookAhead("DOCTYPE", true)) { source.nextWhileMatches(/[\w\._\-]/); setState(inBlock("xml-doctype", ">")); return "xml-doctype"; } else { return "xml-text"; } } else if (source.equals("?")) { source.next(); source.nextWhileMatches(/[\w\._\-]/); setState(inBlock("xml-processing", "?>")); return "xml-processing"; } else { if (source.equals("/")) source.next(); setState(inTag); return "xml-punctuation"; } } else if (ch == "&") { while (!source.endOfLine()) { if (source.next() == ";") break; } return "xml-entity"; } else { source.nextWhileMatches(/[^&<\n]/); return "xml-text"; } } function inTag(source, setState) { var ch = source.next(); if (ch == ">") { setState(inText); return "xml-punctuation"; } else if (/[?\/]/.test(ch) && source.equals(">")) { source.next(); setState(inText); return "xml-punctuation"; } else if (ch == "=") { return "xml-punctuation"; } else if (/[\'\"]/.test(ch)) { setState(inAttribute(ch)); return null; } else { source.nextWhileMatches(/[^\s\u00a0=<>\"\'\/?]/); return "xml-name"; } } function inAttribute(quote) { return function(source, setState) { while (!source.endOfLine()) { if (source.next() == quote) { setState(inTag); break; } } return "xml-attribute"; }; } function inBlock(style, terminator) { return function(source, setState) { while (!source.endOfLine()) { if (source.lookAhead(terminator, true)) { setState(inText); break; } source.next(); } return style; }; } return function(source, startState) { return tokenizer(source, startState || inText); }; })(); // The parser. The structure of this function largely follows that of // parseJavaScript in parsejavascript.js (there is actually a bit more // shared code than I'd like), but it is quite a bit simpler. function parseXML(source) { var tokens = tokenizeXML(source), token; var cc = [base]; var tokenNr = 0, indented = 0; var currentTag = null, context = null; var consume; function push(fs) { for (var i = fs.length - 1; i >= 0; i--) cc.push(fs[i]); } function cont() { push(arguments); consume = true; } function pass() { push(arguments); consume = false; } function markErr() { token.style += " xml-error"; } function expect(text) { return function(style, content) { if (content == text) cont(); else {markErr(); cont(arguments.callee);} }; } function pushContext(tagname, startOfLine) { var noIndent = UseKludges.doNotIndent.hasOwnProperty(tagname) || (context && context.noIndent); context = {prev: context, name: tagname, indent: indented, startOfLine: startOfLine, noIndent: noIndent}; } function popContext() { context = context.prev; } function computeIndentation(baseContext) { return function(nextChars, current) { var context = baseContext; if (context && context.noIndent) return current; if (alignCDATA && /")); else if (style == "xml-cdata") { if (!context || context.name != "!cdata") pushContext("!cdata"); if (/\]\]>$/.test(content)) popContext(); cont(); } else if (harmlessTokens.hasOwnProperty(style)) cont(); else {markErr(); cont();} } function tagname(style, content) { if (style == "xml-name") { currentTag = content.toLowerCase(); token.style = "xml-tagname"; cont(); } else { currentTag = null; pass(); } } function closetagname(style, content) { if (style == "xml-name") { token.style = "xml-tagname"; if (context && content.toLowerCase() == context.name) popContext(); else markErr(); } cont(); } function endtag(startOfLine) { return function(style, content) { if (content == "/>" || (content == ">" && UseKludges.autoSelfClosers.hasOwnProperty(currentTag))) cont(); else if (content == ">") {pushContext(currentTag, startOfLine); cont();} else {markErr(); cont(arguments.callee);} }; } function attributes(style) { if (style == "xml-name") {token.style = "xml-attname"; cont(attribute, attributes);} else pass(); } function attribute(style, content) { if (content == "=") cont(value); else if (content == ">" || content == "/>") pass(endtag); else pass(); } function value(style) { if (style == "xml-attribute") cont(value); else pass(); } return { indentation: function() {return indented;}, next: function(){ token = tokens.next(); if (token.style == "whitespace" && tokenNr == 0) indented = token.value.length; else tokenNr++; if (token.content == "\n") { indented = tokenNr = 0; token.indentation = computeIndentation(context); } if (token.style == "whitespace" || token.type == "xml-comment") return token; while(true){ consume = false; cc.pop()(token.style, token.content); if (consume) return token; } }, copy: function(){ var _cc = cc.concat([]), _tokenState = tokens.state, _context = context; var parser = this; return function(input){ cc = _cc.concat([]); tokenNr = indented = 0; context = _context; tokens = tokenizeXML(input, _tokenState); return parser; }; } }; } return { make: parseXML, electricChars: "/", configure: function(config) { if (config.useHTMLKludges != null) UseKludges = config.useHTMLKludges ? Kludges : NoKludges; if (config.alignCDATA) alignCDATA = config.alignCDATA; } }; })(); js/util.js000066600000007004151374226730006512 0ustar00/* A few useful utility functions. */ // Capture a method on an object. function method(obj, name) { return function() {obj[name].apply(obj, arguments);}; } // The value used to signal the end of a sequence in iterators. var StopIteration = {toString: function() {return "StopIteration"}}; // Apply a function to each element in a sequence. function forEach(iter, f) { if (iter.next) { try {while (true) f(iter.next());} catch (e) {if (e != StopIteration) throw e;} } else { for (var i = 0; i < iter.length; i++) f(iter[i]); } } // Map a function over a sequence, producing an array of results. function map(iter, f) { var accum = []; forEach(iter, function(val) {accum.push(f(val));}); return accum; } // Create a predicate function that tests a string againsts a given // regular expression. No longer used but might be used by 3rd party // parsers. function matcher(regexp){ return function(value){return regexp.test(value);}; } // Test whether a DOM node has a certain CSS class. function hasClass(element, className) { var classes = element.className; return classes && new RegExp("(^| )" + className + "($| )").test(classes); } function removeClass(element, className) { element.className = element.className.replace(new RegExp(" " + className + "\\b", "g"), ""); return element; } // Insert a DOM node after another node. function insertAfter(newNode, oldNode) { var parent = oldNode.parentNode; parent.insertBefore(newNode, oldNode.nextSibling); return newNode; } function removeElement(node) { if (node.parentNode) node.parentNode.removeChild(node); } function clearElement(node) { while (node.firstChild) node.removeChild(node.firstChild); } // Check whether a node is contained in another one. function isAncestor(node, child) { while (child = child.parentNode) { if (node == child) return true; } return false; } // The non-breaking space character. var nbsp = "\u00a0"; var matching = {"{": "}", "[": "]", "(": ")", "}": "{", "]": "[", ")": "("}; // Standardize a few unportable event properties. function normalizeEvent(event) { if (!event.stopPropagation) { event.stopPropagation = function() {this.cancelBubble = true;}; event.preventDefault = function() {this.returnValue = false;}; } if (!event.stop) { event.stop = function() { this.stopPropagation(); this.preventDefault(); }; } if (event.type == "keypress") { event.code = (event.charCode == null) ? event.keyCode : event.charCode; event.character = String.fromCharCode(event.code); } return event; } // Portably register event handlers. function addEventHandler(node, type, handler, removeFunc) { function wrapHandler(event) { handler(normalizeEvent(event || window.event)); } if (typeof node.addEventListener == "function") { node.addEventListener(type, wrapHandler, false); if (removeFunc) return function() {node.removeEventListener(type, wrapHandler, false);}; } else { node.attachEvent("on" + type, wrapHandler); if (removeFunc) return function() {node.detachEvent("on" + type, wrapHandler);}; } } function nodeText(node) { return node.textContent || node.innerText || node.nodeValue || ""; } function nodeTop(node) { var top = 0; while (node.offsetParent) { top += node.offsetTop; node = node.offsetParent; } return top; } function isBR(node) { var nn = node.nodeName; return nn == "BR" || nn == "br"; } function isSpan(node) { var nn = node.nodeName; return nn == "SPAN" || nn == "span"; } js/undo.js000066600000034251151374226730006506 0ustar00/** * Storage and control for undo information within a CodeMirror * editor. 'Why on earth is such a complicated mess required for * that?', I hear you ask. The goal, in implementing this, was to make * the complexity of storing and reverting undo information depend * only on the size of the edited or restored content, not on the size * of the whole document. This makes it necessary to use a kind of * 'diff' system, which, when applied to a DOM tree, causes some * complexity and hackery. * * In short, the editor 'touches' BR elements as it parses them, and * the UndoHistory stores these. When nothing is touched in commitDelay * milliseconds, the changes are committed: It goes over all touched * nodes, throws out the ones that did not change since last commit or * are no longer in the document, and assembles the rest into zero or * more 'chains' -- arrays of adjacent lines. Links back to these * chains are added to the BR nodes, while the chain that previously * spanned these nodes is added to the undo history. Undoing a change * means taking such a chain off the undo history, restoring its * content (text is saved per line) and linking it back into the * document. */ // A history object needs to know about the DOM container holding the // document, the maximum amount of undo levels it should store, the // delay (of no input) after which it commits a set of changes, and, // unfortunately, the 'parent' window -- a window that is not in // designMode, and on which setTimeout works in every browser. function UndoHistory(container, maxDepth, commitDelay, editor) { this.container = container; this.maxDepth = maxDepth; this.commitDelay = commitDelay; this.editor = editor; // This line object represents the initial, empty editor. var initial = {text: "", from: null, to: null}; // As the borders between lines are represented by BR elements, the // start of the first line and the end of the last one are // represented by null. Since you can not store any properties // (links to line objects) in null, these properties are used in // those cases. this.first = initial; this.last = initial; // Similarly, a 'historyTouched' property is added to the BR in // front of lines that have already been touched, and 'firstTouched' // is used for the first line. this.firstTouched = false; // History is the set of committed changes, touched is the set of // nodes touched since the last commit. this.history = []; this.redoHistory = []; this.touched = []; this.lostundo = 0; } UndoHistory.prototype = { // Schedule a commit (if no other touches come in for commitDelay // milliseconds). scheduleCommit: function() { var self = this; parent.clearTimeout(this.commitTimeout); this.commitTimeout = parent.setTimeout(function(){self.tryCommit();}, this.commitDelay); }, // Mark a node as touched. Null is a valid argument. touch: function(node) { this.setTouched(node); this.scheduleCommit(); }, // Undo the last change. undo: function() { // Make sure pending changes have been committed. this.commit(); if (this.history.length) { // Take the top diff from the history, apply it, and store its // shadow in the redo history. var item = this.history.pop(); this.redoHistory.push(this.updateTo(item, "applyChain")); this.notifyEnvironment(); return this.chainNode(item); } }, // Redo the last undone change. redo: function() { this.commit(); if (this.redoHistory.length) { // The inverse of undo, basically. var item = this.redoHistory.pop(); this.addUndoLevel(this.updateTo(item, "applyChain")); this.notifyEnvironment(); return this.chainNode(item); } }, clear: function() { this.history = []; this.redoHistory = []; this.lostundo = 0; }, // Ask for the size of the un/redo histories. historySize: function() { return {undo: this.history.length, redo: this.redoHistory.length, lostundo: this.lostundo}; }, // Push a changeset into the document. push: function(from, to, lines) { var chain = []; for (var i = 0; i < lines.length; i++) { var end = (i == lines.length - 1) ? to : document.createElement("br"); chain.push({from: from, to: end, text: cleanText(lines[i])}); from = end; } this.pushChains([chain], from == null && to == null); this.notifyEnvironment(); }, pushChains: function(chains, doNotHighlight) { this.commit(doNotHighlight); this.addUndoLevel(this.updateTo(chains, "applyChain")); this.redoHistory = []; }, // Retrieve a DOM node from a chain (for scrolling to it after undo/redo). chainNode: function(chains) { for (var i = 0; i < chains.length; i++) { var start = chains[i][0], node = start && (start.from || start.to); if (node) return node; } }, // Clear the undo history, make the current document the start // position. reset: function() { this.history = []; this.redoHistory = []; this.lostundo = 0; }, textAfter: function(br) { return this.after(br).text; }, nodeAfter: function(br) { return this.after(br).to; }, nodeBefore: function(br) { return this.before(br).from; }, // Commit unless there are pending dirty nodes. tryCommit: function() { if (!window || !window.parent || !window.UndoHistory) return; // Stop when frame has been unloaded if (this.editor.highlightDirty()) this.commit(true); else this.scheduleCommit(); }, // Check whether the touched nodes hold any changes, if so, commit // them. commit: function(doNotHighlight) { parent.clearTimeout(this.commitTimeout); // Make sure there are no pending dirty nodes. if (!doNotHighlight) this.editor.highlightDirty(true); // Build set of chains. var chains = this.touchedChains(), self = this; if (chains.length) { this.addUndoLevel(this.updateTo(chains, "linkChain")); this.redoHistory = []; this.notifyEnvironment(); } }, // [ end of public interface ] // Update the document with a given set of chains, return its // shadow. updateFunc should be "applyChain" or "linkChain". In the // second case, the chains are taken to correspond the the current // document, and only the state of the line data is updated. In the // first case, the content of the chains is also pushed iinto the // document. updateTo: function(chains, updateFunc) { var shadows = [], dirty = []; for (var i = 0; i < chains.length; i++) { shadows.push(this.shadowChain(chains[i])); dirty.push(this[updateFunc](chains[i])); } if (updateFunc == "applyChain") this.notifyDirty(dirty); return shadows; }, // Notify the editor that some nodes have changed. notifyDirty: function(nodes) { forEach(nodes, method(this.editor, "addDirtyNode")) this.editor.scheduleHighlight(); }, notifyEnvironment: function() { if (this.onChange) this.onChange(this.editor); // Used by the line-wrapping line-numbering code. if (window.frameElement && window.frameElement.CodeMirror.updateNumbers) window.frameElement.CodeMirror.updateNumbers(); }, // Link a chain into the DOM nodes (or the first/last links for null // nodes). linkChain: function(chain) { for (var i = 0; i < chain.length; i++) { var line = chain[i]; if (line.from) line.from.historyAfter = line; else this.first = line; if (line.to) line.to.historyBefore = line; else this.last = line; } }, // Get the line object after/before a given node. after: function(node) { return node ? node.historyAfter : this.first; }, before: function(node) { return node ? node.historyBefore : this.last; }, // Mark a node as touched if it has not already been marked. setTouched: function(node) { if (node) { if (!node.historyTouched) { this.touched.push(node); node.historyTouched = true; } } else { this.firstTouched = true; } }, // Store a new set of undo info, throw away info if there is more of // it than allowed. addUndoLevel: function(diffs) { this.history.push(diffs); if (this.history.length > this.maxDepth) { this.history.shift(); this.lostundo += 1; } }, // Build chains from a set of touched nodes. touchedChains: function() { var self = this; // The temp system is a crummy hack to speed up determining // whether a (currently touched) node has a line object associated // with it. nullTemp is used to store the object for the first // line, other nodes get it stored in their historyTemp property. var nullTemp = null; function temp(node) {return node ? node.historyTemp : nullTemp;} function setTemp(node, line) { if (node) node.historyTemp = line; else nullTemp = line; } function buildLine(node) { var text = []; for (var cur = node ? node.nextSibling : self.container.firstChild; cur && (!isBR(cur) || cur.hackBR); cur = cur.nextSibling) if (!cur.hackBR && cur.currentText) text.push(cur.currentText); return {from: node, to: cur, text: cleanText(text.join(""))}; } // Filter out unchanged lines and nodes that are no longer in the // document. Build up line objects for remaining nodes. var lines = []; if (self.firstTouched) self.touched.push(null); forEach(self.touched, function(node) { if (node && (node.parentNode != self.container || node.hackBR)) return; if (node) node.historyTouched = false; else self.firstTouched = false; var line = buildLine(node), shadow = self.after(node); if (!shadow || shadow.text != line.text || shadow.to != line.to) { lines.push(line); setTemp(node, line); } }); // Get the BR element after/before the given node. function nextBR(node, dir) { var link = dir + "Sibling", search = node[link]; while (search && !isBR(search)) search = search[link]; return search; } // Assemble line objects into chains by scanning the DOM tree // around them. var chains = []; self.touched = []; forEach(lines, function(line) { // Note that this makes the loop skip line objects that have // been pulled into chains by lines before them. if (!temp(line.from)) return; var chain = [], curNode = line.from, safe = true; // Put any line objects (referred to by temp info) before this // one on the front of the array. while (true) { var curLine = temp(curNode); if (!curLine) { if (safe) break; else curLine = buildLine(curNode); } chain.unshift(curLine); setTemp(curNode, null); if (!curNode) break; safe = self.after(curNode); curNode = nextBR(curNode, "previous"); } curNode = line.to; safe = self.before(line.from); // Add lines after this one at end of array. while (true) { if (!curNode) break; var curLine = temp(curNode); if (!curLine) { if (safe) break; else curLine = buildLine(curNode); } chain.push(curLine); setTemp(curNode, null); safe = self.before(curNode); curNode = nextBR(curNode, "next"); } chains.push(chain); }); return chains; }, // Find the 'shadow' of a given chain by following the links in the // DOM nodes at its start and end. shadowChain: function(chain) { var shadows = [], next = this.after(chain[0].from), end = chain[chain.length - 1].to; while (true) { shadows.push(next); var nextNode = next.to; if (!nextNode || nextNode == end) break; else next = nextNode.historyAfter || this.before(end); // (The this.before(end) is a hack -- FF sometimes removes // properties from BR nodes, in which case the best we can hope // for is to not break.) } return shadows; }, // Update the DOM tree to contain the lines specified in a given // chain, link this chain into the DOM nodes. applyChain: function(chain) { // Some attempt is made to prevent the cursor from jumping // randomly when an undo or redo happens. It still behaves a bit // strange sometimes. var cursor = select.cursorPos(this.container, false), self = this; // Remove all nodes in the DOM tree between from and to (null for // start/end of container). function removeRange(from, to) { var pos = from ? from.nextSibling : self.container.firstChild; while (pos != to) { var temp = pos.nextSibling; removeElement(pos); pos = temp; } } var start = chain[0].from, end = chain[chain.length - 1].to; // Clear the space where this change has to be made. removeRange(start, end); // Insert the content specified by the chain into the DOM tree. for (var i = 0; i < chain.length; i++) { var line = chain[i]; // The start and end of the space are already correct, but BR // tags inside it have to be put back. if (i > 0) self.container.insertBefore(line.from, end); // Add the text. var node = makePartSpan(fixSpaces(line.text)); self.container.insertBefore(node, end); // See if the cursor was on this line. Put it back, adjusting // for changed line length, if it was. if (cursor && cursor.node == line.from) { var cursordiff = 0; var prev = this.after(line.from); if (prev && i == chain.length - 1) { // Only adjust if the cursor is after the unchanged part of // the line. for (var match = 0; match < cursor.offset && line.text.charAt(match) == prev.text.charAt(match); match++){} if (cursor.offset > match) cursordiff = line.text.length - prev.text.length; } select.setCursorPos(this.container, {node: line.from, offset: Math.max(0, cursor.offset + cursordiff)}); } // Cursor was in removed line, this is last new line. else if (cursor && (i == chain.length - 1) && cursor.node && cursor.node.parentNode != this.container) { select.setCursorPos(this.container, {node: line.from, offset: line.text.length}); } } // Anchor the chain in the DOM tree. this.linkChain(chain); return start; } }; js/parsehtmlmixed.js000066600000005247151374226730010572 0ustar00var HTMLMixedParser = Editor.Parser = (function() { // tags that trigger seperate parsers var triggers = { "script": "JSParser", "style": "CSSParser" }; function checkDependencies() { var parsers = ['XMLParser']; for (var p in triggers) parsers.push(triggers[p]); for (var i in parsers) { if (!window[parsers[i]]) throw new Error(parsers[i] + " parser must be loaded for HTML mixed mode to work."); } XMLParser.configure({useHTMLKludges: true}); } function parseMixed(stream) { checkDependencies(); var htmlParser = XMLParser.make(stream), localParser = null, inTag = false; var iter = {next: top, copy: copy}; function top() { var token = htmlParser.next(); if (token.content == "<") inTag = true; else if (token.style == "xml-tagname" && inTag === true) inTag = token.content.toLowerCase(); else if (token.content == ">") { if (triggers[inTag]) { var parser = window[triggers[inTag]]; iter.next = local(parser, " Parse function for PHP. Makes use of the tokenizer from tokenizephp.js. Based on parsejavascript.js by Marijn Haverbeke. Features: + special "deprecated" style for PHP4 keywords like 'var' + support for PHP 5.3 keywords: 'namespace', 'use' + 911 predefined constants, 1301 predefined functions, 105 predeclared classes from a typical PHP installation in a LAMP environment + new feature: syntax error flagging, thus enabling strict parsing of: + function definitions with explicitly or implicitly typed arguments and default values + modifiers (public, static etc.) applied to method and member definitions + foreach(array_expression as $key [=> $value]) loops + differentiation between single-quoted strings and double-quoted interpolating strings */ // add the Array.indexOf method for JS engines that don't support it (e.g. IE) // code from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array/IndexOf if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(elt /*, from*/) { var len = this.length; var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++) { if (from in this && this[from] === elt) return from; } return -1; }; } var PHPParser = Editor.Parser = (function() { // Token types that can be considered to be atoms, part of operator expressions var atomicTypes = { "atom": true, "number": true, "variable": true, "string": true }; // Constructor for the lexical context objects. function PHPLexical(indented, column, type, align, prev, info) { // indentation at start of this line this.indented = indented; // column at which this scope was opened this.column = column; // type of scope ('stat' (statement), 'form' (special form), '[', '{', or '(') this.type = type; // '[', '{', or '(' blocks that have any text after their opening // character are said to be 'aligned' -- any lines below are // indented all the way to the opening character. if (align != null) this.align = align; // Parent scope, if any. this.prev = prev; this.info = info; } // PHP indentation rules function indentPHP(lexical) { return function(firstChars) { var firstChar = firstChars && firstChars.charAt(0), type = lexical.type; var closing = firstChar == type; if (type == "form" && firstChar == "{") return lexical.indented; else if (type == "stat" || type == "form") return lexical.indented + indentUnit; else if (lexical.info == "switch" && !closing) return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit); else if (lexical.align) return lexical.column - (closing ? 1 : 0); else return lexical.indented + (closing ? 0 : indentUnit); }; } // The parser-iterator-producing function itself. function parsePHP(input, basecolumn) { // Wrap the input in a token stream var tokens = tokenizePHP(input); // The parser state. cc is a stack of actions that have to be // performed to finish the current statement. For example we might // know that we still need to find a closing parenthesis and a // semicolon. Actions at the end of the stack go first. It is // initialized with an infinitely looping action that consumes // whole statements. var cc = [statements]; // The lexical scope, used mostly for indentation. var lexical = new PHPLexical((basecolumn || 0) - indentUnit, 0, "block", false); // Current column, and the indentation at the start of the current // line. Used to create lexical scope objects. var column = 0; var indented = 0; // Variables which are used by the mark, cont, and pass functions // below to communicate with the driver loop in the 'next' function. var consume, marked; // The iterator object. var parser = {next: next, copy: copy}; // parsing is accomplished by calling next() repeatedly function next(){ // Start by performing any 'lexical' actions (adjusting the // lexical variable), or the operations below will be working // with the wrong lexical state. while(cc[cc.length - 1].lex) cc.pop()(); // Fetch the next token. var token = tokens.next(); // Adjust column and indented. if (token.type == "whitespace" && column == 0) indented = token.value.length; column += token.value.length; if (token.content == "\n"){ indented = column = 0; // If the lexical scope's align property is still undefined at // the end of the line, it is an un-aligned scope. if (!("align" in lexical)) lexical.align = false; // Newline tokens get an indentation function associated with // them. token.indentation = indentPHP(lexical); } // No more processing for meaningless tokens. if (token.type == "whitespace" || token.type == "comment" || token.type == "string_not_terminated" ) return token; // When a meaningful token is found and the lexical scope's // align is undefined, it is an aligned scope. if (!("align" in lexical)) lexical.align = true; // Execute actions until one 'consumes' the token and we can // return it. 'marked' is used to change the style of the current token. while(true) { consume = marked = false; // Take and execute the topmost action. var action = cc.pop(); action(token); if (consume){ if (marked) token.style = marked; // Here we differentiate between local and global variables. return token; } } return 1; // Firebug workaround for http://code.google.com/p/fbug/issues/detail?id=1239#c1 } // This makes a copy of the parser state. It stores all the // stateful variables in a closure, and returns a function that // will restore them when called with a new input stream. Note // that the cc array has to be copied, because it is contantly // being modified. Lexical objects are not mutated, so they can // be shared between runs of the parser. function copy(){ var _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state; return function copyParser(input){ lexical = _lexical; cc = _cc.concat([]); // copies the array column = indented = 0; tokens = tokenizePHP(input, _tokenState); return parser; }; } // Helper function for pushing a number of actions onto the cc // stack in reverse order. function push(fs){ for (var i = fs.length - 1; i >= 0; i--) cc.push(fs[i]); } // cont and pass are used by the action functions to add other // actions to the stack. cont will cause the current token to be // consumed, pass will leave it for the next action. function cont(){ push(arguments); consume = true; } function pass(){ push(arguments); consume = false; } // Used to change the style of the current token. function mark(style){ marked = style; } // Add a lyer of style to the current token, for example syntax-error function mark_add(style){ marked = marked + ' ' + style; } // Push a new lexical context of the given type. function pushlex(type, info) { var result = function pushlexing() { lexical = new PHPLexical(indented, column, type, null, lexical, info) }; result.lex = true; return result; } // Pop off the current lexical context. function poplex(){ if (lexical.prev) lexical = lexical.prev; } poplex.lex = true; // The 'lex' flag on these actions is used by the 'next' function // to know they can (and have to) be ran before moving on to the // next token. // Creates an action that discards tokens until it finds one of // the given type. This will ignore (and recover from) syntax errors. function expect(wanted){ return function expecting(token){ if (token.type == wanted) cont(); // consume the token else { cont(arguments.callee); // continue expecting() - call itself } }; } // Require a specific token type, or one of the tokens passed in the 'wanted' array // Used to detect blatant syntax errors. 'execute' is used to pass extra code // to be executed if the token is matched. For example, a '(' match could // 'execute' a cont( compasep(funcarg), require(")") ) function require(wanted, execute){ return function requiring(token){ var ok; var type = token.type; if (typeof(wanted) == "string") ok = (type == wanted) -1; else ok = wanted.indexOf(type); if (ok >= 0) { if (execute && typeof(execute[ok]) == "function") pass(execute[ok]); else cont(); } else { if (!marked) mark(token.style); mark_add("syntax-error"); cont(arguments.callee); } }; } // Looks for a statement, and then calls itself. function statements(token){ return pass(statement, statements); } // Dispatches various types of statements based on the type of the current token. function statement(token){ var type = token.type; if (type == "keyword a") cont(pushlex("form"), expression, altsyntax, statement, poplex); else if (type == "keyword b") cont(pushlex("form"), altsyntax, statement, poplex); else if (type == "{") cont(pushlex("}"), block, poplex); else if (type == "function") funcdef(); // technically, "class implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function else if (type == "class") classdef(); else if (type == "foreach") cont(pushlex("form"), require("("), pushlex(")"), expression, require("as"), require("variable"), /* => $value */ expect(")"), altsyntax, poplex, statement, poplex); else if (type == "for") cont(pushlex("form"), require("("), pushlex(")"), expression, require(";"), expression, require(";"), expression, require(")"), altsyntax, poplex, statement, poplex); // public final function foo(), protected static $bar; else if (type == "modifier") cont(require(["modifier", "variable", "function", "abstract"], [null, commasep(require("variable")), funcdef, absfun])); else if (type == "abstract") abs(); else if (type == "switch") cont(pushlex("form"), require("("), expression, require(")"), pushlex("}", "switch"), require([":", "{"]), block, poplex, poplex); else if (type == "case") cont(expression, require(":")); else if (type == "default") cont(require(":")); else if (type == "catch") cont(pushlex("form"), require("("), require("t_string"), require("variable"), require(")"), statement, poplex); else if (type == "const") cont(require("t_string")); // 'const static x=5' is a syntax error // technically, "namespace implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function else if (type == "namespace") cont(namespacedef, require(";")); // $variables may be followed by operators, () for variable function calls, or [] subscripts else pass(pushlex("stat"), expression, require(";"), poplex); } // Dispatch expression types. function expression(token){ var type = token.type; if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator); else if (type == "<<<") cont(require("string"), maybeoperator); // heredoc/nowdoc else if (type == "t_string") cont(maybe_double_colon, maybeoperator); else if (type == "keyword c" || type == "operator") cont(expression); // lambda else if (type == "function") lambdadef(); // function call or parenthesized expression: $a = ($b + 1) * 2; else if (type == "(") cont(pushlex(")"), commasep(expression), require(")"), poplex, maybeoperator); } // Called for places where operators, function calls, or subscripts are // valid. Will skip on to the next action if none is found. function maybeoperator(token){ var type = token.type; if (type == "operator") { if (token.content == "?") cont(expression, require(":"), expression); // ternary operator else cont(expression); } else if (type == "(") cont(pushlex(")"), expression, commasep(expression), require(")"), poplex, maybeoperator /* $varfunc() + 3 */); else if (type == "[") cont(pushlex("]"), expression, require("]"), maybeoperator /* for multidimensional arrays, or $func[$i]() */, poplex); } // A regular use of the double colon to specify a class, as in self::func() or myclass::$var; // Differs from `namespace` or `use` in that only one class can be the parent; chains (A::B::$var) are a syntax error. function maybe_double_colon(token) { if (token.type == "t_double_colon") // A::$var, A::func(), A::const cont(require(["t_string", "variable"]), maybeoperator); else { // a t_string wasn't followed by ::, such as in a function call: foo() pass(expression) } } // the declaration or definition of a function function funcdef() { cont(require("t_string"), require("("), pushlex(")"), commasep(funcarg), require(")"), poplex, block); } // the declaration or definition of a lambda function lambdadef() { cont(require("("), pushlex(")"), commasep(funcarg), require(")"), maybe_lambda_use, poplex, require("{"), pushlex("}"), block, poplex); } // optional lambda 'use' statement function maybe_lambda_use(token) { if(token.type == "namespace") { cont(require('('), commasep(funcarg), require(')')); } else { pass(expression); } } // the definition of a class function classdef() { cont(require("t_string"), expect("{"), pushlex("}"), block, poplex); } // either funcdef if the current token is "function", or the keyword "function" + funcdef function absfun(token) { if(token.type == "function") funcdef(); else cont(require(["function"], [funcdef])); } // the abstract class or function (with optional modifier) function abs(token) { cont(require(["modifier", "function", "class"], [absfun, funcdef, classdef])); } // Parses a comma-separated list of the things that are recognized // by the 'what' argument. function commasep(what){ function proceed(token) { if (token.type == ",") cont(what, proceed); } return function commaSeparated() { pass(what, proceed); }; } // Look for statements until a closing brace is found. function block(token) { if (token.type == "}") cont(); else pass(statement, block); } function empty_parens_if_array(token) { if(token.content == "array") cont(require("("), require(")")); } function maybedefaultparameter(token){ if (token.content == "=") cont(require(["t_string", "string", "number", "atom"], [empty_parens_if_array, null, null])); } function var_or_reference(token) { if(token.type == "variable") cont(maybedefaultparameter); else if(token.content == "&") cont(require("variable"), maybedefaultparameter); } // support for default arguments: http://us.php.net/manual/en/functions.arguments.php#functions.arguments.default function funcarg(token){ // function foo(myclass $obj) {...} or function foo(myclass &objref) {...} if (token.type == "t_string") cont(var_or_reference); // function foo($var) {...} or function foo(&$ref) {...} else var_or_reference(token); } // A namespace definition or use function maybe_double_colon_def(token) { if (token.type == "t_double_colon") cont(namespacedef); } function namespacedef(token) { pass(require("t_string"), maybe_double_colon_def); } function altsyntax(token){ if(token.content==':') cont(altsyntaxBlock,poplex); } function altsyntaxBlock(token){ if (token.type == "altsyntaxend") cont(require(';')); else pass(statement, altsyntaxBlock); } return parser; } return {make: parsePHP, electricChars: "{}:"}; })(); js/basefiles.js000066600000126710151374226730007500 0ustar00var internetExplorer=document.selection&&window.ActiveXObject&&/MSIE/.test(navigator.userAgent),webkit=/AppleWebKit/.test(navigator.userAgent),safari=/Apple Computer, Inc/.test(navigator.vendor),gecko=navigator.userAgent.match(/gecko\/(\d{8})/i);if(gecko)gecko=Number(gecko[1]);var mac=/Mac/.test(navigator.platform),brokenOpera=window.opera&&/Version\/10.[56]/.test(navigator.userAgent),slowWebkit=/AppleWebKit\/533/.test(navigator.userAgent); function makeWhiteSpace(f){for(var l=[],k=true;f>0;f--){l.push(k||f==1?nbsp:" ");k^=true}return l.join("")}function fixSpaces(f){if(f.charAt(0)==" ")f=nbsp+f.slice(1);return f.replace(/\t/g,function(){return makeWhiteSpace(indentUnit)}).replace(/[ \u00a0]{2,}/g,function(l){return makeWhiteSpace(l.length)})}function cleanText(f){return f.replace(/\u00a0/g," ").replace(/\u200b/g,"")} function makePartSpan(f){var l=f;if(f.nodeType==3)l=f.nodeValue;else f=document.createTextNode(l);var k=document.createElement("span");k.isPart=true;k.appendChild(f);k.currentText=l;return k}function alwaysZero(){return 0}var webkitLastLineHack=webkit?function(f){var l=f.lastChild;if(!l||!l.hackBR){l=document.createElement("br");l.hackBR=true;f.appendChild(l)}}:function(){}; function asEditorLines(f){var l=makeWhiteSpace(indentUnit);return map(f.replace(/\t/g,l).replace(/\u00a0/g," ").replace(/\r\n?/g,"\n").split("\n"),fixSpaces)} var Editor=function(){function f(a,d){function g(e,h){if(e.nodeType==3){if((e.nodeValue=fixSpaces(e.nodeValue.replace(/[\r\u200b]/g,"").replace(/\n/g," "))).length)c=false;b.push(e)}else if(isBR(e)&&e.childNodes.length==0){c=true;b.push(e)}else{for(var j=e.firstChild;j;j=j.nextSibling)g(j);if(!c&&w.hasOwnProperty(e.nodeName.toUpperCase())){c=true;if(!d||!h)b.push(document.createElement("br"))}}}var b=[],c=true;g(a,true);return b}function l(a){function d(e){var h=e.parentNode,j=e.nextSibling;return function(i){h.insertBefore(i, j)}}var g=[],b=null,c=true;return{next:function(){if(!a)throw StopIteration;var e=a;a=e.nextSibling;var h;if(e.isPart&&e.childNodes.length==1&&e.firstChild.nodeType==3){h=e.firstChild.nodeValue;e.dirty=e.dirty||h!=e.currentText;e.currentText=h;h=!/[\n\t\r]/.test(e.currentText)}else h=false;if(h){g.push(e);c=false;return e.currentText}else if(isBR(e)){c&&window.opera&&e.parentNode.insertBefore(makePartSpan(""),e);g.push(e);c=true;return"\n"}else{h=!e.nextSibling;b=d(e);removeElement(e);e=f(e,h);for(h= 0;h=o&&(u=t.lastIndexOf(d,r-o))!=-1:(u=t.indexOf(d,r))!=-1)return{from:{node:n,offset:u},to:{node:n,offset:u+o}}}:function(i, n,r){var t=i?j.length-1:0,o=j[t],u=c(n),x=i?u.indexOf(o)+o.length:u.lastIndexOf(o);if(!(i?x>=r||x!=o.length:x<=r||x!=u.length-o.length))for(r=n;;){if(i&&!r)break;r=i?this.history.nodeBefore(r):this.history.nodeAfter(r);if(!i&&!r)break;u=c(r);o=j[i?--t:++t];if(t>0&&td){b=c.nextSibling;g=e.slice(0,d)+g+e.slice(d);removeElement(c);break}d-=e.length}d=asEditorLines(g);for(g=0;g0&&this.container.insertBefore(document.createElement("BR"),b);this.container.insertBefore(makePartSpan(d[g]),b)}this.addDirtyNode(a);this.scheduleHighlight()},selectedText:function(){var a=this.history;a.commit();var d=select.cursorPos(this.container,true),g=select.cursorPos(this.container, false);if(!d||!g)return"";if(d.node==g.node)return a.textAfter(d.node).slice(d.offset,g.offset);var b=[a.textAfter(d.node).slice(d.offset)];for(d=a.nodeAfter(d.node);d!=g.node;d=a.nodeAfter(d))b.push(a.textAfter(d));b.push(a.textAfter(g.node).slice(0,g.offset));return cleanText(b.join("\n"))},replaceSelection:function(a){this.history.commit();var d=select.cursorPos(this.container,true),g=select.cursorPos(this.container,false);if(d&&g){g=this.replaceRange(d,g,a);select.setCursorPos(this.container, g);webkitLastLineHack(this.container)}},cursorCoords:function(a,d){function g(i,n){var r=-(document.body.scrollTop||document.documentElement.scrollTop||0),t=-(document.body.scrollLeft||document.documentElement.scrollLeft||0)+n;forEach([i,d?null:window.frameElement],function(o){for(;o;){t+=o.offsetLeft;r+=o.offsetTop;o=o.offsetParent}});return{x:t,y:r,yBot:r+i.offsetHeight}}function b(i,n){var r=document.createElement("SPAN");r.appendChild(document.createTextNode(i));try{return n(r)}finally{r.parentNode&& r.parentNode.removeChild(r)}}var c=select.cursorPos(this.container,a);if(!c)return null;for(var e=c.offset,h=c.node,j=this;e;){h=h?h.nextSibling:this.container.firstChild;c=nodeText(h);if(e=20101026)){this.capturingPaste=true;var a=window.frameElement.CodeMirror.textareaHack,d=this.cursorCoords(true,true);a.style.top=d.y+"px";if(internetExplorer)if(d=select.getBookmark(this.container))this.selectionSnapshot=d;parent.focus();a.value="";a.focus();var g=this;parent.setTimeout(function(){g.capturingPaste= false;window.focus();g.selectionSnapshot&&window.select.setBookmark(g.container,g.selectionSnapshot);var b=a.value;if(b){g.replaceSelection(b);select.scrollToCursor(g.container)}},10)}},replaceRange:function(a,d,g){g=asEditorLines(g);g[0]=this.history.textAfter(a.node).slice(0,a.offset)+g[0];var b=g[g.length-1];g[g.length-1]=b+this.history.textAfter(d.node).slice(d.offset);d=this.history.nodeAfter(d.node);this.history.push(a.node,d,g);return{node:this.history.nodeBefore(d),offset:b.length}},getSearchCursor:function(a, d,g){return new q(this,a,d,g)},reindent:function(){this.container.firstChild&&this.indentRegion(null,this.container.lastChild)},reindentSelection:function(a){if(select.somethingSelected()){var d=select.selectionTopNode(this.container,true),g=select.selectionTopNode(this.container,false);d===false||g===false||this.indentRegion(d,g,a,true)}else this.indentAtCursor(a)},grabKeys:function(a,d){this.frozen=a;this.keyFilter=d},ungrabKeys:function(){this.frozen="leave"},setParser:function(a,d){p.Parser=window[a]; (d=d||this.options.parserConfig)&&p.Parser.configure&&p.Parser.configure(d);if(this.container.firstChild){forEach(this.container.childNodes,function(g){if(g.nodeType!=3)g.dirty=true});this.addDirtyNode(this.firstChild);this.scheduleHighlight()}},keyDown:function(a){if(this.frozen=="leave")this.keyFilter=this.frozen=null;if(this.frozen&&(!this.keyFilter||this.keyFilter(a.keyCode,a))){a.stop();this.frozen(a)}else{var d=a.keyCode;this.delayScanning();this.options.autoMatchParens&&this.scheduleParenHighlight(); if(d==13){if(a.ctrlKey&&!a.altKey)this.reparseBuffer();else{select.insertNewlineAtCursor();d=this.options.enterMode;if(d!="flat")this.indentAtCursor(d=="keep"?"keep":undefined);select.scrollToCursor(this.container)}a.stop()}else if(d==9&&this.options.tabMode!="default"&&!a.ctrlKey){this.handleTab(!a.shiftKey);a.stop()}else if(d==32&&a.shiftKey&&this.options.tabMode=="default"){this.handleTab(true);a.stop()}else if(d==36&&!a.shiftKey&&!a.ctrlKey)this.home()&&a.stop();else if(d==35&&!a.shiftKey&&!a.ctrlKey)this.end()&& a.stop();else if(d==33&&!a.shiftKey&&!a.ctrlKey&&!gecko)this.pageUp()&&a.stop();else if(d==34&&!a.shiftKey&&!a.ctrlKey&&!gecko)this.pageDown()&&a.stop();else if((d==219||d==221)&&a.ctrlKey&&!a.altKey){this.highlightParens(a.shiftKey,true);a.stop()}else if(a.metaKey&&!a.shiftKey&&(d==37||d==39)){var g=select.selectionTopNode(this.container);if(!(g===false||!this.container.firstChild)){if(d==37)select.focusAfterNode(k(g),this.container);else{d=m(g,this.container);select.focusAfterNode(d?d.previousSibling: this.container.lastChild,this.container)}a.stop()}}else if((a.ctrlKey||a.metaKey)&&!a.altKey)if(a.shiftKey&&d==90||d==89){select.scrollToNode(this.history.redo());a.stop()}else if(d==90||safari&&d==8){select.scrollToNode(this.history.undo());a.stop()}else if(d==83&&this.options.saveFunction){this.options.saveFunction();a.stop()}else d==86&&!mac&&this.reroutePasteEvent()}},keyPress:function(a){var d=this.options.electricChars&&p.Parser.electricChars,g=this;if(this.frozen&&(!this.keyFilter||this.keyFilter(a.keyCode|| a.code,a))||a.code==13||a.code==9&&this.options.tabMode!="default"||a.code==32&&a.shiftKey&&this.options.tabMode=="default")a.stop();else if(mac&&(a.ctrlKey||a.metaKey)&&a.character=="v")this.reroutePasteEvent();else if(d&&d.indexOf(a.character)!=-1)parent.setTimeout(function(){g.indentAtCursor(null)},0);else if(brokenOpera)if(a.code==8){var b=select.selectionTopNode(this.container);g=this;var c=b?b.nextSibling:this.container.firstChild;b!==false&&c&&isBR(c)&&parent.setTimeout(function(){select.selectionTopNode(g.container)== c&&select.focusAfterNode(c.previousSibling,g.container)},20)}else{if(a.code==46){b=select.selectionTopNode(this.container);g=this;b&&isBR(b)&&parent.setTimeout(function(){select.selectionTopNode(g.container)!=b&&select.focusAfterNode(b,g.container)},20)}}else if(slowWebkit){c=(b=select.selectionTopNode(this.container))?b.nextSibling:this.container.firstChild;if(b&&c&&isBR(c)&&!isBR(b)){var e=document.createTextNode("\u200b");this.container.insertBefore(e,c);parent.setTimeout(function(){if(e.nodeValue== "\u200b")removeElement(e);else e.nodeValue=e.nodeValue.replace("\u200b","")},20)}}webkit&&!this.options.textWrapping&&setTimeout(function(){var h=select.selectionTopNode(g.container,true);h&&h.nodeType==3&&h.previousSibling&&isBR(h.previousSibling)&&h.nextSibling&&isBR(h.nextSibling)&&h.parentNode.replaceChild(document.createElement("BR"),h.previousSibling)},50)},keyUp:function(a){this.cursorActivity(a.keyCode>=16&&a.keyCode<=18||a.keyCode>=33&&a.keyCode<=40)},indentLineAfter:function(a,d){function g(n){n= n?n.nextSibling:b.container.firstChild;if(!n||!hasClass(n,"whitespace"))return null;return n}var b=this,c=g(a),e=0,h=c?c.currentText.length:0,j=c?c.nextSibling:a?a.nextSibling:this.container.firstChild;if(d=="keep"){if(a){var i=g(k(a.previousSibling));if(i)e=i.currentText.length}}else{i=a&&j&&j.currentText?j.currentText:"";if(d!=null&&this.options.tabMode!="indent")e=d?h+indentUnit:Math.max(0,h-indentUnit);else if(a)e=a.indentation(i,h,d,j);else if(p.Parser.firstIndentation)e=p.Parser.firstIndentation(i, h,d,j)}h=e-h;if(h<0)if(e==0){if(j)select.snapshotMove(c.firstChild,j.firstChild||j,0);removeElement(c);c=null}else{select.snapshotMove(c.firstChild,c.firstChild,h,true);c.currentText=makeWhiteSpace(e);c.firstChild.nodeValue=c.currentText}else if(h>0)if(c){c.currentText=makeWhiteSpace(e);c.firstChild.nodeValue=c.currentText;select.snapshotMove(c.firstChild,c.firstChild,h,true)}else{c=makePartSpan(makeWhiteSpace(e));c.className="whitespace";a?insertAfter(c,a):this.container.insertBefore(c,this.container.firstChild); select.snapshotMove(j&&(j.firstChild||j),c.firstChild,e,false,true)}else c&&select.snapshotMove(c.firstChild,c.firstChild,e,false);h!=0&&this.addDirtyNode(a)},highlightAtCursor:function(){var a=select.selectionTopNode(this.container,true),d=select.selectionTopNode(this.container,false);if(a===false||d===false)return false;select.markSelection();if(this.highlight(a,m(d,this.container),true,20)===false)return false;select.selectMarked();return true},handleTab:function(a){this.options.tabMode=="spaces"&& !select.somethingSelected()?select.insertTabAtCursor():this.reindentSelection(a)},home:function(){var a=select.selectionTopNode(this.container,true),d=a;if(a===false||!(!a||a.isPart||isBR(a))||!this.container.firstChild)return false;for(;a&&!isBR(a);)a=a.previousSibling;var g=a?a.nextSibling:this.container.firstChild;g&&g!=d&&g.isPart&&hasClass(g,"whitespace")?select.focusAfterNode(g,this.container):select.focusAfterNode(a,this.container);select.scrollToCursor(this.container);return true},end:function(){var a= select.selectionTopNode(this.container,true);if(a===false)return false;a=m(a,this.container);if(!a)return false;select.focusAfterNode(a.previousSibling,this.container);select.scrollToCursor(this.container);return true},pageUp:function(){var a=this.cursorPosition().line,d=this.visibleLineCount();if(a===false||d===false)return false;d-=2;for(var g=0;g0;){var a=this.dirty.pop();try{for(;a&&a.parentNode!=this.container;)a=a.parentNode;if(a&&(a.dirty||a.nodeType==3))return a}catch(d){}}return null},highlightDirty:function(a){if(!window||!window.parent||!window.select)return false;this.options.readOnly||select.markSelection();for(var d,g=a?null:(new Date).getTime()+this.options.passTime;((new Date).getTime()=i||!o&&!u&&x>1&&!g)throw StopIteration;u=o;o=false;x=0;t.next()}else{if(!isSpan(v))throw"Parser out of sync. Expected SPAN.";if(v.dirty)o=true;x++;if(!v.reduced&&v.currentText==s.value&&v.className==s.style){j&&v.dirty&&j(v,s,h);v.dirty=false;t.next()}else{o=true;var y=makePartSpan(s.value);y.className=s.style;e.insertBefore(y,v);j&&j(y,s,h);s=s.value.length;for(var A=0;s>0;){v=t.get();var z=v.currentText.length;select.snapshotReplaceNode(v.firstChild, y.firstChild,s,A);if(z>s){v.currentText=v.currentText.substring(s);v.reduced=true;s=0}else{s-=z;A+=z;t.remove()}}}}});c(a);webkitLastLineHack(this.container);return{node:t.getNonEmpty(),dirty:o}}};return p}();addEventHandler(window,"load",function(){var f=window.frameElement.CodeMirror;f.editor=new Editor(f.options);parent.setTimeout(method(f,"init"),0)});var select={}; (function(){function f(b,c){for(;b&&b.parentNode!=c;)b=b.parentNode;return b}function l(b,c){for(;!b.previousSibling&&b.parentNode!=c;)b=b.parentNode;return f(b.previousSibling,c)}function k(b){var c=b.nextSibling;if(c){for(;c.firstChild;)c=c.firstChild;return c.nodeType==3||isBR(c)?c:k(c)}else{for(b=b.parentNode;b&&!b.nextSibling;)b=b.parentNode;return b&&k(b)}}select.ie_selection=document.selection&&document.selection.createRangeCollection;select.scrollToNode=function(b,c){if(b){for(var e=b,h=document.body, j=document.documentElement,i=!e.nextSibling||!e.nextSibling.nextSibling||!e.nextSibling.nextSibling.nextSibling,n=0;e&&!e.offsetTop;){n++;e=e.previousSibling}if(n==0)i=false;if(!(webkit&&e&&e.offsetTop==5&&e.offsetLeft==5)){n*=e?e.offsetHeight:0;for(var r=0,t=b?b.offsetWidth:0;e&&e.offsetParent;){n+=e.offsetTop;isBR(e)||(r+=e.offsetLeft);e=e.offsetParent}e=h.scrollLeft||j.scrollLeft||0;h=h.scrollTop||j.scrollTop||0;var o=false,u=window.innerWidth||j.clientWidth||0;if(c||tu){e=r;o=true}}r=n-h;if(r<0||i||r>(window.innerHeight||j.clientHeight||0)-50){h=i?1E6:n;o=true}o&&window.scrollTo(e,h)}}};select.scrollToCursor=function(b){select.scrollToNode(select.selectionTopNode(b,true)||b.firstChild,true)};var m=null;select.snapshotChanged=function(){if(m)m.changed=true};select.snapshotReplaceNode=function(b,c,e,h){function j(i){if(b==i.node){m.changed=true;if(e&&i.offset>e)i.offset-=e;else{i.node=c;i.offset+=h||0}}else if(select.ie_selection&& i.offset==0&&i.node==k(b))m.changed=true}if(m){j(m.start);j(m.end)}};select.snapshotMove=function(b,c,e,h,j){function i(n){if(b==n.node&&(!j||n.offset==0)){m.changed=true;n.node=c;n.offset=h?Math.max(0,n.offset+e):e}}if(m){i(m.start);i(m.end)}};if(select.ie_selection){var q=function(){var b=document.selection;if(!b)return null;return b.createRange?b.createRange():b.createTextRange()},p=function(b){function c(t){for(var o=null;!o&&t;){o=t.nextSibling;t=t.parentNode}return e(o)}function e(t){for(;t&& t.firstChild;)t=t.firstChild;return{node:t,offset:0}}var h=q();h.collapse(b);b=h.parentElement();if(!isAncestor(document.body,b))return null;if(!b.firstChild)return e(b);var j=h.duplicate();j.moveToElementText(b);j.collapse(true);for(var i=b.firstChild;i;i=i.nextSibling){if(i.nodeType==3){var n=i.nodeValue.length;j.move("character",n)}else{j.moveToElementText(i);j.collapse(false)}var r=h.compareEndPoints("StartToStart",j);if(r==0)return c(i);if(r!=1){if(i.nodeType!=3)return e(i);j.setEndPoint("StartToEnd", h);return{node:i,offset:n-j.text.length}}}return c(b)};select.markSelection=function(){m=null;if(document.selection){var b=p(true),c=p(false);if(b&&c)m={start:b,end:c,changed:false}}};select.selectMarked=function(){function b(h){var j=document.body.createTextRange(),i=h.node;if(i)if(i.nodeType==3){j.moveToElementText(i.parentNode);for(h=h.offset;i.previousSibling;){i=i.previousSibling;h+=(i.innerText||"").length}j.move("character",h)}else{j.moveToElementText(i);j.collapse(true)}else{j.moveToElementText(document.body); j.collapse(false)}return j}if(m&&m.changed){var c=b(m.start),e=b(m.end);c.setEndPoint("StartToEnd",e);c.select()}};select.offsetInNode=function(b){var c=q();if(!c)return 0;var e=c.duplicate();try{e.moveToElementText(b)}catch(h){return 0}c.setEndPoint("StartToStart",e);return c.text.length};select.selectionTopNode=function(b,c){function e(o,u){if(u.nodeType==3){for(var x=0,s=u.previousSibling;s&&s.nodeType==3;){x+=s.nodeValue.length;s=s.previousSibling}if(s){try{o.moveToElementText(s)}catch(v){return false}o.collapse(false)}else o.moveToElementText(u.parentNode); x&&o.move("character",x)}else try{o.moveToElementText(u)}catch(y){return false}return true}var h=q();if(!h)return false;var j=h.duplicate();h.collapse(c);var i=h.parentElement();if(i&&isAncestor(b,i)){j.moveToElementText(i);if(h.compareEndPoints("StartToStart",j)==1)return f(i,b)}c=0;for(i=b.childNodes.length-1;c")};select.insertTabAtCursor=function(){w("\u00a0\u00a0\u00a0\u00a0")};select.cursorPos=function(b,c){var e=q();if(!e)return null;for(var h= select.selectionTopNode(b,c);h&&!isBR(h);)h=h.previousSibling;var j=e.duplicate();e.collapse(c);if(h){j.moveToElementText(h);j.collapse(false)}else{try{j.moveToElementText(b)}catch(i){return null}j.collapse(true)}e.setEndPoint("StartToStart",j);return{node:h,offset:e.text.length}};select.setCursorPos=function(b,c,e){function h(i){var n=document.body.createTextRange();if(i.node){n.moveToElementText(i.node);n.collapse(false)}else{n.moveToElementText(b);n.collapse(true)}n.move("character",i.offset); return n}var j=h(c);e&&e!=c&&j.setEndPoint("EndToEnd",h(e));j.select()};select.getBookmark=function(b){var c=select.cursorPos(b,true);b=select.cursorPos(b,false);if(c&&b)return{from:c,to:b}};select.setBookmark=function(b,c){c&&select.setCursorPos(b,c.from,c.to)}}else{var a=function(b,c){for(;b.nodeType!=3&&!isBR(b);){var e=b.childNodes[c]||b.nextSibling;for(c=0;!e&&b.parentNode;){b=b.parentNode;e=b.nextSibling}b=e;if(!e)break}return{node:b,offset:c}};select.markSelection=function(){var b=window.getSelection(); if(!b||b.rangeCount==0)return m=null;b=b.getRangeAt(0);m={start:a(b.startContainer,b.startOffset),end:a(b.endContainer,b.endOffset),changed:false}};select.selectMarked=function(){function b(){if(e.start.node==e.end.node&&e.start.offset==e.end.offset){var j=window.getSelection();if(!j||j.rangeCount==0)return true;j=j.getRangeAt(0);j=a(j.startContainer,j.startOffset);return e.start.node!=j.node||e.start.offset!=j.offset}}function c(j,i){if(j.node)if(j.offset==0)h["set"+i+"Before"](j.node);else h["set"+ i](j.node,j.offset);else h.setStartAfter(document.body.lastChild||document.body)}var e=m;if(e&&(e.changed||webkit&&b())){var h=document.createRange();c(e.end,"End");c(e.start,"Start");d(h)}};var d=function(b){var c=window.getSelection();if(c){c.removeAllRanges();c.addRange(b)}},g=function(){var b=window.getSelection();return!b||b.rangeCount==0?false:b.getRangeAt(0)};select.selectionTopNode=function(b,c){var e=g();if(!e)return false;var h=c?e.startContainer:e.endContainer,j=c?e.startOffset:e.endOffset; window.opera&&!c&&e.endContainer==b&&e.endOffset==e.startOffset+1&&b.childNodes[e.startOffset]&&isBR(b.childNodes[e.startOffset])&&j--;return h.nodeType==3?j>0?f(h,b):l(h,b):h.nodeName.toUpperCase()=="HTML"?j==1?null:b.lastChild:h==b?j==0?null:h.childNodes[j-1]:j==h.childNodes.length?f(h,b):j==0?l(h,b):f(h.childNodes[j-1],b)};select.focusAfterNode=function(b,c){var e=document.createRange();e.setStartBefore(c.firstChild||c);if(b&&!b.firstChild)e.setEndAfter(b);else b?e.setEnd(b,b.childNodes.length): e.setEndBefore(c.firstChild||c);e.collapse(false);d(e)};select.somethingSelected=function(){var b=g();return b&&!b.collapsed};select.offsetInNode=function(b){var c=g();if(!c)return 0;c=c.cloneRange();c.setStartBefore(b);return c.toString().length};select.insertNodeAtCursor=function(b){var c=g();if(c){c.deleteContents();c.insertNode(b);webkitLastLineHack(document.body);if(window.opera&&isBR(b)&&isSpan(b.parentNode)){c=b.nextSibling;var e=b.parentNode,h=e.parentNode;h.insertBefore(b,e.nextSibling); for(e="";c&&c.nodeType==3;c=c.nextSibling){e+=c.nodeValue;removeElement(c)}h.insertBefore(makePartSpan(e,document),b.nextSibling)}c=document.createRange();c.selectNode(b);c.collapse(false);d(c)}};select.insertNewlineAtCursor=function(){select.insertNodeAtCursor(document.createElement("BR"))};select.insertTabAtCursor=function(){select.insertNodeAtCursor(document.createTextNode("\u00a0\u00a0\u00a0\u00a0"))};select.cursorPos=function(b,c){var e=g();if(e){for(var h=select.selectionTopNode(b,c);h&&!isBR(h);)h= h.previousSibling;e=e.cloneRange();e.collapse(c);h?e.setStartAfter(h):e.setStartBefore(b);return{node:h,offset:e.toString().length}}};select.setCursorPos=function(b,c,e){function h(i,n,r){function t(s){s.nodeType==3?o.push(s):forEach(s.childNodes,t)}if(n==0&&i&&!i.nextSibling){j["set"+r+"After"](i);return true}if(i=i?i.nextSibling:b.firstChild){if(n==0){j["set"+r+"Before"](i);return true}for(var o=[];;){for(;i&&!o.length;){t(i);i=i.nextSibling}var u=o.shift();if(!u)return false;var x=u.nodeValue.length; if(x>=n){j["set"+r](u,n);return true}n-=x}}}var j=document.createRange();e=e||c;h(e.node,e.offset,"End")&&h(c.node,c.offset,"Start")&&d(j)}}})(); var stringStream=function(f){function l(){for(;m==k.length;){q+=k;k="";m=0;try{k=f.next()}catch(p){if(p!=StopIteration)throw p;else return false}}return true}var k="",m=0,q="";return{peek:function(){if(!l())return null;return k.charAt(m)},next:function(){if(!l())if(q.length>0)throw"End of stringstream reached without emptying buffer ('"+q+"').";else throw StopIteration;return k.charAt(m++)},get:function(){var p=q;q="";if(m>0){p+=k.slice(0,m);k=k.slice(m);m=0}return p},push:function(p){k=k.slice(0, m)+p+k.slice(m)},lookAhead:function(p,w,a,d){function g(i){return d?i.toLowerCase():i}p=g(p);var b=false,c=q,e=m;for(a&&this.nextWhileMatches(/[\s\u00a0]/);;){a=m+p.length;var h=k.length-m;if(a<=k.length){b=p==g(k.slice(m,a));m=a;break}else if(p.slice(0,h)==g(k.slice(m))){q+=k;k="";try{k=f.next()}catch(j){if(j!=StopIteration)throw j;break}m=0;p=p.slice(h)}else break}if(!(b&&w)){k=q.slice(c.length)+k;m=e;q=c}return b},lookAheadRegex:function(p,w){if(p.source.charAt(0)!="^")throw Error("Regexps passed to lookAheadRegex must start with ^"); for(;k.indexOf("\n",m)==-1;)try{k+=f.next()}catch(a){if(a!=StopIteration)throw a;break}var d=k.slice(m).match(p);if(d&&w)m+=d[0].length;return d},more:function(){return this.peek()!==null},applies:function(p){var w=this.peek();return w!==null&&p(w)},nextWhile:function(p){for(var w;(w=this.peek())!==null&&p(w);)this.next()},matches:function(p){var w=this.peek();return w!==null&&p.test(w)},nextWhileMatches:function(p){for(var w;(w=this.peek())!==null&&p.test(w);)this.next()},equals:function(p){return p=== this.peek()},endOfLine:function(){var p=this.peek();return p==null||p=="\n"}}}; function tokenizer(f,l){function k(q){return q!="\n"&&/^[\s\u00a0]*$/.test(q)}var m={state:l,take:function(q){if(typeof q=="string")q={style:q,type:q};q.content=(q.content||"")+f.get();/\n$/.test(q.content)||f.nextWhile(k);q.value=q.content+f.get();return q},next:function(){if(!f.more())throw StopIteration;var q;if(f.equals("\n")){f.next();return this.take("whitespace")}if(f.applies(k))q="whitespace";else for(;!q;)q=this.state(f,function(p){m.state=p});return this.take(q)}};return m} function UndoHistory(f,l,k,m){this.container=f;this.maxDepth=l;this.commitDelay=k;this.editor=m;this.last=this.first=f={text:"",from:null,to:null};this.firstTouched=false;this.history=[];this.redoHistory=[];this.touched=[];this.lostundo=0} UndoHistory.prototype={scheduleCommit:function(){var f=this;parent.clearTimeout(this.commitTimeout);this.commitTimeout=parent.setTimeout(function(){f.tryCommit()},this.commitDelay)},touch:function(f){this.setTouched(f);this.scheduleCommit()},undo:function(){this.commit();if(this.history.length){var f=this.history.pop();this.redoHistory.push(this.updateTo(f,"applyChain"));this.notifyEnvironment();return this.chainNode(f)}},redo:function(){this.commit();if(this.redoHistory.length){var f=this.redoHistory.pop(); this.addUndoLevel(this.updateTo(f,"applyChain"));this.notifyEnvironment();return this.chainNode(f)}},clear:function(){this.history=[];this.redoHistory=[];this.lostundo=0},historySize:function(){return{undo:this.history.length,redo:this.redoHistory.length,lostundo:this.lostundo}},push:function(f,l,k){for(var m=[],q=0;qthis.maxDepth){this.history.shift();this.lostundo+=1}},touchedChains:function(){function f(a,d){if(a)a.historyTemp=d;else q=d}function l(a){for(var d=[],g=a?a.nextSibling:m.container.firstChild;g&&(!isBR(g)||g.hackBR);g=g.nextSibling)!g.hackBR&&g.currentText&&d.push(g.currentText);return{from:a,to:g,text:cleanText(d.join(""))}}function k(a,d){for(var g=d+"Sibling",b=a[g];b&&!isBR(b);)b= b[g];return b}var m=this,q=null,p=[];m.firstTouched&&m.touched.push(null);forEach(m.touched,function(a){if(!(a&&(a.parentNode!=m.container||a.hackBR))){if(a)a.historyTouched=false;else m.firstTouched=false;var d=l(a),g=m.after(a);if(!g||g.text!=d.text||g.to!=d.to){p.push(d);f(a,d)}}});var w=[];m.touched=[];forEach(p,function(a){if(a.from?a.from.historyTemp:q){for(var d=[],g=a.from,b=true;;){var c=g?g.historyTemp:q;if(!c)if(b)break;else c=l(g);d.unshift(c);f(g,null);if(!g)break;b=m.after(g);g=k(g, "previous")}g=a.to;for(b=m.before(a.from);;){if(!g)break;c=g?g.historyTemp:q;if(!c)if(b)break;else c=l(g);d.push(c);f(g,null);b=m.before(g);g=k(g,"next")}w.push(d)}});return w},shadowChain:function(f){var l=[],k=this.after(f[0].from);for(f=f[f.length-1].to;;){l.push(k);k=k.to;if(!k||k==f)break;else k=k.historyAfter||this.before(f)}return l},applyChain:function(f){var l=select.cursorPos(this.container,false),k=this,m=f[0].from,q=f[f.length-1].to;(function(b,c){for(var e=b?b.nextSibling:k.container.firstChild;e!= c;){var h=e.nextSibling;removeElement(e);e=h}})(m,q);for(var p=0;p0&&k.container.insertBefore(w.from,q);var a=makePartSpan(fixSpaces(w.text));k.container.insertBefore(a,q);if(l&&l.node==w.from){a=0;var d=this.after(w.from);if(d&&p==f.length-1){for(var g=0;gg)a=w.text.length-d.text.length}select.setCursorPos(this.container,{node:w.from,offset:Math.max(0,l.offset+a)})}else l&&p==f.length-1&&l.node&&l.node.parentNode!= this.container&&select.setCursorPos(this.container,{node:w.from,offset:w.text.length})}this.linkChain(f);return m}};function method(f,l){return function(){f[l].apply(f,arguments)}}var StopIteration={toString:function(){return"StopIteration"}};function forEach(f,l){if(f.next)try{for(;;)l(f.next())}catch(k){if(k!=StopIteration)throw k;}else for(var m=0;m Order allow,deny Deny from all js/codemirror-uncompressed.js000066600000054124151374226730012414 0ustar00/* CodeMirror main module (http://codemirror.net/) * * Implements the CodeMirror constructor and prototype, which take care * of initializing the editor frame, and providing the outside interface. */ // The CodeMirrorConfig object is used to specify a default // configuration. If you specify such an object before loading this // file, the values you put into it will override the defaults given // below. You can also assign to it after loading. var CodeMirrorConfig = window.CodeMirrorConfig || {}; var CodeMirror = (function(){ function setDefaults(object, defaults) { for (var option in defaults) { if (!object.hasOwnProperty(option)) object[option] = defaults[option]; } } function forEach(array, action) { for (var i = 0; i < array.length; i++) action(array[i]); } function createHTMLElement(el) { if (document.createElementNS && document.documentElement.namespaceURI !== null) return document.createElementNS("http://www.w3.org/1999/xhtml", el) else return document.createElement(el) } // These default options can be overridden by passing a set of // options to a specific CodeMirror constructor. See manual.html for // their meaning. setDefaults(CodeMirrorConfig, { stylesheet: [], path: "", parserfile: [], basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"], iframeClass: null, passDelay: 200, passTime: 50, lineNumberDelay: 200, lineNumberTime: 50, continuousScanning: false, saveFunction: null, onLoad: null, onChange: null, undoDepth: 50, undoDelay: 800, disableSpellcheck: true, textWrapping: true, readOnly: false, width: "", height: "300px", minHeight: 100, onDynamicHeightChange: null, autoMatchParens: false, markParen: null, unmarkParen: null, parserConfig: null, tabMode: "indent", // or "spaces", "default", "shift" enterMode: "indent", // or "keep", "flat" electricChars: true, reindentOnLoad: false, activeTokens: null, onCursorActivity: null, lineNumbers: false, firstLineNumber: 1, onLineNumberClick: null, indentUnit: 2, domain: null, noScriptCaching: false, incrementalLoading: false }); function addLineNumberDiv(container, firstNum) { var nums = createHTMLElement("div"), scroller = createHTMLElement("div"); nums.style.position = "absolute"; nums.style.height = "100%"; if (nums.style.setExpression) { try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");} catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions } nums.style.top = "0px"; nums.style.left = "0px"; nums.style.overflow = "hidden"; container.appendChild(nums); scroller.className = "CodeMirror-line-numbers"; nums.appendChild(scroller); scroller.innerHTML = "
" + firstNum + "
"; return nums; } function frameHTML(options) { if (typeof options.parserfile == "string") options.parserfile = [options.parserfile]; if (typeof options.basefiles == "string") options.basefiles = [options.basefiles]; if (typeof options.stylesheet == "string") options.stylesheet = [options.stylesheet]; var sp = " spellcheck=\"" + (options.disableSpellcheck ? "false" : "true") + "\""; var html = [""]; // Hack to work around a bunch of IE8-specific problems. html.push(""); var queryStr = options.noScriptCaching ? "?nocache=" + new Date().getTime().toString(16) : ""; forEach(options.stylesheet, function(file) { html.push(""); }); forEach(options.basefiles.concat(options.parserfile), function(file) { if (!/^https?:/.test(file)) file = options.path + file; html.push(""); else if (inTag == "script") iter.next = local(JSParser, " character // Return the next character in the stream. peek: function() { if (!ensureChars()) return null; return current.charAt(pos); }, // next: -> character // Get the next character, throw StopIteration if at end, check // for unused content. next: function() { if (!ensureChars()) { if (accum.length > 0) throw "End of stringstream reached without emptying buffer ('" + accum + "')."; else throw StopIteration; } return current.charAt(pos++); }, // get(): -> string // Return the characters iterated over since the last call to // .get(). get: function() { var temp = accum; accum = ""; if (pos > 0){ temp += current.slice(0, pos); current = current.slice(pos); pos = 0; } return temp; }, // Push a string back into the stream. push: function(str) { current = current.slice(0, pos) + str + current.slice(pos); }, lookAhead: function(str, consume, skipSpaces, caseInsensitive) { function cased(str) {return caseInsensitive ? str.toLowerCase() : str;} str = cased(str); var found = false; var _accum = accum, _pos = pos; if (skipSpaces) this.nextWhileMatches(/[\s\u00a0]/); while (true) { var end = pos + str.length, left = current.length - pos; if (end <= current.length) { found = str == cased(current.slice(pos, end)); pos = end; break; } else if (str.slice(0, left) == cased(current.slice(pos))) { accum += current; current = ""; try {current = source.next();} catch (e) {if (e != StopIteration) throw e; break;} pos = 0; str = str.slice(left); } else { break; } } if (!(found && consume)) { current = accum.slice(_accum.length) + current; pos = _pos; accum = _accum; } return found; }, // Wont't match past end of line. lookAheadRegex: function(regex, consume) { if (regex.source.charAt(0) != "^") throw new Error("Regexps passed to lookAheadRegex must start with ^"); // Fetch the rest of the line while (current.indexOf("\n", pos) == -1) { try {current += source.next();} catch (e) {if (e != StopIteration) throw e; break;} } var matched = current.slice(pos).match(regex); if (matched && consume) pos += matched[0].length; return matched; }, // Utils built on top of the above // more: -> boolean // Produce true if the stream isn't empty. more: function() { return this.peek() !== null; }, applies: function(test) { var next = this.peek(); return (next !== null && test(next)); }, nextWhile: function(test) { var next; while ((next = this.peek()) !== null && test(next)) this.next(); }, matches: function(re) { var next = this.peek(); return (next !== null && re.test(next)); }, nextWhileMatches: function(re) { var next; while ((next = this.peek()) !== null && re.test(next)) this.next(); }, equals: function(ch) { return ch === this.peek(); }, endOfLine: function() { var next = this.peek(); return next == null || next == "\n"; } }; }; js/parsesparql.js000066600000012033151374226730010070 0ustar00var SparqlParser = Editor.Parser = (function() { function wordRegexp(words) { return new RegExp("^(?:" + words.join("|") + ")$", "i"); } var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri", "isblank", "isliteral", "union", "a"]); var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe", "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional", "graph", "by", "asc", "desc"]); var operatorChars = /[*+\-<>=&|]/; var tokenizeSparql = (function() { function normal(source, setState) { var ch = source.next(); if (ch == "$" || ch == "?") { source.nextWhileMatches(/[\w\d]/); return "sp-var"; } else if (ch == "<" && !source.matches(/[\s\u00a0=]/)) { source.nextWhileMatches(/[^\s\u00a0>]/); if (source.equals(">")) source.next(); return "sp-uri"; } else if (ch == "\"" || ch == "'") { setState(inLiteral(ch)); return null; } else if (/[{}\(\),\.;\[\]]/.test(ch)) { return "sp-punc"; } else if (ch == "#") { while (!source.endOfLine()) source.next(); return "sp-comment"; } else if (operatorChars.test(ch)) { source.nextWhileMatches(operatorChars); return "sp-operator"; } else if (ch == ":") { source.nextWhileMatches(/[\w\d\._\-]/); return "sp-prefixed"; } else { source.nextWhileMatches(/[_\w\d]/); if (source.equals(":")) { source.next(); source.nextWhileMatches(/[\w\d_\-]/); return "sp-prefixed"; } var word = source.get(), type; if (ops.test(word)) type = "sp-operator"; else if (keywords.test(word)) type = "sp-keyword"; else type = "sp-word"; return {style: type, content: word}; } } function inLiteral(quote) { return function(source, setState) { var escaped = false; while (!source.endOfLine()) { var ch = source.next(); if (ch == quote && !escaped) { setState(normal); break; } escaped = !escaped && ch == "\\"; } return "sp-literal"; }; } return function(source, startState) { return tokenizer(source, startState || normal); }; })(); function indentSparql(context) { return function(nextChars) { var firstChar = nextChars && nextChars.charAt(0); if (/[\]\}]/.test(firstChar)) while (context && context.type == "pattern") context = context.prev; var closing = context && firstChar == matching[context.type]; if (!context) return 0; else if (context.type == "pattern") return context.col; else if (context.align) return context.col - (closing ? context.width : 0); else return context.indent + (closing ? 0 : indentUnit); } } function parseSparql(source) { var tokens = tokenizeSparql(source); var context = null, indent = 0, col = 0; function pushContext(type, width) { context = {prev: context, indent: indent, col: col, type: type, width: width}; } function popContext() { context = context.prev; } var iter = { next: function() { var token = tokens.next(), type = token.style, content = token.content, width = token.value.length; if (content == "\n") { token.indentation = indentSparql(context); indent = col = 0; if (context && context.align == null) context.align = false; } else if (type == "whitespace" && col == 0) { indent = width; } else if (type != "sp-comment" && context && context.align == null) { context.align = true; } if (content != "\n") col += width; if (/[\[\{\(]/.test(content)) { pushContext(content, width); } else if (/[\]\}\)]/.test(content)) { while (context && context.type == "pattern") popContext(); if (context && content == matching[context.type]) popContext(); } else if (content == "." && context && context.type == "pattern") { popContext(); } else if ((type == "sp-word" || type == "sp-prefixed" || type == "sp-uri" || type == "sp-var" || type == "sp-literal") && context && /[\{\[]/.test(context.type)) { pushContext("pattern", width); } return token; }, copy: function() { var _context = context, _indent = indent, _col = col, _tokenState = tokens.state; return function(source) { tokens = tokenizeSparql(source, _tokenState); context = _context; indent = _indent; col = _col; return iter; }; } }; return iter; } return {make: parseSparql, electricChars: "}]"}; })();