Skip to content
Browse files

Adding files from Local HG to Git

  • Loading branch information...
0 parents commit 83d6fc69502ce67e627f4309359e9ccdce762c5a @axemclion committed Aug 14, 2009
Showing with 7,189 additions and 0 deletions.
  1. +11 −0 .project
  2. +1 −0 README
  3. +183 −0 TrialTool.css
  4. +16 −0 examples/Template.html
  5. +46 −0 iframe.html
  6. BIN images/closed.png
  7. BIN images/opened.png
  8. +104 −0 index.html
  9. +53 −0 js/ConsoleHelper.js
  10. +165 −0 js/TrialTool.js
  11. +23 −0 lib/codemirror/LICENSE
  12. +51 −0 lib/codemirror/css/csscolors.css
  13. +50 −0 lib/codemirror/css/docs.css
  14. +59 −0 lib/codemirror/css/jscolors.css
  15. +43 −0 lib/codemirror/css/sparqlcolors.css
  16. +55 −0 lib/codemirror/css/xmlcolors.css
  17. +469 −0 lib/codemirror/js/codemirror.js
  18. +1,465 −0 lib/codemirror/js/editor.js
  19. +68 −0 lib/codemirror/js/highlight.js
  20. +81 −0 lib/codemirror/js/mirrorframe.js
  21. +155 −0 lib/codemirror/js/parsecss.js
  22. +32 −0 lib/codemirror/js/parsedummy.js
  23. +74 −0 lib/codemirror/js/parsehtmlmixed.js
  24. +352 −0 lib/codemirror/js/parsejavascript.js
  25. +162 −0 lib/codemirror/js/parsesparql.js
  26. +286 −0 lib/codemirror/js/parsexml.js
  27. +619 −0 lib/codemirror/js/select.js
  28. +140 −0 lib/codemirror/js/stringstream.js
  29. +57 −0 lib/codemirror/js/tokenize.js
  30. +174 −0 lib/codemirror/js/tokenizejavascript.js
  31. +410 −0 lib/codemirror/js/undo.js
  32. +130 −0 lib/codemirror/js/util.js
  33. BIN lib/jquery/css/smoothness/images/ui-anim_basic_16x16.gif
  34. BIN lib/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
  35. BIN lib/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
  36. BIN lib/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
  37. BIN lib/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
  38. BIN lib/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
  39. BIN lib/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
  40. BIN lib/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
  41. BIN lib/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
  42. BIN lib/jquery/css/smoothness/images/ui-icons_222222_256x240.png
  43. BIN lib/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png
  44. BIN lib/jquery/css/smoothness/images/ui-icons_454545_256x240.png
  45. BIN lib/jquery/css/smoothness/images/ui-icons_888888_256x240.png
  46. BIN lib/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png
  47. +489 −0 lib/jquery/css/smoothness/jquery-ui-1.8.2.custom.css
  48. +154 −0 lib/jquery/jquery-1.4.2.min.js
  49. +1,012 −0 lib/jquery/jquery-ui-1.8.2.custom.min.js
11 .project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>TrialTool</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
1 README
@@ -0,0 +1 @@
+My GitHub Page
183 TrialTool.css
@@ -0,0 +1,183 @@
+body {
+ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ padding: 0;
+ max-width: 100%;
+ overflow: auto;
+ background-color: #314362;
+ margin: 0 1% 0 1%;
+}
+
+div#header {
+ width: 100%;
+ height: 5%;
+}
+
+div#content {
+ width: 100%;
+ height: 93%;
+ background-color: #314362;
+}
+
+div#footer {
+ width: 100%;
+ height: 1%;
+}
+
+div#top-pane {
+ height: 50%;
+}
+
+div#examples {
+ width: 24.5%;
+ float: left;
+ background-color: white;
+ height: 100%;
+}
+
+div#vertical-thumb {
+ float: left;
+ width: 0.5%;
+ height: 100%;
+}
+
+div.code-area {
+ float: right;
+ width: 75%;
+ height: 100%;
+ background-color: WHITE;
+}
+
+div#examples-title {
+ padding: 0 1em 0 1em;
+ line-height: 2em;
+ height: 7%;
+ overflow: hidden;
+ background-color: #ABCEDF;
+}
+
+#example-sets {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ margin: 0;
+ padding: 1% 0 0 1%;
+ height: 91%;
+}
+
+#example-sets ul {
+ padding: 0;
+ margin: 0;
+}
+
+li.example-set, li.example {
+ margin: 0;
+ padding: 0 0 0 3%;
+ list-style: none;
+}
+
+div.example-docs, li.example textarea {
+ display: none;
+}
+
+a.example-set-name {
+ margin: 0.2em 0 0 0;
+ padding: 0 0 0 1em;
+ text-decoration: none;
+ color: black;
+ background-image: url('images/opened.png');
+ background-repeat: no-repeat;
+ background-position: left center;
+}
+
+a.example-name {
+ margin: 0.2em 0 0 0;
+ padding: 0 1em 0 1em;
+ text-decoration: none;
+ color: #5A5A5A;
+ display: table;
+}
+
+a.example-name-selected {
+ background-color: #FBD877;
+ font-weight: bold;
+}
+
+ul#toolbar {
+ list-style: none;
+ padding: 0;
+ margin: 0 1em 0 0;
+ height: 100%;
+ float: right;
+}
+
+ul#toolbar li {
+ float: left;
+ margin: 0.5em 1em 0 0em;
+ background-color: #A3B7CB;
+ width: 12em;
+ text-align: center;
+}
+
+ul#toolbar a {
+ padding: 0.5em 0 0.5em 0;
+ display: block;
+ text-decoration: none;
+ color: BLACK;
+ width: 100%;
+ background-image: -moz-linear-gradient(top, #FFFFFF, #A3B7CB); /* FF3.6 */
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #FFFFFF),color-stop(1, #A3B7CB)); /* Saf4+, Chrome */
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#A3B7CB'); /* IE6,IE7 */
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#A3B7CB')"; /* IE8 */
+}
+
+ul#toolbar a:hover {
+ background-image: -moz-linear-gradient(top, #FFFFFF, #A9DBF6); /* FF3.6 */
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #FFFFFF),color-stop(1, #A9DBF6)); /* Saf4+, Chrome */
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#A9DBF6'); /* IE6,IE7 */
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#A9DBF6')"; /* IE8 */
+}
+
+div#formattedCode {
+ width: 100%;
+ height: 100%;
+}
+
+textarea#code {
+ display: none;
+ font-size: 1.5 em;
+ width: 100%;
+ height: 100%;
+}
+
+div#horizontal-thumb {
+ height: 1%;
+ font-size: 0px;
+}
+
+div#console {
+ background-color: white;
+ clear: both;
+ height: 48%;
+ overflow-y : auto;
+}
+
+div#docs {
+ width: 98%;
+ height: 98%;
+ padding: 1%;
+}
+
+div#console iframe {
+ display: none;
+ width: 100%;
+ border: none;
+ height: 100%;
+}
+
+.sample {
+ display: none;
+}
+
+.clear {
+ clear: both;
+}
16 examples/Template.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ </head>
+ <body>
+ <div>
+ <div class = "example-set">
+ <div class = "example">
+ <div class = "name">
+ </div>
+ <script type = "text/javascript">
+ </script>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
46 iframe.html
@@ -0,0 +1,46 @@
+<html>
+ <meta http-equiv="X-UA-Compatible" content="IE=8">
+ <head>
+ <title>Trial Tool Console</title>
+ <style>
+ body {
+ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ }
+
+ .log-time {
+ color: #314362;
+ font-weight: bold;
+ }
+
+ .log-object, .log-array {
+ cursor: pointer;
+ color: blue;
+ }
+
+ .log-opened > span {
+ border: dotted 1px BLACK;
+ border-bottom: none;
+ background-color: #F1F4F7;
+ padding-bottom: 1px;
+ }
+
+ .log-opened ul, ol {
+ border: dotted 1px BLACK;
+ background-color: #F1F4F7;
+ padding: 0 0 0 2%;
+ margin: 0 3px 5px 0;
+ color: black;
+ list-style: square;
+ }
+ </style>
+ <script type = "text/javascript" src= "lib/jquery/jquery-1.4.2.min.js">
+ </script>
+ <script type = "text/javascript" src= "js/ConsoleHelper.js">
+ </script>
+ </head>
+ <body>
+ <div id = "console">
+ </div>
+ </body>
+</html>
BIN images/closed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/opened.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 index.html
@@ -0,0 +1,104 @@
+<html>
+ <head>
+ <title>Trial Tool</title>
+ <link rel="stylesheet" type="text/css" href="lib/jquery/css/smoothness/jquery-ui-1.8.2.custom.css">
+ </link>
+ <link rel="stylesheet" type="text/css" href="lib/codemirror/css/docs.css">
+ </link>
+ <link rel="stylesheet" type="text/css" href="TrialTool.css">
+ </link>
+ </head>
+ <body>
+ <div id = "header">
+ <div style ="float:left; line-height : 1.5em; font-size : 2em;margin : 0 0 0 1em; color : WHITE; font-family : Garamond; font-style :italic; font-weight : bolder;">
+ Trial Tool
+ </div>
+ <ul id = "toolbar">
+ <li>
+ <a href = "#run" id = "run">Run Snippet</a>
+ </li>
+ <li>
+ <a href = "#getDependencies" id = "getDependencies">Load Pre-requisites</a>
+ </li>
+ <li>
+ <a href = "#viewdocs" id = "viewdocs">View Output</a>
+ </li>
+ <li>
+ <a href = "#clearConsole" id = "clearConsole">Clear Console</a>
+ </li>
+ </ul>
+ <div class = "clear">
+ </div>
+ </div>
+ <div id = "content" class = "clear">
+ <div id = "top-pane">
+ <div id = "examples">
+ <div id = "examples-title">
+ Examples
+ </div>
+ <ul id = "example-sets" class = "example-set">
+ </ul>
+ </div>
+ <div id = "vertical-thumb">
+ </div>
+ <div class = "code-area">
+ <div id = "formattedCode" class = "prettyprint">
+ </div>
+ <textarea border = "0" id = "code">
+ /***************************************\
+ | Select a module from the Examples list|
+ \***************************************/
+ //This is the code area//
+ </textarea>
+ </div>
+ <div class = "clear">
+ </div>
+ </div>
+ <div id = "horizontal-thumb">
+ </div>
+ <div id = "console" class = "clear">
+ <div id = "docs">
+ <h2>Using this tool</h2>
+ This tool showcases the capabilities of various API and libraries.
+ You can load example snippets, modify them and run it to see the results right here.
+ <br/>
+ <h5>The toolbar buttons</h5>
+ <ul>
+ <li>
+ <b>Run Snippet : </b>
+ This button runs the code that is in the code area at the top right. The code area is editable and you can modify the examples and run them.
+ </li>
+ <li>
+ <b>Load Pre-requisites : </b>
+ Some snippets require of other snippets to be run. This button adds those dependencies in the code area.
+ </li>
+ <li>
+ <b>View Output / View Docs</b>
+ Toggle to view the documentation for the current API or the output window here.
+ </li>
+ <li>
+ <b>Clear Console</b>Clears the output window
+ </li>
+ </ul>
+ <p>
+ If you are an API developer and want to use this tool to showcase your libraries, you can use this tool. The examples loaded are configrable.
+ </p>
+ </div>
+ <iframe frameBorder = 0 src = "iframe.html" id = "console-iframe">
+ </iframe>
+ </div>
+ </div>
+ <div id = "footer">
+ </div>
+ <script src="lib/jquery/jquery-1.4.2.min.js" type="text/javascript">
+ </script>
+ <script src="lib/jquery/jquery-ui-1.8.2.custom.min.js" type="text/javascript">
+ </script>
+ <script src="lib/codemirror/js/codemirror.js" type="text/javascript">
+ </script>
+ <script src="lib/codemirror/js/mirrorframe.js" type="text/javascript">
+ </script>
+ <script src="js/TrialTool.js" type=text/javascript>
+ </script>
+ </body>
+</html>
53 js/ConsoleHelper.js
@@ -0,0 +1,53 @@
+$("span.log-object, span.log-array").live("click", function(){
+ $(this).children("ul, ol").toggle();
+ if ($(this).children("ul, ol").css("display") !== "none") {
+ $(this).addClass("log-opened");
+ }
+ else {
+ $(this).removeClass("log-opened");
+ }
+});
+
+function write(){
+ var text = document.createElement("div");
+ var msg = [];
+ for (var i = 0; i < arguments.length; i++) {
+ msg.push(getDomFromJSON(arguments[i]));
+ }
+ text.innerHTML = ["<span class='log-time'>[", new Date().toLocaleTimeString(), "]&nbsp;</span>"].join("") + msg.join(" ");
+ document.getElementById("console").appendChild(text);
+ return text;
+}
+
+function writeError(e){
+ write(e.name + ": " + e.message).style.color = "RED";
+}
+
+function getDomFromJSON(data){
+ var result = [];
+ if (Object.prototype.toString.apply(data) === '[object Array]') {
+ result = ["<span class = 'log-array'>&nbsp;<u>[Array : ", data.length, "]</u>&nbsp;"];
+ result.push("<ol start = 0 style = 'display:none'>");
+ for (var i = 0; i < data.length; i++) {
+ result.push("<li>");
+ result.push(getDomFromJSON(data[i]));
+ result.push("</li>")
+ }
+ result.push("</ol></span>");
+ }
+ else
+ if (typeof(data) === "object") {
+ result = ["<span class = 'log-object'>&nbsp;<u>[Object]</u>&nbsp;"];
+ result.push("<ul style = 'display:none'>");
+ for (x in data) {
+ result.push("<li>" + x);
+ result.push(":" + getDomFromJSON(data[x]));
+ result.push("</li>")
+ }
+ result.push("</ul></span>");
+ }
+ else {
+ result = ["<span class = 'log-item'>", data, "</span>"];
+ }
+ return result.join("");
+}
165 js/TrialTool.js
@@ -0,0 +1,165 @@
+/**
+ * The Main TrialTool Object
+ * @param {Object} divs representing various elements in the page
+ */
+var TrialTool = (function(){
+ var currentSelection = null;
+ $("a.example-set-name").live("click", function(e){
+ var list = $(this).parent().children("ul").toggle();
+ if (list.css("display") === "none") {
+ $(this).css("background-image", "url('images/closed.png')");
+ }
+ else {
+ $(this).css("background-image", "url('images/opened.png')");
+ }
+ e.preventDefault();
+ });
+
+ $("a.example-name").live("click", function(e){
+ var example = $(this).parent();
+ showCode(example.children("textarea.script").val());
+ $("div#docs").html(example.children("div.example-docs").html());
+ currentSelection = example;
+ e.preventDefault();
+
+ $("a.example-name-selected").removeClass("example-name-selected");
+ $(this).addClass("example-name-selected");
+
+
+ });
+
+
+
+ $("ul#toolbar a").live("click", function(e){
+ switch ($(this).attr("id")) {
+ case "viewdocs":
+ showDocs(($("div#docs").css("display") === "none"));
+ break;
+ case "clearConsole":
+ runCode("document.getElementById('console').innerHTML = '';")
+ break;
+ case "run":
+ showDocs(false);
+ runCode(editor.getCode());
+
+ break;
+ case "getDependencies":
+ var code = [];
+ visitedNodes = {};
+ $.each(getDependencies(currentSelection), function(){
+ code.push("/*" + this.module + "*/\n");
+ code.push(this.code);
+ code.push("\n\n\n");
+ });
+ showCode(code.join(" "));
+ break;
+ };
+ e.preventDefault();
+ });
+
+ var runCode = function(code){
+ var iframe = $("#console-iframe").get(0).contentWindow;
+ if (!iframe.eval && iframe.execScript) {
+ iframe.execScript("null");
+ }
+ try {
+ iframe.eval(code);
+ }
+ catch (e) {
+ iframe.writeError(e);
+ }
+ }
+
+ var visitedNodes = {};
+ var getDependencies = function(example){
+ var result = [];
+ var node = (example && typeof(example) === "string") ? $("li.#" + example + ":first") : example;
+ if (!node || node.attr("id") in visitedNodes) {
+ return;
+ }
+ visitedNodes[node.attr("id")] = '';
+ function add(a){
+ result = (a ? result.concat(a) : result);
+ };
+
+ // Getting the current node's dependencies
+ var dependents = (node.parent("ul").parent("li.example-set").attr("depends") || "") + "," + (node.attr("depends") || "");
+ //console.log(node.get(0), " depends on ", dependents, visitedNodes);
+ $.each(dependents.split(","), function(){
+ add(getDependencies(String(this)));
+ });
+
+ // Adding self to the result
+ if (node.hasClass("example-set")) {
+ $(node.children("li.example")).each(function(){
+ add(getDependencies($(this).attr("id")))
+ });
+ $(node.children("ul").children("li.example")).each(function(){
+ add(getDependencies($(this).attr("id")))
+ });
+ }
+ else {
+ result.push({
+ "module": node.children("a.example-name").html(),
+ "code": node.children("textarea.script").val()
+ });
+ }
+ return result;
+ };
+
+ var showCode = function(code){
+ if (!code) {
+ code = $("#code").val();
+ }
+ editor.setCode(code.replace(/^\s+|\s+$/g, ''));
+ editor.reindent();
+ }
+
+ var showDocs = function(flag){
+ $("#console-iframe").toggle(!flag);
+ $("div#docs").toggle(flag);
+ $("a#viewdocs").html((flag && "View Output") || "View Docs");
+ }
+
+ /**
+ * Uses codemirror to initialize a code editor
+ */
+ var editor = new CodeMirror(CodeMirror.replace("formattedCode"), {
+ parserfile: ["tokenizejavascript.js", "parsejavascript.js"],
+ path: "lib/codemirror/js/",
+ stylesheet: "lib/codemirror/css/jscolors.css",
+ content: document.getElementById("code").value,
+ height: "100%"
+ });
+
+ return {
+ /**
+ * Adds a new example to
+ * @param {Object} example
+ */
+ loadExamples: function(url){
+ $.ajax({
+ "type": "GET",
+ "datatype": "html",
+ "url": url + "?" + Math.random(),
+ dataFilter: function(data, type){
+ return data.replace(/<script/g, "<textarea class = 'script' ").replace(/<\/script>/g, "</textarea>");
+ },
+ "success": function(data){
+ $("#example-sets").append($(data));
+ },
+ "error": function(data, errorString, m){
+ alert("Could not load " + url);
+ }
+ });
+ }
+ };
+})();
+
+
+var url = document.location.href;
+url = url.substring((url.indexOf("#") + 1) || url.length);
+url = url || "examples/Template.html";
+$.each(url.split("&"), function(){
+ TrialTool.loadExamples(this);
+});
23 lib/codemirror/LICENSE
@@ -0,0 +1,23 @@
+ Copyright (c) 2007-2009 Marijn Haverbeke
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
+ damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
+ redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+
+ Marijn Haverbeke
+ marijnh at gmail
51 lib/codemirror/css/csscolors.css
@@ -0,0 +1,51 @@
+html {
+ 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.css-at {
+ color: #770088;
+}
+
+span.css-unit {
+ color: #228811;
+}
+
+span.css-value {
+ color: #770088;
+}
+
+span.css-identifier {
+ color: black;
+}
+
+span.css-important {
+ color: #0000FF;
+}
+
+span.css-colorcode {
+ color: #004499;
+}
+
+span.css-comment {
+ color: #AA7700;
+}
+
+span.css-string {
+ color: #AA2222;
+}
50 lib/codemirror/css/docs.css
@@ -0,0 +1,50 @@
+body {
+ margin: 0;
+ padding: 3em 6em;
+ color: black;
+ max-width: 50em;
+}
+
+h1 {
+ font-size: 22pt;
+}
+
+.underline {
+ border-bottom: 3px solid #C44;
+}
+
+h2 {
+ font-size: 14pt;
+}
+
+h3 {
+ font-size: 12pt;
+}
+
+p.rel {
+ padding-left: 2em;
+ text-indent: -2em;
+}
+
+div.border {
+ border: 1px solid black;
+ padding: 3px;
+}
+
+code {
+ font-family: courier, monospace;
+ font-size: 90%;
+ color: #144;
+}
+
+pre.code {
+ margin: 1.1em 12px;
+ border: 1px solid #CCCCCC;
+ color: black;
+ padding: .4em;
+ font-family: courier, monospace;
+}
+
+.warn {
+ color: #C00;
+}
59 lib/codemirror/css/jscolors.css
@@ -0,0 +1,59 @@
+html {
+ 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;
+}
43 lib/codemirror/css/sparqlcolors.css
@@ -0,0 +1,43 @@
+html {
+ 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;
+}
55 lib/codemirror/css/xmlcolors.css
@@ -0,0 +1,55 @@
+html {
+ 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;
+}
469 lib/codemirror/js/codemirror.js
@@ -0,0 +1,469 @@
+/* CodeMirror main module
+ *
+ * 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]);
+ }
+
+ // 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,
+ onChange: null,
+ undoDepth: 50,
+ undoDelay: 800,
+ disableSpellcheck: true,
+ textWrapping: true,
+ readOnly: false,
+ width: "",
+ height: "300px",
+ autoMatchParens: false,
+ parserConfig: null,
+ tabMode: "indent", // or "spaces", "default", "shift"
+ reindentOnLoad: false,
+ activeTokens: null,
+ cursorActivity: null,
+ lineNumbers: false,
+ indentUnit: 2,
+ domain: null
+ });
+
+ function addLineNumberDiv(container) {
+ var nums = document.createElement("DIV"),
+ scroller = document.createElement("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.overflow = "hidden";
+ container.appendChild(nums);
+ scroller.className = "CodeMirror-line-numbers";
+ nums.appendChild(scroller);
+ return nums;
+ }
+
+ function frameHTML(options) {
+ if (typeof options.parserfile == "string")
+ options.parserfile = [options.parserfile];
+ if (typeof options.stylesheet == "string")
+ options.stylesheet = [options.stylesheet];
+
+ var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html><head>"];
+ // Hack to work around a bunch of IE8-specific problems.
+ html.push("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE7\"/>");
+ forEach(options.stylesheet, function(file) {
+ html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + "\"/>");
+ });
+ forEach(options.basefiles.concat(options.parserfile), function(file) {
+ html.push("<script type=\"text/javascript\" src=\"" + options.path + file + "\"><" + "/script>");
+ });
+ html.push("</head><body style=\"border-width: 0;\" class=\"editbox\" spellcheck=\"" +
+ (options.disableSpellcheck ? "false" : "true") + "\"></body></html>");
+ return html.join("");
+ }
+
+ var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
+
+ function CodeMirror(place, options) {
+ // Backward compatibility for deprecated options.
+ if (options.dumbTabs) options.tabMode = "spaces";
+ else if (options.normalTab) options.tabMode = "default";
+
+ // Use passed options, if any, to override defaults.
+ this.options = options = options || {};
+ setDefaults(options, CodeMirrorConfig);
+
+ var frame = this.frame = document.createElement("IFRAME");
+ if (options.iframeClass) frame.className = options.iframeClass;
+ frame.frameBorder = 0;
+ frame.style.border = "0";
+ frame.style.width = '100%';
+ frame.style.height = '100%';
+ // display: block occasionally suppresses some Firefox bugs, so we
+ // always add it, redundant as it sounds.
+ frame.style.display = "block";
+
+ var div = this.wrapping = document.createElement("DIV");
+ div.style.position = "relative";
+ div.className = "CodeMirror-wrapping";
+ div.style.width = options.width;
+ div.style.height = options.height;
+ // This is used by Editor.reroutePasteEvent
+ var teHack = this.textareaHack = document.createElement("TEXTAREA");
+ div.appendChild(teHack);
+ teHack.style.position = "absolute";
+ teHack.style.left = "-10000px";
+ teHack.style.width = "10px";
+
+ // Link back to this object, so that the editor can fetch options
+ // and add a reference to itself.
+ frame.CodeMirror = this;
+ if (options.domain && internetExplorer) {
+ this.html = frameHTML(options);
+ frame.src = "javascript:(function(){document.open();" +
+ (options.domain ? "document.domain=\"" + options.domain + "\";" : "") +
+ "document.write(window.frameElement.CodeMirror.html);document.close();})()";
+ }
+ else {
+ frame.src = "javascript:false";
+ }
+
+ if (place.appendChild) place.appendChild(div);
+ else place(div);
+ div.appendChild(frame);
+ if (options.lineNumbers) this.lineNumbers = addLineNumberDiv(div);
+
+ this.win = frame.contentWindow;
+ if (!options.domain || !internetExplorer) {
+ this.win.document.open();
+ this.win.document.write(frameHTML(options));
+ this.win.document.close();
+ }
+ }
+
+ CodeMirror.prototype = {
+ init: function() {
+ if (this.options.initCallback) this.options.initCallback(this);
+ if (this.options.lineNumbers) this.activateLineNumbers();
+ if (this.options.reindentOnLoad) this.reindent();
+ },
+
+ getCode: function() {return this.editor.getCode();},
+ setCode: function(code) {this.editor.importCode(code);},
+ selection: function() {this.focusIfIE(); return this.editor.selectedText();},
+ reindent: function() {this.editor.reindent();},
+ reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},
+
+ focusIfIE: function() {
+ // in IE, a lot of selection-related functionality only works when the frame is focused
+ if (this.win.select.ie_selection) this.focus();
+ },
+ focus: function() {
+ this.win.focus();
+ if (this.editor.selectionSnapshot) // IE hack
+ this.win.select.setBookmark(this.win.document.body, this.editor.selectionSnapshot);
+ },
+ replaceSelection: function(text) {
+ this.focus();
+ this.editor.replaceSelection(text);
+ return true;
+ },
+ replaceChars: function(text, start, end) {
+ this.editor.replaceChars(text, start, end);
+ },
+ getSearchCursor: function(string, fromCursor, caseFold) {
+ return this.editor.getSearchCursor(string, fromCursor, caseFold);
+ },
+
+ undo: function() {this.editor.history.undo();},
+ redo: function() {this.editor.history.redo();},
+ historySize: function() {return this.editor.history.historySize();},
+ clearHistory: function() {this.editor.history.clear();},
+
+ grabKeys: function(callback, filter) {this.editor.grabKeys(callback, filter);},
+ ungrabKeys: function() {this.editor.ungrabKeys();},
+
+ setParser: function(name) {this.editor.setParser(name);},
+ setSpellcheck: function(on) {this.win.document.body.spellcheck = on;},
+ setStylesheet: function(names) {
+ if (typeof names === "string") names = [names];
+ var activeStylesheets = {};
+ var matchedNames = {};
+ var links = this.win.document.getElementsByTagName("link");
+ // Create hashes of active stylesheets and matched names.
+ // This is O(n^2) but n is expected to be very small.
+ for (var x = 0, link; link = links[x]; x++) {
+ if (link.rel.indexOf("stylesheet") !== -1) {
+ for (var y = 0; y < names.length; y++) {
+ var name = names[y];
+ if (link.href.substring(link.href.length - name.length) === name) {
+ activeStylesheets[link.href] = true;
+ matchedNames[name] = true;
+ }
+ }
+ }
+ }
+ // Activate the selected stylesheets and disable the rest.
+ for (var x = 0, link; link = links[x]; x++) {
+ if (link.rel.indexOf("stylesheet") !== -1) {
+ link.disabled = !(link.href in activeStylesheets);
+ }
+ }
+ // Create any new stylesheets.
+ for (var y = 0; y < names.length; y++) {
+ var name = names[y];
+ if (!(name in matchedNames)) {
+ var link = this.win.document.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = name;
+ this.win.document.getElementsByTagName('head')[0].appendChild(link);
+ }
+ }
+ },
+ setTextWrapping: function(on) {
+ if (on == this.options.textWrapping) return;
+ this.win.document.body.style.whiteSpace = on ? "" : "nowrap";
+ this.options.textWrapping = on;
+ if (this.lineNumbers) {
+ this.setLineNumbers(false);
+ this.setLineNumbers(true);
+ }
+ },
+ setIndentUnit: function(unit) {this.win.indentUnit = unit;},
+ setUndoDepth: function(depth) {this.editor.history.maxDepth = depth;},
+ setTabMode: function(mode) {this.options.tabMode = mode;},
+ setLineNumbers: function(on) {
+ if (on && !this.lineNumbers) {
+ this.lineNumbers = addLineNumberDiv(this.wrapping);
+ this.activateLineNumbers();
+ }
+ else if (!on && this.lineNumbers) {
+ this.wrapping.removeChild(this.lineNumbers);
+ this.wrapping.style.marginLeft = "";
+ this.lineNumbers = null;
+ }
+ },
+
+ cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
+ firstLine: function() {return this.editor.firstLine();},
+ lastLine: function() {return this.editor.lastLine();},
+ nextLine: function(line) {return this.editor.nextLine(line);},
+ prevLine: function(line) {return this.editor.prevLine(line);},
+ lineContent: function(line) {return this.editor.lineContent(line);},
+ setLineContent: function(line, content) {this.editor.setLineContent(line, content);},
+ removeLine: function(line){this.editor.removeLine(line);},
+ insertIntoLine: function(line, position, content) {this.editor.insertIntoLine(line, position, content);},
+ selectLines: function(startLine, startOffset, endLine, endOffset) {
+ this.win.focus();
+ this.editor.selectLines(startLine, startOffset, endLine, endOffset);
+ },
+ nthLine: function(n) {
+ var line = this.firstLine();
+ for (; n > 1 && line !== false; n--)
+ line = this.nextLine(line);
+ return line;
+ },
+ lineNumber: function(line) {
+ var num = 0;
+ while (line !== false) {
+ num++;
+ line = this.prevLine(line);
+ }
+ return num;
+ },
+ jumpToLine: function(line) {
+ if (typeof line == "number") line = this.nthLine(line);
+ this.selectLines(line, 0);
+ this.win.focus();
+ },
+ currentLine: function() { // Deprecated, but still there for backward compatibility
+ return this.lineNumber(this.cursorLine());
+ },
+ cursorLine: function() {
+ return this.cursorPosition().line;
+ },
+
+ activateLineNumbers: function() {
+ var frame = this.frame, win = frame.contentWindow, doc = win.document, body = doc.body,
+ nums = this.lineNumbers, scroller = nums.firstChild, self = this;
+ var barWidth = null;
+
+ function sizeBar() {
+ if (frame.offsetWidth == 0) return;
+ for (var root = frame; root.parentNode; root = root.parentNode);
+ if (!nums.parentNode || root != document || !win.Editor) {
+ // Clear event handlers (their nodes might already be collected, so try/catch)
+ try{clear();}catch(e){}
+ clearInterval(sizeInterval);
+ return;
+ }
+
+ if (nums.offsetWidth != barWidth) {
+ barWidth = nums.offsetWidth;
+ nums.style.left = "-" + (frame.parentNode.style.marginLeft = barWidth + "px");
+ }
+ }
+ function doScroll() {
+ nums.scrollTop = body.scrollTop || doc.documentElement.scrollTop || 0;
+ }
+ // Cleanup function, registered by nonWrapping and wrapping.
+ var clear = function(){};
+ sizeBar();
+ var sizeInterval = setInterval(sizeBar, 500);
+
+ function nonWrapping() {
+ var nextNum = 1, pending;
+ function update() {
+ var target = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0));
+ var endTime = new Date().getTime() + self.options.lineNumberTime;
+ while (scroller.offsetHeight < target && (!scroller.firstChild || scroller.offsetHeight)) {
+ scroller.appendChild(document.createElement("DIV"));
+ scroller.lastChild.innerHTML = nextNum++;
+ if (new Date().getTime() > endTime) {
+ if (pending) clearTimeout(pending);
+ pending = setTimeout(update, self.options.lineNumberDelay);
+ break;
+ }
+ }
+ doScroll();
+ }
+ var onScroll = win.addEventHandler(win, "scroll", update, true),
+ onResize = win.addEventHandler(win, "resize", update, true);
+ clear = function(){onScroll(); onResize(); if (pending) clearTimeout(pending);};
+ update();
+ }
+ function wrapping() {
+ var node, lineNum, next, pos;
+
+ function addNum(n) {
+ if (!lineNum) lineNum = scroller.appendChild(document.createElement("DIV"));
+ lineNum.innerHTML = n;
+ pos = lineNum.offsetHeight + lineNum.offsetTop;
+ lineNum = lineNum.nextSibling;
+ }
+ function work() {
+ if (!scroller.parentNode || scroller.parentNode != self.lineNumbers) return;
+
+ var endTime = new Date().getTime() + self.options.lineNumberTime;
+ while (node) {
+ addNum(next++);
+ for (; node && !win.isBR(node); node = node.nextSibling) {
+ var bott = node.offsetTop + node.offsetHeight;
+ while (scroller.offsetHeight && bott - 3 > pos) addNum("&nbsp;");
+ }
+ if (node) node = node.nextSibling;
+ if (new Date().getTime() > endTime) {
+ pending = setTimeout(work, self.options.lineNumberDelay);
+ return;
+ }
+ }
+ // While there are un-processed number DIVs, or the scroller is smaller than the frame...
+ var target = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0));
+ while (lineNum || (scroller.offsetHeight < target && (!scroller.firstChild || scroller.offsetHeight)))
+ addNum(next++);
+ doScroll();
+ }
+ function start() {
+ doScroll();
+ node = body.firstChild;
+ lineNum = scroller.firstChild;
+ pos = 0;
+ next = 1;
+ work();
+ }
+
+ start();
+ var pending = null;
+ function update() {
+ if (pending) clearTimeout(pending);
+ if (self.editor.allClean()) start();
+ else pending = setTimeout(update, 200);
+ }
+ self.updateNumbers = update;
+ var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
+ onResize = win.addEventHandler(win, "resize", update, true);
+ clear = function(){
+ if (pending) clearTimeout(pending);
+ if (self.updateNumbers == update) self.updateNumbers = null;
+ onScroll();
+ onResize();
+ };
+ }
+ (this.options.textWrapping ? wrapping : nonWrapping)();
+ }
+ };
+
+ CodeMirror.InvalidLineHandle = {toString: function(){return "CodeMirror.InvalidLineHandle";}};
+
+ CodeMirror.replace = function(element) {
+ if (typeof element == "string")
+ element = document.getElementById(element);
+ return function(newElement) {
+ element.parentNode.replaceChild(newElement, element);
+ };
+ };
+
+ CodeMirror.fromTextArea = function(area, options) {
+ if (typeof area == "string")
+ area = document.getElementById(area);
+
+ options = options || {};
+ if (area.style.width && options.width == null)
+ options.width = area.style.width;
+ if (area.style.height && options.height == null)
+ options.height = area.style.height;
+ if (options.content == null) options.content = area.value;
+
+ if (area.form) {
+ function updateField() {
+ area.value = mirror.getCode();
+ }
+ if (typeof area.form.addEventListener == "function")
+ area.form.addEventListener("submit", updateField, false);
+ else
+ area.form.attachEvent("onsubmit", updateField);
+ }
+
+ function insert(frame) {
+ if (area.nextSibling)
+ area.parentNode.insertBefore(frame, area.nextSibling);
+ else
+ area.parentNode.appendChild(frame);
+ }
+
+ area.style.display = "none";
+ var mirror = new CodeMirror(insert, options);
+ return mirror;
+ };
+
+ CodeMirror.isProbablySupported = function() {
+ // This is rather awful, but can be useful.
+ var match;
+ if (window.opera)
+ return Number(window.opera.version()) >= 9.52;
+ else if (/Apple Computers, Inc/.test(navigator.vendor) && (match = navigator.userAgent.match(/Version\/(\d+(?:\.\d+)?)\./)))
+ return Number(match[1]) >= 3;
+ else if (document.selection && window.ActiveXObject && (match = navigator.userAgent.match(/MSIE (\d+(?:\.\d*)?)\b/)))
+ return Number(match[1]) >= 6;
+ else if (match = navigator.userAgent.match(/gecko\/(\d{8})/i))
+ return Number(match[1]) >= 20050901;
+ else if (match = navigator.userAgent.match(/AppleWebKit\/(\d+)/))
+ return Number(match[1]) >= 525;
+ else
+ return null;
+ };
+
+ return CodeMirror;
+})();
1,465 lib/codemirror/js/editor.js
@@ -0,0 +1,1465 @@
+/* The Editor object manages the content of the editable frame. It
+ * catches events, colours nodes, and indents lines. This file also
+ * holds some functions for transforming arbitrary DOM structures into
+ * plain sequences of <span> and <br> elements
+ */
+
+var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
+var webkit = /AppleWebKit/.test(navigator.userAgent);
+var safari = /Apple Computers, Inc/.test(navigator.vendor);
+var gecko = /gecko\/(\d{8})/i.test(navigator.userAgent);
+
+// Make sure a string does not contain two consecutive 'collapseable'
+// whitespace characters.
+function makeWhiteSpace(n) {
+ var buffer = [], nb = true;
+ for (; n > 0; n--) {
+ buffer.push((nb || n == 1) ? nbsp : " ");
+ nb = !nb;
+ }
+ return buffer.join("");
+}
+
+// Create a set of white-space characters that will not be collapsed
+// by the browser, but will not break text-wrapping either.
+function fixSpaces(string) {
+ if (string.charAt(0) == " ") string = nbsp + string.slice(1);
+ return string.replace(/\t/g, function(){return makeWhiteSpace(indentUnit);})
+ .replace(/[ \u00a0]{2,}/g, function(s) {return makeWhiteSpace(s.length);});
+}
+
+function cleanText(text) {
+ return text.replace(/\u00a0/g, " ").replace(/\u200b/g, "");
+}
+
+// Create a SPAN node with the expected properties for document part
+// spans.
+function makePartSpan(value, doc) {
+ var text = value;
+ if (value.nodeType == 3) text = value.nodeValue;
+ else value = doc.createTextNode(text);
+
+ var span = doc.createElement("SPAN");
+ span.isPart = true;
+ span.appendChild(value);
+ span.currentText = text;
+ return span;
+}
+
+// On webkit, when the last BR of the document does not have text
+// behind it, the cursor can not be put on the line after it. This
+// makes pressing enter at the end of the document occasionally do
+// nothing (or at least seem to do nothing). To work around it, this
+// function makes sure the document ends with a span containing a
+// zero-width space character. The traverseDOM iterator filters such
+// character out again, so that the parsers won't see them. This
+// function is called from a few strategic places to make sure the
+// zwsp is restored after the highlighting process eats it.
+var webkitLastLineHack = webkit ?
+ function(container) {
+ var last = container.lastChild;
+ if (!last || !last.isPart || last.textContent != "\u200b")
+ container.appendChild(makePartSpan("\u200b", container.ownerDocument));
+ } : function() {};
+
+var Editor = (function(){
+ // The HTML elements whose content should be suffixed by a newline
+ // when converting them to flat text.
+ var newlineElements = {"P": true, "DIV": true, "LI": true};
+
+ function asEditorLines(string) {
+ var tab = makeWhiteSpace(indentUnit);
+ return map(string.replace(/\t/g, tab).replace(/\u00a0/g, " ").replace(/\r\n?/g, "\n").split("\n"), fixSpaces);
+ }
+
+ // Helper function for traverseDOM. Flattens an arbitrary DOM node
+ // into an array of textnodes and <br> tags.
+ function simplifyDOM(root, atEnd) {
+ var doc = root.ownerDocument;
+ var result = [];
+ var leaving = true;
+
+ function simplifyNode(node, top) {
+ if (node.nodeType == 3) {
+ var text = node.nodeValue = fixSpaces(node.nodeValue.replace(/[\r\u200b]/g, "").replace(/\n/g, " "));
+ if (text.length) leaving = false;
+ result.push(node);
+ }
+ else if (isBR(node) && node.childNodes.length == 0) {
+ leaving = true;
+ result.push(node);
+ }
+ else {
+ forEach(node.childNodes, simplifyNode);
+ if (!leaving && newlineElements.hasOwnProperty(node.nodeName.toUpperCase())) {
+ leaving = true;
+ if (!atEnd || !top)
+ result.push(doc.createElement("BR"));
+ }
+ }
+ }
+
+ simplifyNode(root, true);
+ return result;
+ }
+
+ // Creates a MochiKit-style iterator that goes over a series of DOM
+ // nodes. The values it yields are strings, the textual content of
+ // the nodes. It makes sure that all nodes up to and including the
+ // one whose text is being yielded have been 'normalized' to be just
+ // <span> and <br> elements.
+ // See the story.html file for some short remarks about the use of
+ // continuation-passing style in this iterator.
+ function traverseDOM(start){
+ function _yield(value, c){cc = c; return value;}
+ function push(fun, arg, c){return function(){return fun(arg, c);};}
+ function stop(){cc = stop; throw StopIteration;};
+ var cc = push(scanNode, start, stop);
+ var owner = start.ownerDocument;
+ var nodeQueue = [];
+
+ // Create a function that can be used to insert nodes after the
+ // one given as argument.
+ function pointAt(node){
+ var parent = node.parentNode;
+ var next = node.nextSibling;
+ return function(newnode) {
+ parent.insertBefore(newnode, next);
+ };
+ }
+ var point = null;
+
+ // This an Opera-specific hack -- always insert an empty span
+ // between two BRs, because Opera's cursor code gets terribly
+ // confused when the cursor is between two BRs.
+ var afterBR = true;
+
+ // Insert a normalized node at the current point. If it is a text
+ // node, wrap it in a <span>, and give that span a currentText
+ // property -- this is used to cache the nodeValue, because
+ // directly accessing nodeValue is horribly slow on some browsers.
+ // The dirty property is used by the highlighter to determine
+ // which parts of the document have to be re-highlighted.
+ function insertPart(part){
+ var text = "\n";
+ if (part.nodeType == 3) {
+ select.snapshotChanged();
+ part = makePartSpan(part, owner);
+ text = part.currentText;
+ afterBR = false;
+ }
+ else {
+ if (afterBR && window.opera)
+ point(makePartSpan("", owner));
+ afterBR = true;
+ }
+ part.dirty = true;
+ nodeQueue.push(part);
+ point(part);
+ return text;
+ }
+
+ // Extract the text and newlines from a DOM node, insert them into
+ // the document, and yield the textual content. Used to replace
+ // non-normalized nodes.
+ function writeNode(node, c, end) {
+ var toYield = [];
+ forEach(simplifyDOM(node, end), function(part) {
+ toYield.push(insertPart(part));
+ });
+ return _yield(toYield.join(""), c);
+ }
+
+ // Check whether a node is a normalized <span> element.
+ function partNode(node){
+ if (node.isPart && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
+ node.currentText = node.firstChild.nodeValue;
+ return !/[\n\t\r]/.test(node.currentText);
+ }
+ return false;
+ }
+
+ // Handle a node. Add its successor to the continuation if there
+ // is one, find out whether the node is normalized. If it is,
+ // yield its content, otherwise, normalize it (writeNode will take
+ // care of yielding).
+ function scanNode(node, c){
+ if (node.nextSibling)
+ c = push(scanNode, node.nextSibling, c);
+
+ if (partNode(node)){
+ nodeQueue.push(node);
+ afterBR = false;
+ return _yield(node.currentText, c);
+ }
+ else if (isBR(node)) {
+ if (afterBR && window.opera)
+ node.parentNode.insertBefore(makePartSpan("", owner), node);
+ nodeQueue.push(node);
+ afterBR = true;
+ return _yield("\n", c);
+ }
+ else {
+ var end = !node.nextSibling;
+ point = pointAt(node);
+ removeElement(node);
+ return writeNode(node, c, end);
+ }
+ }
+
+ // MochiKit iterators are objects with a next function that
+ // returns the next value or throws StopIteration when there are
+ // no more values.
+ return {next: function(){return cc();}, nodes: nodeQueue};
+ }
+
+ // Determine the text size of a processed node.
+ function nodeSize(node) {
+ return isBR(node) ? 1 : node.currentText.length;
+ }
+
+ // Search backwards through the top-level nodes until the next BR or
+ // the start of the frame.
+ function startOfLine(node) {
+ while (node && !isBR(node)) node = node.previousSibling;
+ return node;
+ }
+ function endOfLine(node, container) {
+ if (!node) node = container.firstChild;
+ else if (isBR(node)) node = node.nextSibling;
+
+ while (node && !isBR(node)) node = node.nextSibling;
+ return node;
+ }
+
+ function time() {return new Date().getTime();}
+
+ // Client interface for searching the content of the editor. Create
+ // these by calling CodeMirror.getSearchCursor. To use, call
+ // findNext on the resulting object -- this returns a boolean
+ // indicating whether anything was found, and can be called again to
+ // skip to the next find. Use the select and replace methods to
+ // actually do something with the found locations.
+ function SearchCursor(editor, string, fromCursor, caseFold) {
+ this.editor = editor;
+ this.caseFold = caseFold;
+ if (caseFold) string = string.toLowerCase();
+ this.history = editor.history;
+ this.history.commit();
+
+ // Are we currently at an occurrence of the search string?
+ this.atOccurrence = false;
+ // The object stores a set of nodes coming after its current
+ // position, so that when the current point is taken out of the
+ // DOM tree, we can still try to continue.
+ this.fallbackSize = 15;
+ var cursor;
+ // Start from the cursor when specified and a cursor can be found.
+ if (fromCursor && (cursor = select.cursorPos(this.editor.container))) {
+ this.line = cursor.node;
+ this.offset = cursor.offset;
+ }
+ else {
+ this.line = null;
+ this.offset = 0;
+ }
+ this.valid = !!string;
+
+ // Create a matcher function based on the kind of string we have.
+ var target = string.split("\n"), self = this;
+ this.matches = (target.length == 1) ?
+ // For one-line strings, searching can be done simply by calling
+ // indexOf on the current line.
+ function() {
+ var line = cleanText(self.history.textAfter(self.line).slice(self.offset));
+ var match = (self.caseFold ? line.toLowerCase() : line).indexOf(string);
+ if (match > -1)
+ return {from: {node: self.line, offset: self.offset + match},
+ to: {node: self.line, offset: self.offset + match + string.length}};
+ } :
+ // Multi-line strings require internal iteration over lines, and
+ // some clunky checks to make sure the first match ends at the
+ // end of the line and the last match starts at the start.
+ function() {
+ var firstLine = cleanText(self.history.textAfter(self.line).slice(self.offset));
+ var match = (self.caseFold ? firstLine.toLowerCase() : firstLine).lastIndexOf(target[0]);
+ if (match == -1 || match != firstLine.length - target[0].length)
+ return false;
+ var startOffset = self.offset + match;
+
+ var line = self.history.nodeAfter(self.line);
+ for (var i = 1; i < target.length - 1; i++) {
+ var lineText = cleanText(self.history.textAfter(line));
+ if ((self.caseFold ? lineText.toLowerCase() : lineText) != target[i])
+ return false;
+ line = self.history.nodeAfter(line);
+ }
+
+ var lastLine = cleanText(self.history.textAfter(line));
+ if ((self.caseFold ? lastLine.toLowerCase() : lastLine).indexOf(target[target.length - 1]) != 0)
+ return false;
+
+ return {from: {node: self.line, offset: startOffset},
+ to: {node: line, offset: target[target.length - 1].length}};
+ };
+ }
+
+ SearchCursor.prototype = {
+ findNext: function() {
+ if (!this.valid) return false;
+ this.atOccurrence = false;
+ var self = this;
+
+ // Go back to the start of the document if the current line is
+ // no longer in the DOM tree.
+ if (this.line && !this.line.parentNode) {
+ this.line = null;
+ this.offset = 0;
+ }
+
+ // Set the cursor's position one character after the given
+ // position.
+ function saveAfter(pos) {
+ if (self.history.textAfter(pos.node).length > pos.offset) {
+ self.line = pos.node;
+ self.offset = pos.offset + 1;
+ }
+ else {
+ self.line = self.history.nodeAfter(pos.node);
+ self.offset = 0;
+ }
+ }
+
+ while (true) {
+ var match = this.matches();
+ // Found the search string.
+ if (match) {
+ this.atOccurrence = match;
+ saveAfter(match.from);
+ return true;
+ }
+ this.line = this.history.nodeAfter(this.line);
+ this.offset = 0;
+ // End of document.
+ if (!this.line) {
+ this.valid = false;
+ return false;
+ }
+ }
+ },
+
+ select: function() {
+ if (this.atOccurrence) {
+ select.setCursorPos(this.editor.container, this.atOccurrence.from, this.atOccurrence.to);
+ select.scrollToCursor(this.editor.container);
+ }
+ },
+
+ replace: function(string) {
+ if (this.atOccurrence) {
+ var end = this.editor.replaceRange(this.atOccurrence.from, this.atOccurrence.to, string);
+ this.line = end.node;
+ this.offset = end.offset;
+ this.atOccurrence = false;
+ }
+ }
+ };
+
+ // The Editor object is the main inside-the-iframe interface.
+ function Editor(options) {
+ this.options = options;
+ window.indentUnit = options.indentUnit;
+ this.parent = parent;
+ this.doc = document;
+ var container = this.container = this.doc.body;
+ this.win = window;
+ this.history = new History(container, options.undoDepth, options.undoDelay, this);
+ var self = this;
+
+ if (!Editor.Parser)
+ throw "No parser loaded.";
+ if (options.parserConfig && Editor.Parser.configure)
+ Editor.Parser.configure(options.parserConfig);
+
+ if (!options.readOnly)
+ select.setCursorPos(container, {node: null, offset: 0});
+
+ this.dirty = [];
+ this.importCode(options.content || "");
+ this.history.onChange = options.onChange;
+
+ if (!options.readOnly) {
+ if (options.continuousScanning !== false) {
+ this.scanner = this.documentScanner(options.passTime);
+ this.delayScanning();
+ }
+
+ function setEditable() {
+ // In IE, designMode frames can not run any scripts, so we use
+ // contentEditable instead.
+ if (document.body.contentEditable != undefined && internetExplorer)
+ document.body.contentEditable = "true";
+ else
+ document.designMode = "on";
+
+ document.documentElement.style.borderWidth = "0";
+ if (!options.textWrapping)
+ container.style.whiteSpace = "nowrap";
+ }
+
+ // If setting the frame editable fails, try again when the user
+ // focus it (happens when the frame is not visible on
+ // initialisation, in Firefox).
+ try {
+ setEditable();
+ }
+ catch(e) {
+ var focusEvent = addEventHandler(document, "focus", function() {
+ focusEvent();
+ setEditable();
+ }, true);
+ }
+
+ addEventHandler(document, "keydown", method(this, "keyDown"));
+ addEventHandler(document, "keypress", method(this, "keyPress"));
+ addEventHandler(document, "keyup", method(this, "keyUp"));
+
+ function cursorActivity() {self.cursorActivity(false);}
+ addEventHandler(document.body, "mouseup", cursorActivity);
+ addEventHandler(document.body, "cut", cursorActivity);
+
+ // workaround for a gecko bug [?] where going forward and then
+ // back again breaks designmode (no more cursor)
+ if (gecko)
+ addEventHandler(this.win, "pagehide", function(){self.unloaded = true;});
+
+ addEventHandler(document.body, "paste", function(event) {
+ cursorActivity();
+ var text = null;
+ try {
+ var clipboardData = event.clipboardData || window.clipboardData;
+ if (clipboardData) text = clipboardData.getData('Text');
+ }
+ catch(e) {}
+ if (text !== null) {
+ event.stop();
+ self.replaceSelection(text);
+ select.scrollToCursor(self.container);
+ }
+ });
+
+ if (this.options.autoMatchParens)
+ addEventHandler(document.body, "click", method(this, "scheduleParenHighlight"));
+ }
+ else if (!options.textWrapping) {
+ container.style.whiteSpace = "nowrap";
+ }
+ }
+
+ function isSafeKey(code) {
+ return (code >= 16 && code <= 18) || // shift, control, alt
+ (code >= 33 && code <= 40); // arrows, home, end
+ }
+
+ Editor.prototype = {
+ // Import a piece of code into the editor.
+ importCode: function(code) {
+ this.history.push(null, null, asEditorLines(code));
+ this.history.reset();
+ },
+
+ // Extract the code from the editor.
+ getCode: function() {
+ if (!this.container.firstChild)
+ return "";
+
+ var accum = [];
+ select.markSelection(this.win);
+ forEach(traverseDOM(this.container.firstChild), method(accum, "push"));
+ webkitLastLineHack(this.container);
+ select.selectMarked();
+ return cleanText(accum.join(""));
+ },
+
+ checkLine: function(node) {
+ if (node === false || !(node == null || node.parentNode == this.container))
+ throw parent.CodeMirror.InvalidLineHandle;
+ },
+
+ cursorPosition: function(start) {
+ if (start == null) start = true;
+ var pos = select.cursorPos(this.container, start);
+ if (pos) return {line: pos.node, character: pos.offset};
+ else return {line: null, character: 0};
+ },
+
+ firstLine: function() {
+ return null;
+ },
+
+ lastLine: function() {
+ if (this.container.lastChild) return startOfLine(this.container.lastChild);
+ else return null;
+ },
+
+ nextLine: function(line) {
+ this.checkLine(line);
+ var end = endOfLine(line, this.container);
+ return end || false;
+ },
+
+ prevLine: function(line) {
+ this.checkLine(line);
+ if (line == null) return false;
+ return startOfLine(line.previousSibling);
+ },
+
+ visibleLineCount: function() {
+ var line = this.container.firstChild;
+ while (line && isBR(line)) line = line.nextSibling; // BR heights are unreliable
+ if (!line) return false;
+ var innerHeight = (window.innerHeight
+ || document.documentElement.clientHeight
+ || document.body.clientHeight);
+ return Math.floor(innerHeight / line.offsetHeight);
+ },
+
+ selectLines: function(startLine, startOffset, endLine, endOffset) {
+ this.checkLine(startLine);
+ var start = {node: startLine, offset: startOffset}, end = null;
+ if (endOffset !== undefined) {
+ this.checkLine(endLine);
+ end = {node: endLine, offset: endOffset};
+ }
+ select.setCursorPos(this.container, start, end);
+ select.scrollToCursor(this.container);
+ },
+
+ lineContent: function(line) {
+ var accum = [];
+ for (line = line ? line.nextSibling : this.container.firstChild;
+ line && !isBR(line); line = line.nextSibling)
+ accum.push(nodeText(line));
+ return cleanText(accum.join(""));
+ },
+
+ setLineContent: function(line, content) {
+ this.history.commit();
+ this.replaceRange({node: line, offset: 0},
+ {node: line, offset: this.history.textAfter(line).length},
+ content);
+ this.addDirtyNode(line);
+ this.scheduleHighlight();
+ },
+
+ removeLine: function(line) {
+ var node = line ? line.nextSibling : this.container.firstChild;
+ while (node) {
+ var next = node.nextSibling;
+ removeElement(node);
+ if (isBR(node)) break;
+ node = next;
+ }
+ this.addDirtyNode(line);
+ this.scheduleHighlight();
+ },
+
+ insertIntoLine: function(line, position, content) {
+ var before = null;
+ if (position == "end") {
+ before = endOfLine(line, this.container);
+ }
+ else {
+ for (var cur = line ? line.nextSibling : this.container.firstChild; cur; cur = cur.nextSibling) {
+ if (position == 0) {
+ before = cur;
+ break;
+ }
+ var text = nodeText(cur);
+ if (text.length > position) {
+ before = cur.nextSibling;
+ content = text.slice(0, position) + content + text.slice(position);
+ removeElement(cur);
+ break;
+ }
+ position -= text.length;
+ }
+ }
+
+ var lines = asEditorLines(content), doc = this.container.ownerDocument;
+ for (var i = 0; i < lines.length; i++) {
+ if (i > 0) this.container.insertBefore(doc.createElement("BR"), before);
+ this.container.insertBefore(makePartSpan(lines[i], doc), before);
+ }
+ this.addDirtyNode(line);
+ this.scheduleHighlight();
+ },
+
+ // Retrieve the selected text.
+ selectedText: function() {
+ var h = this.history;
+ h.commit();
+
+ var start = select.cursorPos(this.container, true),
+ end = select.cursorPos(this.container, false);
+ if (!start || !end) return "";
+
+ if (start.node == end.node)
+ return h.textAfter(start.node).slice(start.offset, end.offset);
+
+ var text = [h.textAfter(start.node).slice(start.offset)];
+ for (var pos = h.nodeAfter(start.node); pos != end.node; pos = h.nodeAfter(pos))
+ text.push(h.textAfter(pos));
+ text.push(h.textAfter(end.node).slice(0, end.offset));
+ return cleanText(text.join("\n"));
+ },
+
+ // Replace the selection with another piece of text.
+ replaceSelection: function(text) {
+ this.history.commit();
+
+ var start = select.cursorPos(this.container, true),
+ end = select.cursorPos(this.container, false);
+ if (!start || !end) return;
+
+ end = this.replaceRange(start, end, text);
+ select.setCursorPos(this.container, end);
+ webkitLastLineHack(this.container);
+ },
+
+ reroutePasteEvent: function() {
+ if (this.capturingPaste || window.opera) return;
+ this.capturingPaste = true;
+ var te = window.frameElement.CodeMirror.textareaHack;
+ parent.focus();
+ te.value = "";
+ te.focus();
+
+ var self = this;
+ this.parent.setTimeout(function() {
+ self.capturingPaste = false;
+ self.win.focus();
+ if (self.selectionSnapshot) // IE hack
+ self.win.select.setBookmark(self.container, self.selectionSnapshot);
+ var text = te.value;
+ if (text) {
+ self.replaceSelection(text);
+ select.scrollToCursor(self.container);
+ }
+ }, 10);
+ },
+
+ replaceRange: function(from, to, text) {
+ var lines = asEditorLines(text);
+ lines[0] = this.history.textAfter(from.node).slice(0, from.offset) + lines[0];
+ var lastLine = lines[lines.length - 1];
+ lines[lines.length - 1] = lastLine + this.history.textAfter(to.node).slice(to.offset);
+ var end = this.history.nodeAfter(to.node);
+ this.history.push(from.node, end, lines);
+ return {node: this.history.nodeBefore(end),
+ offset: lastLine.length};
+ },
+
+ getSearchCursor: function(string, fromCursor, caseFold) {
+ return new SearchCursor(this, string, fromCursor, caseFold);
+ },
+
+ // Re-indent the whole buffer
+ reindent: function() {
+ if (this.container.firstChild)
+ this.indentRegion(null, this.container.lastChild);
+ },
+
+ reindentSelection: function(direction) {
+ if (!select.somethingSelected(this.win)) {
+ this.indentAtCursor(direction);
+ }
+ else {
+ var start = select.selectionTopNode(this.container, true),
+ end = select.selectionTopNode(this.container, false);
+ if (start === false || end === false) return;
+ this.indentRegion(start, end, direction);
+ }
+ },
+
+ grabKeys: function(eventHandler, filter) {
+ this.frozen = eventHandler;
+ this.keyFilter = filter;
+ },
+ ungrabKeys: function() {
+ this.frozen = "leave";
+ this.keyFilter = null;
+ },
+
+ setParser: function(name) {
+ Editor.Parser = window[name];
+ if (this.container.firstChild) {
+ forEach(this.container.childNodes, function(n) {
+ if (n.nodeType != 3) n.dirty = true;
+ });
+ this.addDirtyNode(this.firstChild);
+ this.scheduleHighlight();
+ }
+ },
+
+ // Intercept enter and tab, and assign their new functions.
+ keyDown: function(event) {
+ if (this.frozen == "leave") this.frozen = null;
+ if (this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode, event))) {
+ event.stop();
+ this.frozen(event);
+ return;
+ }
+
+ var code = event.keyCode;
+ // Don't scan when the user is typing.
+ this.delayScanning();
+ // Schedule a paren-highlight event, if configured.
+ if (this.options.autoMatchParens)
+ this.scheduleParenHighlight();
+
+ // The various checks for !altKey are there because AltGr sets both
+ // ctrlKey and altKey to true, and should not be recognised as
+ // Control.
+ if (code == 13) { // enter
+ if (event.ctrlKey && !event.altKey) {
+ this.reparseBuffer();
+ }
+ else {
+ select.insertNewlineAtCursor(this.win);
+ this.indentAtCursor();
+ select.scrollToCursor(this.container);
+ }
+ event.stop();
+ }
+ else if (code == 9 && this.options.tabMode != "default" && !event.ctrlKey) { // tab
+ this.handleTab(!event.shiftKey);
+ event.stop();
+ }
+ else if (code == 32 && event.shiftKey && this.options.tabMode == "default") { // space
+ this.handleTab(true);
+ event.stop();
+ }
+ else if (code == 36 && !event.shiftKey && !event.ctrlKey) { // home
+ if (this.home()) event.stop();
+ }
+ else if (code == 35 && !event.shiftKey && !event.ctrlKey) { // end
+ if (this.end()) event.stop();
+ }
+ // Only in Firefox is the default behavior for PgUp/PgDn correct.
+ else if (code == 33 && !event.shiftKey && !event.ctrlKey && !gecko) { // PgUp
+ if (this.pageUp()) event.stop();
+ }
+ else if (code == 34 && !event.shiftKey && !event.ctrlKey && !gecko) { // PgDn
+ if (this.pageDown()) event.stop();
+ }
+ else if ((code == 219 || code == 221) && event.ctrlKey && !event.altKey) { // [, ]
+ this.highlightParens(event.shiftKey, true);
+ event.stop();
+ }
+ else if (event.metaKey && !event.shiftKey && (code == 37 || code == 39)) { // Meta-left/right
+ var cursor = select.selectionTopNode(this.container);
+ if (cursor === false || !this.container.firstChild) return;
+
+ if (code == 37) select.focusAfterNode(startOfLine(cursor), this.container);
+ else {
+ var end = endOfLine(cursor, this.container);
+ select.focusAfterNode(end ? end.previousSibling : this.container.lastChild, this.container);
+ }
+ event.stop();
+ }
+ else if ((event.ctrlKey || event.metaKey) && !event.altKey) {
+ if ((event.shiftKey && code == 90) || code == 89) { // shift-Z, Y
+ select.scrollToNode(this.history.redo());
+ event.stop();
+ }
+ else if (code == 90 || (safari && code == 8)) { // Z, backspace
+ select.scrollToNode(this.history.undo());
+ event.stop();
+ }
+ else if (code == 83 && this.options.saveFunction) { // S
+ this.options.saveFunction();
+ event.stop();
+ }
+ else if (internetExplorer && code == 86) {
+ this.reroutePasteEvent();
+ }
+ }
+ },
+
+ // Check for characters that should re-indent the current line,
+ // and prevent Opera from handling enter and tab anyway.
+ keyPress: function(event) {
+ var electric = Editor.Parser.electricChars, self = this;
+ // Hack for Opera, and Firefox on OS X, in which stopping a
+ // keydown event does not prevent the associated keypress event
+ // from happening, so we have to cancel enter and tab again
+ // here.
+ if ((this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode, event))) ||
+ event.code == 13 || (event.code == 9 && this.options.tabMode != "default") ||
+ (event.keyCode == 32 && event.shiftKey && this.options.tabMode == "default"))
+ event.stop();
+ else if (electric && electric.indexOf(event.character) != -1)
+ this.parent.setTimeout(function(){self.indentAtCursor(null);}, 0);
+ else if ((event.character == "v" || event.character == "V")
+ && (event.ctrlKey || event.metaKey) && !event.altKey) // ctrl-V