From 51418c2aaa8b32a22ba715ba9d89eae37054ac95 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 12:27:02 +0300 Subject: [PATCH 001/170] Update lib/server/object.js --- lib/server/object.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/object.js b/lib/server/object.js index bd1e94d4..62f9daca 100644 --- a/lib/server/object.js +++ b/lib/server/object.js @@ -100,7 +100,7 @@ exports.Minify={ }catch(pError){ this._allowed={js:false,css:false,html:false}; return console.log('Could not minify ' + - 'withou minify module\n' + + 'without minify module\n' + 'npm i minify'); } From 4de3721a65fc296bdca39ca0bcc4b3c43d0eb128 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 07:53:39 -0400 Subject: [PATCH 002/170] load fancybox from local directory --- lib/client/viewer.js | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 796cfd95..5a8247ce 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -46,31 +46,38 @@ CloudCommander.Viewer.FancyBox = { load: (function(pParent, pCallBack){ return function(){ var ljsLoad_f = function(){ - var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.pack.js'; - + /* + var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.pack.js'; + */ + var lSrc = pParent.dir + 'jquery.fancybox.pack.js'; CloudCommander.jsload(lSrc,{ - onload: pCallBack, - - onerror: (function() { - CloudCommander.jsload(pParent.dir + - 'jquery.fancybox.pack.js', {onload: pCallBack}); - }) + onload: pCallBack + /* + ,onerror: (function() { + CloudCommander.jsload(pParent.dir + + 'jquery.fancybox.pack.js', {onload: pCallBack}); + }) + */ }); }; - var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css'; - + /* + var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css'; + */ + var lSrc = pParent.dir +'jquery.fancybox.css'; CloudCommander.cssLoad({ src : lSrc, func : { - onload: ljsLoad_f, - onerror: (function() { - CloudCommander.cssLoad({ - src : pParent.dir +'jquery.fancybox.css', - func : ljsLoad_f - }); - }) - } + onload: ljsLoad_f + /* + ,onerror: (function() { + CloudCommander.cssLoad({ + src : pParent.dir +'jquery.fancybox.css', + func : ljsLoad_f + }); + }) + */ + } }); }(); }), From cb7b939f2a6d915c3e6030a63a351f299865bfa9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 08:00:33 -0400 Subject: [PATCH 003/170] added packed css of fancybox --- lib/client/viewer.js | 2 +- lib/client/viewer/fancybox/jquery.fancybox.pack.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 lib/client/viewer/fancybox/jquery.fancybox.pack.css diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 5a8247ce..42e6df93 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -64,7 +64,7 @@ CloudCommander.Viewer.FancyBox = { /* var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css'; */ - var lSrc = pParent.dir +'jquery.fancybox.css'; + var lSrc = pParent.dir +'jquery.fancybox.min.css'; CloudCommander.cssLoad({ src : lSrc, func : { diff --git a/lib/client/viewer/fancybox/jquery.fancybox.pack.css b/lib/client/viewer/fancybox/jquery.fancybox.pack.css new file mode 100644 index 00000000..ec43849e --- /dev/null +++ b/lib/client/viewer/fancybox/jquery.fancybox.pack.css @@ -0,0 +1 @@ +/*! fancyBox v2.0.6 fancyapps.com | fancyapps.com/fancybox/#license */.fancybox-wrap,.fancybox-skin,.fancybox-outer,.fancybox-inner,.fancybox-image,.fancybox-wrap iframe,.fancybox-wrap object,.fancybox-nav,.fancybox-nav span,.fancybox-tmp{padding:0;margin:0;border:0;outline:0;vertical-align:top}.fancybox-wrap{position:absolute;top:0;left:0;z-index:8020}.fancybox-skin{position:relative;background:#f9f9f9;color:#444;text-shadow:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fancybox-opened{z-index:8030}.fancybox-opened .fancybox-skin{-webkit-box-shadow:0 10px 25px rgba(0,0,0,.5);-moz-box-shadow:0 10px 25px rgba(0,0,0,.5);box-shadow:0 10px 25px rgba(0,0,0,.5)}.fancybox-outer,.fancybox-inner{position:relative}.fancybox-inner{overflow:hidden}.fancybox-type-iframe .fancybox-inner{-webkit-overflow-scrolling:touch}.fancybox-error{color:#444;font:14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;margin:0;padding:15px;white-space:nowrap}.fancybox-image,.fancybox-iframe{display:block;width:100%;height:100%}.fancybox-image{max-width:100%;max-height:100%}#fancybox-loading,.fancybox-close,.fancybox-prev span,.fancybox-next span{background-image:url('fancybox_sprite.png')}#fancybox-loading{position:fixed;top:50%;left:50%;margin-top:-22px;margin-left:-22px;background-position:0 -108px;opacity:.8;cursor:pointer;z-index:8060}#fancybox-loading div{width:44px;height:44px;background:url('fancybox_loading.gif') center center no-repeat}.fancybox-close{position:absolute;top:-18px;right:-18px;width:36px;height:36px;cursor:pointer;z-index:8040}.fancybox-nav{position:absolute;top:0;width:40%;height:100%;cursor:pointer;text-decoration:none;background:transparent url('blank.gif');-webkit-tap-highlight-color:rgba(0,0,0,0);z-index:8040}.fancybox-prev{left:0}.fancybox-next{right:0}.fancybox-nav span{position:absolute;top:50%;width:36px;height:34px;margin-top:-18px;cursor:pointer;z-index:8040;visibility:hidden}.fancybox-prev span{left:10px;background-position:0 -36px}.fancybox-next span{right:10px;background-position:0 -72px}.fancybox-nav:hover span{visibility:visible}.fancybox-tmp{position:absolute;top:-9999px;left:-9999px;visibility:hidden}#fancybox-overlay{position:absolute;top:0;left:0;overflow:hidden;display:none;z-index:8010;background:#000}#fancybox-overlay.overlay-fixed{position:fixed;bottom:0;right:0}.fancybox-title{visibility:hidden;font:normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;position:relative;text-shadow:none;z-index:8050}.fancybox-opened .fancybox-title{visibility:visible}.fancybox-title-float-wrap{position:absolute;bottom:0;right:50%;margin-bottom:-35px;z-index:8050;text-align:center}.fancybox-title-float-wrap .child{display:inline-block;margin-right:-100%;padding:2px 20px;background:transparent;background:rgba(0,0,0,.8);-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;text-shadow:0 1px 2px #222;color:#FFF;font-weight:700;line-height:24px;white-space:nowrap}.fancybox-title-outside-wrap{position:relative;margin-top:10px;color:#fff}.fancybox-title-inside-wrap{padding-top:10px}.fancybox-title-over-wrap{position:absolute;bottom:0;left:0;color:#fff;padding:10px;background:#000;background:rgba(0,0,0,.8)} \ No newline at end of file From b1ad2bd34719374e5bf2777e5e9f366d8e9b0751 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 08:01:53 -0400 Subject: [PATCH 004/170] added packed css of fancybox --- lib/client/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 42e6df93..260a4704 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -64,7 +64,7 @@ CloudCommander.Viewer.FancyBox = { /* var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css'; */ - var lSrc = pParent.dir +'jquery.fancybox.min.css'; + var lSrc = pParent.dir +'jquery.fancybox.pack.css'; CloudCommander.cssLoad({ src : lSrc, func : { From e510ee59d30c4b05c9a9458c66aaae5ce2b2791b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 08:15:27 -0400 Subject: [PATCH 005/170] added local copies of codemirror --- lib/client/editor.js | 8 ++++---- lib/client/viewer.js | 24 ++---------------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 1476df59..3ba93df1 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -40,11 +40,11 @@ CloudCommander.Editor.CodeMirror = { var loadAll = function(pParent) { return function(){ CloudCommander.cssLoad({ - src : 'http://codemirror.net/lib/codemirror.css' + src : 'lib/client/editor/codemirror/pack/codemirror.pack.css' }); CloudCommander.cssLoad({ - src : 'http://codemirror.net/theme/night.css' + src : 'lib/client/editor/codemirror/pack/night.pack.css' }); CloudCommander.cssSet({id:'editor', @@ -62,13 +62,13 @@ CloudCommander.Editor.CodeMirror = { '}' }); - CloudCommander.jsload('http://codemirror.net/mode/xml/xml.js', + CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js', showEditor(pParent)); }; }; /* load CodeMirror main module */ - CloudCommander.jsload('http://codemirror.net/lib/codemirror.js', loadAll(this)); + CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', loadAll(this)); }), show : (function(){ /* function shows CodeMirror editor */ diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 260a4704..3d03b0c1 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -45,38 +45,18 @@ CloudCommander.Viewer.FancyBox = { */ load: (function(pParent, pCallBack){ return function(){ - var ljsLoad_f = function(){ - /* - var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.pack.js'; - */ + var ljsLoad_f = function(){ var lSrc = pParent.dir + 'jquery.fancybox.pack.js'; CloudCommander.jsload(lSrc,{ onload: pCallBack - /* - ,onerror: (function() { - CloudCommander.jsload(pParent.dir + - 'jquery.fancybox.pack.js', {onload: pCallBack}); - }) - */ }); }; - /* - var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css'; - */ var lSrc = pParent.dir +'jquery.fancybox.pack.css'; CloudCommander.cssLoad({ src : lSrc, func : { - onload: ljsLoad_f - /* - ,onerror: (function() { - CloudCommander.cssLoad({ - src : pParent.dir +'jquery.fancybox.css', - func : ljsLoad_f - }); - }) - */ + onload: ljsLoad_f } }); }(); From 0a1802dde8491df3d319ec908a7f1dd585ef01f0 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 08:16:16 -0400 Subject: [PATCH 006/170] added local copies of codemirror --- lib/client/editor/codemirror/codemirror.css | 169 + lib/client/editor/codemirror/codemirror.js | 3229 +++++++++++++++++ lib/client/editor/codemirror/mode/xml.js | 326 ++ .../codemirror/pack/codemirror.pack.css | 1 + .../editor/codemirror/pack/codemirror.pack.js | 1 + .../editor/codemirror/pack/night.pack.css | 1 + lib/client/editor/codemirror/pack/xml.pack.js | 1 + lib/client/editor/codemirror/theme/night.css | 21 + 8 files changed, 3749 insertions(+) create mode 100644 lib/client/editor/codemirror/codemirror.css create mode 100644 lib/client/editor/codemirror/codemirror.js create mode 100644 lib/client/editor/codemirror/mode/xml.js create mode 100644 lib/client/editor/codemirror/pack/codemirror.pack.css create mode 100644 lib/client/editor/codemirror/pack/codemirror.pack.js create mode 100644 lib/client/editor/codemirror/pack/night.pack.css create mode 100644 lib/client/editor/codemirror/pack/xml.pack.js create mode 100644 lib/client/editor/codemirror/theme/night.css diff --git a/lib/client/editor/codemirror/codemirror.css b/lib/client/editor/codemirror/codemirror.css new file mode 100644 index 00000000..03342c18 --- /dev/null +++ b/lib/client/editor/codemirror/codemirror.css @@ -0,0 +1,169 @@ +.CodeMirror { + line-height: 1em; + font-family: monospace; + + /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */ + position: relative; + /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */ + overflow: hidden; +} + +.CodeMirror-scroll { + overflow-x: auto; + overflow-y: hidden; + height: 300px; + /* This is needed to prevent an IE[67] bug where the scrolled content + is visible outside of the scrolling box. */ + position: relative; + outline: none; +} + +/* Vertical scrollbar */ +.CodeMirror-scrollbar { + float: right; + overflow-x: hidden; + overflow-y: scroll; + + /* This corrects for the 1px gap introduced to the left of the scrollbar + by the rule for .CodeMirror-scrollbar-inner. */ + margin-left: -1px; +} +.CodeMirror-scrollbar-inner { + /* This needs to have a nonzero width in order for the scrollbar to appear + in Firefox and IE9. */ + width: 1px; +} +.CodeMirror-scrollbar.cm-sb-overlap { + /* Ensure that the scrollbar appears in Lion, and that it overlaps the content + rather than sitting to the right of it. */ + position: absolute; + z-index: 1; + float: none; + right: 0; + min-width: 12px; +} +.CodeMirror-scrollbar.cm-sb-nonoverlap { + min-width: 12px; +} +.CodeMirror-scrollbar.cm-sb-ie7 { + min-width: 18px; +} + +.CodeMirror-gutter { + position: absolute; left: 0; top: 0; + z-index: 10; + background-color: #f7f7f7; + border-right: 1px solid #eee; + min-width: 2em; + height: 100%; +} +.CodeMirror-gutter-text { + color: #aaa; + text-align: right; + padding: .4em .2em .4em .4em; + white-space: pre !important; + cursor: default; +} +.CodeMirror-lines { + padding: .4em; + white-space: pre; + cursor: text; +} +.CodeMirror-lines * { + /* Necessary for throw-scrolling to decelerate properly on Safari. */ + pointer-events: none; +} + +.CodeMirror pre { + -moz-border-radius: 0; + -webkit-border-radius: 0; + -o-border-radius: 0; + border-radius: 0; + border-width: 0; margin: 0; padding: 0; background: transparent; + font-family: inherit; + font-size: inherit; + padding: 0; margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; +} + +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} +.CodeMirror-wrap .CodeMirror-scroll { + overflow-x: hidden; +} + +.CodeMirror textarea { + outline: none !important; +} + +.CodeMirror pre.CodeMirror-cursor { + z-index: 10; + position: absolute; + visibility: hidden; + border-left: 1px solid black; + border-right: none; + width: 0; +} +.cm-keymap-fat-cursor pre.CodeMirror-cursor { + width: auto; + border: 0; + background: transparent; + background: rgba(0, 200, 0, .4); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); +} +/* Kludge to turn off filter in ie9+, which also accepts rgba */ +.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} +.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} +.CodeMirror-focused pre.CodeMirror-cursor { + visibility: visible; +} + +div.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; } + +.CodeMirror-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* Default theme */ + +.cm-s-default span.cm-keyword {color: #708;} +.cm-s-default span.cm-atom {color: #219;} +.cm-s-default span.cm-number {color: #164;} +.cm-s-default span.cm-def {color: #00f;} +.cm-s-default span.cm-variable {color: black;} +.cm-s-default span.cm-variable-2 {color: #05a;} +.cm-s-default span.cm-variable-3 {color: #085;} +.cm-s-default span.cm-property {color: black;} +.cm-s-default span.cm-operator {color: black;} +.cm-s-default span.cm-comment {color: #a50;} +.cm-s-default span.cm-string {color: #a11;} +.cm-s-default span.cm-string-2 {color: #f50;} +.cm-s-default span.cm-meta {color: #555;} +.cm-s-default span.cm-error {color: #f00;} +.cm-s-default span.cm-qualifier {color: #555;} +.cm-s-default span.cm-builtin {color: #30a;} +.cm-s-default span.cm-bracket {color: #cc7;} +.cm-s-default span.cm-tag {color: #170;} +.cm-s-default span.cm-attribute {color: #00c;} +.cm-s-default span.cm-header {color: blue;} +.cm-s-default span.cm-quote {color: #090;} +.cm-s-default span.cm-hr {color: #999;} +.cm-s-default span.cm-link {color: #00c;} + +span.cm-header, span.cm-strong {font-weight: bold;} +span.cm-em {font-style: italic;} +span.cm-emstrong {font-style: italic; font-weight: bold;} +span.cm-link {text-decoration: underline;} + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} \ No newline at end of file diff --git a/lib/client/editor/codemirror/codemirror.js b/lib/client/editor/codemirror/codemirror.js new file mode 100644 index 00000000..97298bb2 --- /dev/null +++ b/lib/client/editor/codemirror/codemirror.js @@ -0,0 +1,3229 @@ +// All functions that need access to the editor's state live inside +// the CodeMirror function. Below that, at the bottom of the file, +// some utilities are defined. + +// CodeMirror is the only global var we claim +var CodeMirror = (function() { + // This is the function that produces an editor instance. Its + // closure is used to store the editor state. + function CodeMirror(place, givenOptions) { + // Determine effective options based on given values and defaults. + var options = {}, defaults = CodeMirror.defaults; + for (var opt in defaults) + if (defaults.hasOwnProperty(opt)) + options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; + + // The element in which the editor lives. + var wrapper = document.createElement("div"); + wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : ""); + // This mess creates the base DOM structure for the editor. + wrapper.innerHTML = + '
' + // Wraps and hides input textarea + '
' + + '
' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself. + '
' + // The empty scrollbar content, used solely for managing the scrollbar thumb. + '
' + // This must be before the scroll area because it's float-right. + '
' + + '
' + // Set to the height of the text, causes scrolling + '
' + // Moved around its parent to cover visible view + '
' + + // Provides positioning relative to (visible) text origin + '
' + + // Used to measure text size + '
' + + '
 
' + // Absolutely positioned blinky cursor + '' + // Used to force a width + '
' + // DIVs containing the selection and the actual code + '
'; + if (place.appendChild) place.appendChild(wrapper); else place(wrapper); + // I've never seen more elegant code in my life. + var inputDiv = wrapper.firstChild, input = inputDiv.firstChild, + scroller = wrapper.lastChild, code = scroller.firstChild, + mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild, + lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild, + cursor = measure.nextSibling, widthForcer = cursor.nextSibling, + selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling, + scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild; + themeChanged(); keyMapChanged(); + // Needed to hide big blue blinking cursor on Mobile Safari + if (ios) input.style.width = "0px"; + if (!webkit) scroller.draggable = true; + lineSpace.style.outline = "none"; + if (options.tabindex != null) input.tabIndex = options.tabindex; + if (options.autofocus) focusInput(); + if (!options.gutter && !options.lineNumbers) gutter.style.display = "none"; + // Needed to handle Tab key in KHTML + if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute"; + + // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and + // make it overlap the content. (But we only do this if the scrollbar doesn't already + // have a natural width. If the mouse is plugged in or the user sets the system pref + // to always show scrollbars, the scrollbar shouldn't overlap.) + if (mac_geLion) { + scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap"); + } else if (ie_lt8) { + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + scrollbar.className += " cm-sb-ie7"; + } + + // Check for problem with IE innerHTML not working when we have a + // P (or similar) parent node. + try { stringWidth("x"); } + catch (e) { + if (e.message.match(/runtime/i)) + e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)"); + throw e; + } + + // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval. + var poll = new Delayed(), highlight = new Delayed(), blinker; + + // mode holds a mode API object. doc is the tree of Line objects, + // work an array of lines that should be parsed, and history the + // undo history (instance of History constructor). + var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused; + loadMode(); + // The selection. These are always maintained to point at valid + // positions. Inverted is used to remember that the user is + // selecting bottom-to-top. + var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false}; + // Selection-related flags. shiftSelecting obviously tracks + // whether the user is holding shift. + var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText, + overwrite = false, suppressEdits = false; + // Variables used by startOperation/endOperation to track what + // happened during the operation. + var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone, + gutterDirty, callbacks; + // Current visible range (may be bigger than the view window). + var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0; + // bracketHighlighted is used to remember that a bracket has been + // marked. + var bracketHighlighted; + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + var maxLine = "", updateMaxLine = false, maxLineChanged = true; + var tabCache = {}; + + // Initialize the content. + operation(function(){setValue(options.value || ""); updateInput = false;})(); + var history = new History(); + + // Register our event handlers. + connect(scroller, "mousedown", operation(onMouseDown)); + connect(scroller, "dblclick", operation(onDoubleClick)); + connect(lineSpace, "selectstart", e_preventDefault); + // Gecko browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for Gecko. + if (!gecko) connect(scroller, "contextmenu", onContextMenu); + connect(scroller, "scroll", onScroll); + connect(scrollbar, "scroll", onScroll); + connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);}); + connect(scroller, "mousewheel", onMouseWheel); + connect(scroller, "DOMMouseScroll", onMouseWheel); + connect(window, "resize", function() {updateDisplay(true);}); + connect(input, "keyup", operation(onKeyUp)); + connect(input, "input", fastPoll); + connect(input, "keydown", operation(onKeyDown)); + connect(input, "keypress", operation(onKeyPress)); + connect(input, "focus", onFocus); + connect(input, "blur", onBlur); + + if (options.dragDrop) { + connect(scroller, "dragstart", onDragStart); + function drag_(e) { + if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return; + e_stop(e); + } + connect(scroller, "dragenter", drag_); + connect(scroller, "dragover", drag_); + connect(scroller, "drop", operation(onDrop)); + } + connect(scroller, "paste", function(){focusInput(); fastPoll();}); + connect(input, "paste", fastPoll); + connect(input, "cut", operation(function(){ + if (!options.readOnly) replaceSelection(""); + })); + + // Needed to handle Tab key in KHTML + if (khtml) connect(code, "mouseup", function() { + if (document.activeElement == input) input.blur(); + focusInput(); + }); + + // IE throws unspecified error in certain cases, when + // trying to access activeElement before onload + var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { } + if (hasFocus || options.autofocus) setTimeout(onFocus, 20); + else onBlur(); + + function isLine(l) {return l >= 0 && l < doc.size;} + // The instance object that we'll return. Mostly calls out to + // local functions in the CodeMirror function. Some do some extra + // range checking and/or clipping. operation is used to wrap the + // call so that changes it makes are tracked, and the display is + // updated afterwards. + var instance = wrapper.CodeMirror = { + getValue: getValue, + setValue: operation(setValue), + getSelection: getSelection, + replaceSelection: operation(replaceSelection), + focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();}, + setOption: function(option, value) { + var oldVal = options[option]; + options[option] = value; + if (option == "mode" || option == "indentUnit") loadMode(); + else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();} + else if (option == "readOnly" && !value) {resetInput(true);} + else if (option == "theme") themeChanged(); + else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)(); + else if (option == "tabSize") updateDisplay(true); + else if (option == "keyMap") keyMapChanged(); + if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") { + gutterChanged(); + updateDisplay(true); + } + }, + getOption: function(option) {return options[option];}, + undo: operation(undo), + redo: operation(redo), + indentLine: operation(function(n, dir) { + if (typeof dir != "string") { + if (dir == null) dir = options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(n)) indentLine(n, dir); + }), + indentSelection: operation(indentSelected), + historySize: function() {return {undo: history.done.length, redo: history.undone.length};}, + clearHistory: function() {history = new History();}, + setHistory: function(histData) { + history = new History(); + history.done = histData.done; + history.undone = histData.undone; + }, + getHistory: function() { + history.time = 0; + return {done: history.done.concat([]), undone: history.undone.concat([])}; + }, + matchBrackets: operation(function(){matchBrackets(true);}), + getTokenAt: operation(function(pos) { + pos = clipPos(pos); + return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch); + }), + getStateAfter: function(line) { + line = clipLine(line == null ? doc.size - 1: line); + return getStateBefore(line + 1); + }, + cursorCoords: function(start, mode) { + if (start == null) start = sel.inverted; + return this.charCoords(start ? sel.from : sel.to, mode); + }, + charCoords: function(pos, mode) { + pos = clipPos(pos); + if (mode == "local") return localCoords(pos, false); + if (mode == "div") return localCoords(pos, true); + return pageCoords(pos); + }, + coordsChar: function(coords) { + var off = eltOffset(lineSpace); + return coordsChar(coords.x - off.left, coords.y - off.top); + }, + markText: operation(markText), + setBookmark: setBookmark, + findMarksAt: findMarksAt, + setMarker: operation(addGutterMarker), + clearMarker: operation(removeGutterMarker), + setLineClass: operation(setLineClass), + hideLine: operation(function(h) {return setLineHidden(h, true);}), + showLine: operation(function(h) {return setLineHidden(h, false);}), + onDeleteLine: function(line, f) { + if (typeof line == "number") { + if (!isLine(line)) return null; + line = getLine(line); + } + (line.handlers || (line.handlers = [])).push(f); + return line; + }, + lineInfo: lineInfo, + addWidget: function(pos, node, scroll, vert, horiz) { + pos = localCoords(clipPos(pos)); + var top = pos.yBot, left = pos.x; + node.style.position = "absolute"; + code.appendChild(node); + if (vert == "over") top = pos.y; + else if (vert == "near") { + var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()), + hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft(); + if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight) + top = pos.y - node.offsetHeight; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = (top + paddingTop()) + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = code.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2; + node.style.left = (left + paddingLeft()) + "px"; + } + if (scroll) + scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + lineCount: function() {return doc.size;}, + clipPos: clipPos, + getCursor: function(start) { + if (start == null) start = sel.inverted; + return copyPos(start ? sel.from : sel.to); + }, + somethingSelected: function() {return !posEq(sel.from, sel.to);}, + setCursor: operation(function(line, ch, user) { + if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user); + else setCursor(line, ch, user); + }), + setSelection: operation(function(from, to, user) { + (user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from)); + }), + getLine: function(line) {if (isLine(line)) return getLine(line).text;}, + getLineHandle: function(line) {if (isLine(line)) return getLine(line);}, + setLine: operation(function(line, text) { + if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length}); + }), + removeLine: operation(function(line) { + if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0})); + }), + replaceRange: operation(replaceRange), + getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);}, + + triggerOnKeyDown: operation(onKeyDown), + execCommand: function(cmd) {return commands[cmd](instance);}, + // Stuff used by commands, probably not much use to outside code. + moveH: operation(moveH), + deleteH: operation(deleteH), + moveV: operation(moveV), + toggleOverwrite: function() { + if(overwrite){ + overwrite = false; + cursor.className = cursor.className.replace(" CodeMirror-overwrite", ""); + } else { + overwrite = true; + cursor.className += " CodeMirror-overwrite"; + } + }, + + posFromIndex: function(off) { + var lineNo = 0, ch; + doc.iter(0, doc.size, function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos({line: lineNo, ch: ch}); + }, + indexFromPos: function (coords) { + if (coords.line < 0 || coords.ch < 0) return 0; + var index = coords.ch; + doc.iter(0, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + scrollTo: function(x, y) { + if (x != null) scroller.scrollLeft = x; + if (y != null) scrollbar.scrollTop = y; + updateDisplay([]); + }, + getScrollInfo: function() { + return {x: scroller.scrollLeft, y: scrollbar.scrollTop, + height: scrollbar.scrollHeight, width: scroller.scrollWidth}; + }, + setSize: function(width, height) { + function interpret(val) { + val = String(val); + return /^\d+$/.test(val) ? val + "px" : val; + } + if (width != null) wrapper.style.width = interpret(width); + if (height != null) scroller.style.height = interpret(height); + }, + + operation: function(f){return operation(f)();}, + compoundChange: function(f){return compoundChange(f);}, + refresh: function(){ + updateDisplay(true, null, lastScrollTop); + if (scrollbar.scrollHeight > lastScrollTop) + scrollbar.scrollTop = lastScrollTop; + }, + getInputField: function(){return input;}, + getWrapperElement: function(){return wrapper;}, + getScrollerElement: function(){return scroller;}, + getGutterElement: function(){return gutter;} + }; + + function getLine(n) { return getLineAt(doc, n); } + function updateLineHeight(line, height) { + gutterDirty = true; + var diff = height - line.height; + for (var n = line; n; n = n.parent) n.height += diff; + } + + function setValue(code) { + var top = {line: 0, ch: 0}; + updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length}, + splitLines(code), top, top); + updateInput = true; + } + function getValue(lineSep) { + var text = []; + doc.iter(0, doc.size, function(line) { text.push(line.text); }); + return text.join(lineSep || "\n"); + } + + function onScroll(e) { + if (scroller.scrollTop) { + scrollbar.scrollTop += scroller.scrollTop; + scroller.scrollTop = 0; + } + if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) { + lastScrollTop = scrollbar.scrollTop; + lastScrollLeft = scroller.scrollLeft; + updateDisplay([]); + if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px"; + if (options.onScroll) options.onScroll(instance); + } + } + + function onMouseDown(e) { + setShift(e_prop(e, "shiftKey")); + // Check whether this is a click in a widget + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == code && n != mover) return; + + // See if this is a click in the gutter + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == gutterText) { + if (options.onGutterClick) + options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e); + return e_preventDefault(e); + } + + var start = posFromMouse(e); + + switch (e_button(e)) { + case 3: + if (gecko) onContextMenu(e); + return; + case 2: + if (start) setCursor(start.line, start.ch, true); + setTimeout(focusInput, 20); + e_preventDefault(e); + return; + } + // For button 1, if it was clicked inside the editor + // (posFromMouse returning non-null), we have to adjust the + // selection. + if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;} + + if (!focused) onFocus(); + + var now = +new Date, type = "single"; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { + type = "triple"; + e_preventDefault(e); + setTimeout(focusInput, 20); + selectLine(start.line); + } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + e_preventDefault(e); + var word = findWordAt(start); + setSelectionUser(word.from, word.to); + } else { lastClick = {time: now, pos: start}; } + + var last = start, going; + if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) && + !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") { + // Let the drag handler handle this. + if (webkit) scroller.draggable = true; + function dragEnd(e2) { + if (webkit) scroller.draggable = false; + draggingText = false; + up(); drop(); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + setCursor(start.line, start.ch, true); + focusInput(); + } + } + var up = connect(document, "mouseup", operation(dragEnd), true); + var drop = connect(scroller, "drop", operation(dragEnd), true); + draggingText = true; + // IE's approach to draggable + if (scroller.dragDrop) scroller.dragDrop(); + return; + } + e_preventDefault(e); + if (type == "single") setCursor(start.line, start.ch, true); + + var startstart = sel.from, startend = sel.to; + + function doSelect(cur) { + if (type == "single") { + setSelectionUser(start, cur); + } else if (type == "double") { + var word = findWordAt(cur); + if (posLess(cur, startstart)) setSelectionUser(word.from, startend); + else setSelectionUser(startstart, word.to); + } else if (type == "triple") { + if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0})); + else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0})); + } + } + + function extend(e) { + var cur = posFromMouse(e, true); + if (cur && !posEq(cur, last)) { + if (!focused) onFocus(); + last = cur; + doSelect(cur); + updateInput = false; + var visible = visibleLines(); + if (cur.line >= visible.to || cur.line < visible.from) + going = setTimeout(operation(function(){extend(e);}), 150); + } + } + + function done(e) { + clearTimeout(going); + var cur = posFromMouse(e); + if (cur) doSelect(cur); + e_preventDefault(e); + focusInput(); + updateInput = true; + move(); up(); + } + var move = connect(document, "mousemove", operation(function(e) { + clearTimeout(going); + e_preventDefault(e); + if (!ie && !e_button(e)) done(e); + else extend(e); + }), true); + var up = connect(document, "mouseup", operation(done), true); + } + function onDoubleClick(e) { + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == gutterText) return e_preventDefault(e); + e_preventDefault(e); + } + function onDrop(e) { + if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return; + e.preventDefault(); + var pos = posFromMouse(e, true), files = e.dataTransfer.files; + if (!pos || options.readOnly) return; + if (files && files.length && window.FileReader && window.File) { + function loadFile(file, i) { + var reader = new FileReader; + reader.onload = function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(pos); + operation(function() { + var end = replaceRange(text.join(""), pos, pos); + setSelectionUser(pos, end); + })(); + } + }; + reader.readAsText(file); + } + var n = files.length, text = Array(n), read = 0; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { + // Don't do a replace if the drop happened inside of the selected text. + if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return; + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + compoundChange(function() { + var curFrom = sel.from, curTo = sel.to; + setSelectionUser(pos, pos); + if (draggingText) replaceRange("", curFrom, curTo); + replaceSelection(text); + focusInput(); + }); + } + } + catch(e){} + } + } + function onDragStart(e) { + var txt = getSelection(); + e.dataTransfer.setData("Text", txt); + + // Use dummy image instead of default browsers image. + if (gecko || chrome || opera) { + var img = document.createElement('img'); + img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image + e.dataTransfer.setDragImage(img, 0, 0); + } + } + + function doHandleBinding(bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + var prevShift = shiftSelecting; + try { + if (options.readOnly) suppressEdits = true; + if (dropShift) shiftSelecting = null; + bound(instance); + } catch(e) { + if (e != Pass) throw e; + return false; + } finally { + shiftSelecting = prevShift; + suppressEdits = false; + } + return true; + } + function handleKeyBinding(e) { + // Handle auto keymap transitions + var startMap = getKeyMap(options.keyMap), next = startMap.auto; + clearTimeout(maybeTransition); + if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() { + if (getKeyMap(options.keyMap) == startMap) { + options.keyMap = (next.call ? next.call(null, instance) : next); + } + }, 50); + + var name = keyNames[e_prop(e, "keyCode")], handled = false; + if (name == null || e.altGraphKey) return false; + if (e_prop(e, "altKey")) name = "Alt-" + name; + if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name; + if (e_prop(e, "metaKey")) name = "Cmd-" + name; + + var stopped = false; + function stop() { stopped = true; } + + if (e_prop(e, "shiftKey")) { + handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap, + function(b) {return doHandleBinding(b, true);}, stop) + || lookupKey(name, options.extraKeys, options.keyMap, function(b) { + if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b); + }, stop); + } else { + handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop); + } + if (stopped) handled = false; + if (handled) { + e_preventDefault(e); + restartBlink(); + if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; } + } + return handled; + } + function handleCharBinding(e, ch) { + var handled = lookupKey("'" + ch + "'", options.extraKeys, + options.keyMap, function(b) { return doHandleBinding(b, true); }); + if (handled) { + e_preventDefault(e); + restartBlink(); + } + return handled; + } + + var lastStoppedKey = null, maybeTransition; + function onKeyDown(e) { + if (!focused) onFocus(); + if (ie && e.keyCode == 27) { e.returnValue = false; } + if (pollingFast) { if (readInput()) pollingFast = false; } + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + var code = e_prop(e, "keyCode"); + // IE does strange things with escape. + setShift(code == 16 || e_prop(e, "shiftKey")); + // First give onKeyEvent option a chance to handle this. + var handled = handleKeyBinding(e); + if (opera) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey")) + replaceSelection(""); + } + } + function onKeyPress(e) { + if (pollingFast) readInput(); + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode"); + if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) { + if (mode.electricChars.indexOf(ch) > -1) + setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75); + } + if (handleCharBinding(e, ch)) return; + fastPoll(); + } + function onKeyUp(e) { + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + if (e_prop(e, "keyCode") == 16) shiftSelecting = null; + } + + function onFocus() { + if (options.readOnly == "nocursor") return; + if (!focused) { + if (options.onFocus) options.onFocus(instance); + focused = true; + if (scroller.className.search(/\bCodeMirror-focused\b/) == -1) + scroller.className += " CodeMirror-focused"; + if (!leaveInputAlone) resetInput(true); + } + slowPoll(); + restartBlink(); + } + function onBlur() { + if (focused) { + if (options.onBlur) options.onBlur(instance); + focused = false; + if (bracketHighlighted) + operation(function(){ + if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; } + })(); + scroller.className = scroller.className.replace(" CodeMirror-focused", ""); + } + clearInterval(blinker); + setTimeout(function() {if (!focused) shiftSelecting = null;}, 150); + } + + function chopDelta(delta) { + // Make sure we always scroll a little bit for any nonzero delta. + if (delta > 0.0 && delta < 1.0) return 1; + else if (delta > -1.0 && delta < 0.0) return -1; + else return Math.round(delta); + } + + function onMouseWheel(e) { + var deltaX = 0, deltaY = 0; + if (e.type == "DOMMouseScroll") { // Firefox + var delta = -e.detail * 8.0; + if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta; + else if (e.axis == e.VERTICAL_AXIS) deltaY = delta; + } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit + deltaX = e.wheelDeltaX / 3.0; + deltaY = e.wheelDeltaY / 3.0; + } else if (e.wheelDelta !== undefined) { // IE or Opera + deltaY = e.wheelDelta / 3.0; + } + + var scrolled = false; + deltaX = chopDelta(deltaX); + deltaY = chopDelta(deltaY); + if ((deltaX > 0 && scroller.scrollLeft > 0) || + (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) { + scroller.scrollLeft -= deltaX; + scrolled = true; + } + if ((deltaY > 0 && scrollbar.scrollTop > 0) || + (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) { + scrollbar.scrollTop -= deltaY; + scrolled = true; + } + if (scrolled) e_stop(e); + } + + // Replace the range from from to to by the strings in newText. + // Afterwards, set the selection to selFrom, selTo. + function updateLines(from, to, newText, selFrom, selTo) { + if (suppressEdits) return; + if (history) { + var old = []; + doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); }); + history.addChange(from.line, newText.length, old); + while (history.done.length > options.undoDepth) history.done.shift(); + } + updateLinesNoUndo(from, to, newText, selFrom, selTo); + } + function unredoHelper(from, to) { + if (!from.length) return; + var set = from.pop(), out = []; + for (var i = set.length - 1; i >= 0; i -= 1) { + var change = set[i]; + var replaced = [], end = change.start + change.added; + doc.iter(change.start, end, function(line) { replaced.push(line.text); }); + out.push({start: change.start, added: change.old.length, old: replaced}); + var pos = {line: change.start + change.old.length - 1, + ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])}; + updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos); + } + updateInput = true; + to.push(out); + } + function undo() {unredoHelper(history.done, history.undone);} + function redo() {unredoHelper(history.undone, history.done);} + + function updateLinesNoUndo(from, to, newText, selFrom, selTo) { + if (suppressEdits) return; + var recomputeMaxLength = false, maxLineLength = maxLine.length; + if (!options.lineWrapping) + doc.iter(from.line, to.line + 1, function(line) { + if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;} + }); + if (from.line != to.line || newText.length > 1) gutterDirty = true; + + var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line); + // First adjust the line structure, taking some care to leave highlighting intact. + if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = [], prevLine = null; + if (from.line) { + prevLine = getLine(from.line - 1); + prevLine.fixMarkEnds(lastLine); + } else lastLine.fixMarkStarts(); + for (var i = 0, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], prevLine)); + if (nlines) doc.remove(from.line, nlines, callbacks); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (newText.length == 1) + firstLine.replace(from.ch, to.ch, newText[0]); + else { + lastLine = firstLine.split(to.ch, newText[newText.length-1]); + firstLine.replace(from.ch, null, newText[0]); + firstLine.fixMarkEnds(lastLine); + var added = []; + for (var i = 1, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], firstLine)); + added.push(lastLine); + doc.insert(from.line + 1, added); + } + } else if (newText.length == 1) { + firstLine.replace(from.ch, null, newText[0]); + lastLine.replace(null, to.ch, ""); + firstLine.append(lastLine); + doc.remove(from.line + 1, nlines, callbacks); + } else { + var added = []; + firstLine.replace(from.ch, null, newText[0]); + lastLine.replace(null, to.ch, newText[newText.length-1]); + firstLine.fixMarkEnds(lastLine); + for (var i = 1, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], firstLine)); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks); + doc.insert(from.line + 1, added); + } + if (options.lineWrapping) { + var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3); + doc.iter(from.line, from.line + newText.length, function(line) { + if (line.hidden) return; + var guess = Math.ceil(line.text.length / perLine) || 1; + if (guess != line.height) updateLineHeight(line, guess); + }); + } else { + doc.iter(from.line, from.line + newText.length, function(line) { + var l = line.text; + if (!line.hidden && l.length > maxLineLength) { + maxLine = l; maxLineLength = l.length; maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) updateMaxLine = true; + } + + // Add these lines to the work array, so that they will be + // highlighted. Adjust work lines if lines were added/removed. + var newWork = [], lendiff = newText.length - nlines - 1; + for (var i = 0, l = work.length; i < l; ++i) { + var task = work[i]; + if (task < from.line) newWork.push(task); + else if (task > to.line) newWork.push(task + lendiff); + } + var hlEnd = from.line + Math.min(newText.length, 500); + highlightLines(from.line, hlEnd); + newWork.push(hlEnd); + work = newWork; + startWorker(100); + // Remember that these lines changed, for updating the display + changes.push({from: from.line, to: to.line + 1, diff: lendiff}); + var changeObj = {from: from, to: to, text: newText}; + if (textChanged) { + for (var cur = textChanged; cur.next; cur = cur.next) {} + cur.next = changeObj; + } else textChanged = changeObj; + + // Update the selection + function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;} + setSelection(clipPos(selFrom), clipPos(selTo), + updateLine(sel.from.line), updateLine(sel.to.line)); + } + + function needsScrollbar() { + var realHeight = doc.height * textHeight() + 2 * paddingTop(); + return realHeight - 1 > scroller.offsetHeight ? realHeight : false; + } + + function updateVerticalScroll(scrollTop) { + var scrollHeight = needsScrollbar(); + scrollbar.style.display = scrollHeight ? "block" : "none"; + if (scrollHeight) { + scrollbarInner.style.height = scrollHeight + "px"; + scrollbar.style.height = scroller.offsetHeight + "px"; + if (scrollTop != null) scrollbar.scrollTop = scrollTop; + } + // Position the mover div to align with the current virtual scroll position + mover.style.top = (displayOffset * textHeight() - scrollbar.scrollTop) + "px"; + } + + // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring + // the width of a div with a scrollbar in it. If the width is <= 1, then + // the mouse isn't plugged in and scrollbars should overlap the content. + function overlapScrollbars() { + var tmpSb = document.createElement('div'), + tmpSbInner = document.createElement('div'); + tmpSb.className = "CodeMirror-scrollbar"; + tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;"; + tmpSbInner.className = "CodeMirror-scrollbar-inner"; + tmpSbInner.style.height = "200px"; + tmpSb.appendChild(tmpSbInner); + + document.body.appendChild(tmpSb); + var result = (tmpSb.offsetWidth <= 1); + document.body.removeChild(tmpSb); + return result; + } + + function computeMaxLength() { + var maxLineLength = 0; + maxLine = ""; maxLineChanged = true; + doc.iter(0, doc.size, function(line) { + var l = line.text; + if (!line.hidden && l.length > maxLineLength) { + maxLineLength = l.length; maxLine = l; + } + }); + updateMaxLine = false; + } + + function replaceRange(code, from, to) { + from = clipPos(from); + if (!to) to = from; else to = clipPos(to); + code = splitLines(code); + function adjustPos(pos) { + if (posLess(pos, from)) return pos; + if (!posLess(to, pos)) return end; + var line = pos.line + code.length - (to.line - from.line) - 1; + var ch = pos.ch; + if (pos.line == to.line) + ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0)); + return {line: line, ch: ch}; + } + var end; + replaceRange1(code, from, to, function(end1) { + end = end1; + return {from: adjustPos(sel.from), to: adjustPos(sel.to)}; + }); + return end; + } + function replaceSelection(code, collapse) { + replaceRange1(splitLines(code), sel.from, sel.to, function(end) { + if (collapse == "end") return {from: end, to: end}; + else if (collapse == "start") return {from: sel.from, to: sel.from}; + else return {from: sel.from, to: end}; + }); + } + function replaceRange1(code, from, to, computeSel) { + var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length; + var newSel = computeSel({line: from.line + code.length - 1, ch: endch}); + updateLines(from, to, code, newSel.from, newSel.to); + } + + function getRange(from, to, lineSep) { + var l1 = from.line, l2 = to.line; + if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch); + var code = [getLine(l1).text.slice(from.ch)]; + doc.iter(l1 + 1, l2, function(line) { code.push(line.text); }); + code.push(getLine(l2).text.slice(0, to.ch)); + return code.join(lineSep || "\n"); + } + function getSelection(lineSep) { + return getRange(sel.from, sel.to, lineSep); + } + + var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll + function slowPoll() { + if (pollingFast) return; + poll.set(options.pollInterval, function() { + startOperation(); + readInput(); + if (focused) slowPoll(); + endOperation(); + }); + } + function fastPoll() { + var missed = false; + pollingFast = true; + function p() { + startOperation(); + var changed = readInput(); + if (!changed && !missed) {missed = true; poll.set(60, p);} + else {pollingFast = false; slowPoll();} + endOperation(); + } + poll.set(20, p); + } + + // Previnput is a hack to work with IME. If we reset the textarea + // on every change, that breaks IME. So we look for changes + // compared to the previous content instead. (Modern browsers have + // events that indicate IME taking place, but these are not widely + // supported or compatible enough yet to rely on.) + var prevInput = ""; + function readInput() { + if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false; + var text = input.value; + if (text == prevInput) return false; + shiftSelecting = null; + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput[same] == text[same]) ++same; + if (same < prevInput.length) + sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)}; + else if (overwrite && posEq(sel.from, sel.to)) + sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))}; + replaceSelection(text.slice(same), "end"); + if (text.length > 1000) { input.value = prevInput = ""; } + else prevInput = text; + return true; + } + function resetInput(user) { + if (!posEq(sel.from, sel.to)) { + prevInput = ""; + input.value = getSelection(); + selectInput(input); + } else if (user) prevInput = input.value = ""; + } + + function focusInput() { + if (options.readOnly != "nocursor") input.focus(); + } + + function scrollEditorIntoView() { + var rect = cursor.getBoundingClientRect(); + // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden + if (ie && rect.top == rect.bottom) return; + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView(); + } + function scrollCursorIntoView() { + var coords = calculateCursorCoords(); + return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot); + } + function calculateCursorCoords() { + var cursor = localCoords(sel.inverted ? sel.from : sel.to); + var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x; + return {x: x, y: cursor.y, yBot: cursor.yBot}; + } + function scrollIntoView(x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false; + if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;} + if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;} + if (scrolled && options.onScroll) options.onScroll(instance); + } + function calculateScrollPos(x1, y1, x2, y2) { + var pl = paddingLeft(), pt = paddingTop(); + y1 += pt; y2 += pt; x1 += pl; x2 += pl; + var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {}; + var docBottom = scroller.scrollHeight; + var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;; + if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1); + else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen; + + var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft; + var gutterw = options.fixedGutter ? gutter.clientWidth : 0; + var atLeft = x1 < gutterw + pl + 10; + if (x1 < screenleft + gutterw || atLeft) { + if (atLeft) x1 = 0; + result.scrollLeft = Math.max(0, x1 - 10 - gutterw); + } else if (x2 > screenw + screenleft - 3) { + result.scrollLeft = x2 + 10 - screenw; + } + return result; + } + + function visibleLines(scrollTop) { + var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop(); + var fromHeight = Math.max(0, Math.floor(top / lh)); + var toHeight = Math.ceil((top + scroller.clientHeight) / lh); + return {from: lineAtHeight(doc, fromHeight), + to: lineAtHeight(doc, toHeight)}; + } + // Uses a set of changes plus the current scroll position to + // determine which DOM updates have to be made, and makes the + // updates. + function updateDisplay(changes, suppressCallback, scrollTop) { + if (!scroller.clientWidth) { + showingFrom = showingTo = displayOffset = 0; + return; + } + // Compute the new visible window + // If scrollTop is specified, use that to determine which lines + // to render instead of the current scrollbar position. + var visible = visibleLines(scrollTop); + // Bail out if the visible area is already rendered and nothing changed. + if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) { + updateVerticalScroll(scrollTop); + return; + } + var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100); + if (showingFrom < from && from - showingFrom < 20) from = showingFrom; + if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo); + + // Create a range of theoretically intact lines, and punch holes + // in that using the change info. + var intact = changes === true ? [] : + computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes); + // Clip off the parts that won't be visible + var intactLines = 0; + for (var i = 0; i < intact.length; ++i) { + var range = intact[i]; + if (range.from < from) {range.domStart += (from - range.from); range.from = from;} + if (range.to > to) range.to = to; + if (range.from >= range.to) intact.splice(i--, 1); + else intactLines += range.to - range.from; + } + if (intactLines == to - from && from == showingFrom && to == showingTo) { + updateVerticalScroll(scrollTop); + return; + } + intact.sort(function(a, b) {return a.domStart - b.domStart;}); + + var th = textHeight(), gutterDisplay = gutter.style.display; + lineDiv.style.display = "none"; + patchDisplay(from, to, intact); + lineDiv.style.display = gutter.style.display = ""; + + var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th; + // This is just a bogus formula that detects when the editor is + // resized or the font size changes. + if (different) lastSizeC = scroller.clientHeight + th; + showingFrom = from; showingTo = to; + displayOffset = heightAtLine(doc, from); + + // Since this is all rather error prone, it is honoured with the + // only assertion in the whole file. + if (lineDiv.childNodes.length != showingTo - showingFrom) + throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) + + " nodes=" + lineDiv.childNodes.length); + + function checkHeights() { + var curNode = lineDiv.firstChild, heightChanged = false; + doc.iter(showingFrom, showingTo, function(line) { + if (!line.hidden) { + var height = Math.round(curNode.offsetHeight / th) || 1; + if (line.height != height) { + updateLineHeight(line, height); + gutterDirty = heightChanged = true; + } + } + curNode = curNode.nextSibling; + }); + return heightChanged; + } + + if (options.lineWrapping) { + checkHeights(); + var scrollHeight = needsScrollbar(); + var shouldHaveScrollbar = scrollHeight ? "block" : "none"; + if (scrollbar.style.display != shouldHaveScrollbar) { + scrollbar.style.display = shouldHaveScrollbar; + if (scrollHeight) scrollbarInner.style.height = scrollHeight + "px"; + checkHeights(); + } + } + + gutter.style.display = gutterDisplay; + if (different || gutterDirty) { + // If the gutter grew in size, re-check heights. If those changed, re-draw gutter. + updateGutter() && options.lineWrapping && checkHeights() && updateGutter(); + } + updateVerticalScroll(scrollTop); + updateSelection(); + if (!suppressCallback && options.onUpdate) options.onUpdate(instance); + return true; + } + + function computeIntact(intact, changes) { + for (var i = 0, l = changes.length || 0; i < l; ++i) { + var change = changes[i], intact2 = [], diff = change.diff || 0; + for (var j = 0, l2 = intact.length; j < l2; ++j) { + var range = intact[j]; + if (change.to <= range.from && change.diff) + intact2.push({from: range.from + diff, to: range.to + diff, + domStart: range.domStart}); + else if (change.to <= range.from || change.from >= range.to) + intact2.push(range); + else { + if (change.from > range.from) + intact2.push({from: range.from, to: change.from, domStart: range.domStart}); + if (change.to < range.to) + intact2.push({from: change.to + diff, to: range.to + diff, + domStart: range.domStart + (change.to - range.from)}); + } + } + intact = intact2; + } + return intact; + } + + function patchDisplay(from, to, intact) { + // The first pass removes the DOM nodes that aren't intact. + if (!intact.length) lineDiv.innerHTML = ""; + else { + function killNode(node) { + var tmp = node.nextSibling; + node.parentNode.removeChild(node); + return tmp; + } + var domPos = 0, curNode = lineDiv.firstChild, n; + for (var i = 0; i < intact.length; ++i) { + var cur = intact[i]; + while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;} + for (var j = 0, e = cur.to - cur.from; j < e; ++j) {curNode = curNode.nextSibling; domPos++;} + } + while (curNode) curNode = killNode(curNode); + } + // This pass fills in the lines that actually changed. + var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from; + var scratch = document.createElement("div"); + doc.iter(from, to, function(line) { + if (nextIntact && nextIntact.to == j) nextIntact = intact.shift(); + if (!nextIntact || nextIntact.from > j) { + if (line.hidden) var html = scratch.innerHTML = "
";
+          else {
+            var html = ''
+              + line.getHTML(makeTab) + '';
+            // Kludge to make sure the styled element lies behind the selection (by z-index)
+            if (line.bgClassName)
+              html = '
 
' + html + "
"; + } + scratch.innerHTML = html; + lineDiv.insertBefore(scratch.firstChild, curNode); + } else { + curNode = curNode.nextSibling; + } + ++j; + }); + } + + function updateGutter() { + if (!options.gutter && !options.lineNumbers) return; + var hText = mover.offsetHeight, hEditor = scroller.clientHeight; + gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px"; + var html = [], i = showingFrom, normalNode; + doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) { + if (line.hidden) { + html.push("
");
+        } else {
+          var marker = line.gutterMarker;
+          var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
+          if (marker && marker.text)
+            text = marker.text.replace("%N%", text != null ? text : "");
+          else if (text == null)
+            text = "\u00a0";
+          html.push((marker && marker.style ? '
' : "
"), text);
+          for (var j = 1; j < line.height; ++j) html.push("
 "); + html.push("
"); + if (!marker) normalNode = i; + } + ++i; + }); + gutter.style.display = "none"; + gutterText.innerHTML = html.join(""); + // Make sure scrolling doesn't cause number gutter size to pop + if (normalNode != null && options.lineNumbers) { + var node = gutterText.childNodes[normalNode - showingFrom]; + var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = ""; + while (val.length + pad.length < minwidth) pad += "\u00a0"; + if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild); + } + gutter.style.display = ""; + var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2; + lineSpace.style.marginLeft = gutter.offsetWidth + "px"; + gutterDirty = false; + return resized; + } + function updateSelection() { + var collapsed = posEq(sel.from, sel.to); + var fromPos = localCoords(sel.from, true); + var toPos = collapsed ? fromPos : localCoords(sel.to, true); + var headPos = sel.inverted ? fromPos : toPos, th = textHeight(); + var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv); + inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px"; + inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px"; + if (collapsed) { + cursor.style.top = headPos.y + "px"; + cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px"; + cursor.style.display = ""; + selectionDiv.style.display = "none"; + } else { + var sameLine = fromPos.y == toPos.y, html = ""; + var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth; + var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight; + function add(left, top, right, height) { + var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px" + : "right: " + right + "px"; + html += '
'; + } + if (sel.from.ch && fromPos.y >= 0) { + var right = sameLine ? clientWidth - toPos.x : 0; + add(fromPos.x, fromPos.y, right, th); + } + var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0)); + var middleHeight = Math.min(toPos.y, clientHeight) - middleStart; + if (middleHeight > 0.2 * th) + add(0, middleStart, 0, middleHeight); + if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th) + add(0, toPos.y, clientWidth - toPos.x, th); + selectionDiv.innerHTML = html; + cursor.style.display = "none"; + selectionDiv.style.display = ""; + } + } + + function setShift(val) { + if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from); + else shiftSelecting = null; + } + function setSelectionUser(from, to) { + var sh = shiftSelecting && clipPos(shiftSelecting); + if (sh) { + if (posLess(sh, from)) from = sh; + else if (posLess(to, sh)) to = sh; + } + setSelection(from, to); + userSelChange = true; + } + // Update the selection. Last two args are only used by + // updateLines, since they have to be expressed in the line + // numbers before the update. + function setSelection(from, to, oldFrom, oldTo) { + goalColumn = null; + if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;} + if (posEq(sel.from, from) && posEq(sel.to, to)) return; + if (posLess(to, from)) {var tmp = to; to = from; from = tmp;} + + // Skip over hidden lines. + if (from.line != oldFrom) { + var from1 = skipHidden(from, oldFrom, sel.from.ch); + // If there is no non-hidden line left, force visibility on current line + if (!from1) setLineHidden(from.line, false); + else from = from1; + } + if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch); + + if (posEq(from, to)) sel.inverted = false; + else if (posEq(from, sel.to)) sel.inverted = false; + else if (posEq(to, sel.from)) sel.inverted = true; + + if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) { + var head = sel.inverted ? from : to; + if (head.line != sel.from.line && sel.from.line < doc.size) { + var oldLine = getLine(sel.from.line); + if (/^\s+$/.test(oldLine.text)) + setTimeout(operation(function() { + if (oldLine.parent && /^\s+$/.test(oldLine.text)) { + var no = lineNo(oldLine); + replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length}); + } + }, 10)); + } + } + + sel.from = from; sel.to = to; + selectionChanged = true; + } + function skipHidden(pos, oldLine, oldCh) { + function getNonHidden(dir) { + var lNo = pos.line + dir, end = dir == 1 ? doc.size : -1; + while (lNo != end) { + var line = getLine(lNo); + if (!line.hidden) { + var ch = pos.ch; + if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length; + return {line: lNo, ch: ch}; + } + lNo += dir; + } + } + var line = getLine(pos.line); + var toEnd = pos.ch == line.text.length && pos.ch != oldCh; + if (!line.hidden) return pos; + if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1); + else return getNonHidden(-1) || getNonHidden(1); + } + function setCursor(line, ch, user) { + var pos = clipPos({line: line, ch: ch || 0}); + (user ? setSelectionUser : setSelection)(pos, pos); + } + + function clipLine(n) {return Math.max(0, Math.min(n, doc.size-1));} + function clipPos(pos) { + if (pos.line < 0) return {line: 0, ch: 0}; + if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc.size-1).text.length}; + var ch = pos.ch, linelen = getLine(pos.line).text.length; + if (ch == null || ch > linelen) return {line: pos.line, ch: linelen}; + else if (ch < 0) return {line: pos.line, ch: 0}; + else return pos; + } + + function findPosH(dir, unit) { + var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch; + var lineObj = getLine(line); + function findNextLine() { + for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) { + var lo = getLine(l); + if (!lo.hidden) { line = l; lineObj = lo; return true; } + } + } + function moveOnce(boundToLine) { + if (ch == (dir < 0 ? 0 : lineObj.text.length)) { + if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0; + else return false; + } else ch += dir; + return true; + } + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word") { + var sawWord = false; + for (;;) { + if (dir < 0) if (!moveOnce()) break; + if (isWordChar(lineObj.text.charAt(ch))) sawWord = true; + else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;} + if (dir > 0) if (!moveOnce()) break; + } + } + return {line: line, ch: ch}; + } + function moveH(dir, unit) { + var pos = dir < 0 ? sel.from : sel.to; + if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit); + setCursor(pos.line, pos.ch, true); + } + function deleteH(dir, unit) { + if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to); + else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to); + else replaceRange("", sel.from, findPosH(dir, unit)); + userSelChange = true; + } + var goalColumn = null; + function moveV(dir, unit) { + var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true); + if (goalColumn != null) pos.x = goalColumn; + if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight); + else if (unit == "line") dist = textHeight(); + var target = coordsChar(pos.x, pos.y + dist * dir + 2); + if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y; + setCursor(target.line, target.ch, true); + goalColumn = pos.x; + } + + function findWordAt(pos) { + var line = getLine(pos.line).text; + var start = pos.ch, end = pos.ch; + var check = isWordChar(line.charAt(start < line.length ? start : start - 1)) ? + isWordChar : function(ch) {return !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}}; + } + function selectLine(line) { + setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0})); + } + function indentSelected(mode) { + if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode); + var e = sel.to.line - (sel.to.ch ? 0 : 1); + for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode); + } + + function indentLine(n, how) { + if (!how) how = "add"; + if (how == "smart") { + if (!mode.indent) how = "prev"; + else var state = getStateBefore(n); + } + + var line = getLine(n), curSpace = line.indentation(options.tabSize), + curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (how == "smart") { + indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass) how = "prev"; + } + if (how == "prev") { + if (n) indentation = getLine(n-1).indentation(options.tabSize); + else indentation = 0; + } + else if (how == "add") indentation = curSpace + options.indentUnit; + else if (how == "subtract") indentation = curSpace - options.indentUnit; + indentation = Math.max(0, indentation); + var diff = indentation - curSpace; + + var indentString = "", pos = 0; + if (options.indentWithTabs) + for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";} + while (pos < indentation) {++pos; indentString += " ";} + + replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}); + } + + function loadMode() { + mode = CodeMirror.getMode(options, options.mode); + doc.iter(0, doc.size, function(line) { line.stateAfter = null; }); + work = [0]; + startWorker(); + } + function gutterChanged() { + var visible = options.gutter || options.lineNumbers; + gutter.style.display = visible ? "" : "none"; + if (visible) gutterDirty = true; + else lineDiv.parentNode.style.marginLeft = 0; + } + function wrappingChanged(from, to) { + if (options.lineWrapping) { + wrapper.className += " CodeMirror-wrap"; + var perLine = scroller.clientWidth / charWidth() - 3; + doc.iter(0, doc.size, function(line) { + if (line.hidden) return; + var guess = Math.ceil(line.text.length / perLine) || 1; + if (guess != 1) updateLineHeight(line, guess); + }); + lineSpace.style.width = code.style.width = ""; + widthForcer.style.left = ""; + } else { + wrapper.className = wrapper.className.replace(" CodeMirror-wrap", ""); + maxLine = ""; maxLineChanged = true; + doc.iter(0, doc.size, function(line) { + if (line.height != 1 && !line.hidden) updateLineHeight(line, 1); + if (line.text.length > maxLine.length) maxLine = line.text; + }); + } + changes.push({from: 0, to: doc.size}); + } + function makeTab(col) { + var w = options.tabSize - col % options.tabSize, cached = tabCache[w]; + if (cached) return cached; + for (var str = '', i = 0; i < w; ++i) str += " "; + return (tabCache[w] = {html: str + "", width: w}); + } + function themeChanged() { + scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") + + options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + } + function keyMapChanged() { + var style = keyMap[options.keyMap].style; + wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + + (style ? " cm-keymap-" + style : ""); + } + + function TextMarker() { this.set = []; } + TextMarker.prototype.clear = operation(function() { + var min = Infinity, max = -Infinity; + for (var i = 0, e = this.set.length; i < e; ++i) { + var line = this.set[i], mk = line.marked; + if (!mk || !line.parent) continue; + var lineN = lineNo(line); + min = Math.min(min, lineN); max = Math.max(max, lineN); + for (var j = 0; j < mk.length; ++j) + if (mk[j].marker == this) mk.splice(j--, 1); + } + if (min != Infinity) + changes.push({from: min, to: max + 1}); + }); + TextMarker.prototype.find = function() { + var from, to; + for (var i = 0, e = this.set.length; i < e; ++i) { + var line = this.set[i], mk = line.marked; + for (var j = 0; j < mk.length; ++j) { + var mark = mk[j]; + if (mark.marker == this) { + if (mark.from != null || mark.to != null) { + var found = lineNo(line); + if (found != null) { + if (mark.from != null) from = {line: found, ch: mark.from}; + if (mark.to != null) to = {line: found, ch: mark.to}; + } + } + } + } + } + return {from: from, to: to}; + }; + + function markText(from, to, className) { + from = clipPos(from); to = clipPos(to); + var tm = new TextMarker(); + if (!posLess(from, to)) return tm; + function add(line, from, to, className) { + getLine(line).addMark(new MarkedText(from, to, className, tm)); + } + if (from.line == to.line) add(from.line, from.ch, to.ch, className); + else { + add(from.line, from.ch, null, className); + for (var i = from.line + 1, e = to.line; i < e; ++i) + add(i, null, null, className); + add(to.line, null, to.ch, className); + } + changes.push({from: from.line, to: to.line + 1}); + return tm; + } + + function setBookmark(pos) { + pos = clipPos(pos); + var bm = new Bookmark(pos.ch); + getLine(pos.line).addMark(bm); + return bm; + } + + function findMarksAt(pos) { + pos = clipPos(pos); + var markers = [], marked = getLine(pos.line).marked; + if (!marked) return markers; + for (var i = 0, e = marked.length; i < e; ++i) { + var m = marked[i]; + if ((m.from == null || m.from <= pos.ch) && + (m.to == null || m.to >= pos.ch)) + markers.push(m.marker || m); + } + return markers; + } + + function addGutterMarker(line, text, className) { + if (typeof line == "number") line = getLine(clipLine(line)); + line.gutterMarker = {text: text, style: className}; + gutterDirty = true; + return line; + } + function removeGutterMarker(line) { + if (typeof line == "number") line = getLine(clipLine(line)); + line.gutterMarker = null; + gutterDirty = true; + } + + function changeLine(handle, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(clipLine(handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no)) changes.push({from: no, to: no + 1}); + else return null; + return line; + } + function setLineClass(handle, className, bgClassName) { + return changeLine(handle, function(line) { + if (line.className != className || line.bgClassName != bgClassName) { + line.className = className; + line.bgClassName = bgClassName; + return true; + } + }); + } + function setLineHidden(handle, hidden) { + return changeLine(handle, function(line, no) { + if (line.hidden != hidden) { + line.hidden = hidden; + if (!options.lineWrapping) { + var l = line.text; + if (hidden && l.length == maxLine.length) { + updateMaxLine = true; + } else if (!hidden && l.length > maxLine.length) { + maxLine = l; updateMaxLine = false; + } + } + updateLineHeight(line, hidden ? 0 : 1); + var fline = sel.from.line, tline = sel.to.line; + if (hidden && (fline == no || tline == no)) { + var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from; + var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to; + // Can't hide the last visible line, we'd have no place to put the cursor + if (!to) return; + setSelection(from, to); + } + return (gutterDirty = true); + } + }); + } + + function lineInfo(line) { + if (typeof line == "number") { + if (!isLine(line)) return null; + var n = line; + line = getLine(line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + var marker = line.gutterMarker; + return {line: n, handle: line, text: line.text, markerText: marker && marker.text, + markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName}; + } + + function stringWidth(str) { + measure.innerHTML = "
x
"; + measure.firstChild.firstChild.firstChild.nodeValue = str; + return measure.firstChild.firstChild.offsetWidth || 10; + } + // These are used to go from pixel positions to character + // positions, taking varying character widths into account. + function charFromX(line, x) { + if (x <= 0) return 0; + var lineObj = getLine(line), text = lineObj.text; + function getX(len) { + return measureLine(lineObj, len).left; + } + var from = 0, fromX = 0, to = text.length, toX; + // Guess a suitable upper bound for our search. + var estimated = Math.min(to, Math.ceil(x / charWidth())); + for (;;) { + var estX = getX(estimated); + if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2)); + else {toX = estX; to = estimated; break;} + } + if (x > toX) return to; + // Try to guess a suitable lower bound as well. + estimated = Math.floor(to * 0.8); estX = getX(estimated); + if (estX < x) {from = estimated; fromX = estX;} + // Do a binary search between these bounds. + for (;;) { + if (to - from <= 1) return (toX - x > x - fromX) ? from : to; + var middle = Math.ceil((from + to) / 2), middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX;} + else {from = middle; fromX = middleX;} + } + } + + var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16); + function measureLine(line, ch) { + if (ch == 0) return {top: 0, left: 0}; + var wbr = options.lineWrapping && ch < line.text.length && + spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1)); + measure.innerHTML = "
" + line.getHTML(makeTab, ch, tempId, wbr) + "
"; + var elt = document.getElementById(tempId); + var top = elt.offsetTop, left = elt.offsetLeft; + // Older IEs report zero offsets for spans directly after a wrap + if (ie && top == 0 && left == 0) { + var backup = document.createElement("span"); + backup.innerHTML = "x"; + elt.parentNode.insertBefore(backup, elt.nextSibling); + top = backup.offsetTop; + } + return {top: top, left: left}; + } + function localCoords(pos, inLineWrap) { + var x, lh = textHeight(), y = lh * (heightAtLine(doc, pos.line) - (inLineWrap ? displayOffset : 0)); + if (pos.ch == 0) x = 0; + else { + var sp = measureLine(getLine(pos.line), pos.ch); + x = sp.left; + if (options.lineWrapping) y += Math.max(0, sp.top); + } + return {x: x, y: y, yBot: y + lh}; + } + // Coords must be lineSpace-local + function coordsChar(x, y) { + if (y < 0) y = 0; + var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th); + var lineNo = lineAtHeight(doc, heightPos); + if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length}; + var lineObj = getLine(lineNo), text = lineObj.text; + var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0; + if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0}; + function getX(len) { + var sp = measureLine(lineObj, len); + if (tw) { + var off = Math.round(sp.top / th); + return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth); + } + return sp.left; + } + var from = 0, fromX = 0, to = text.length, toX; + // Guess a suitable upper bound for our search. + var estimated = Math.min(to, Math.ceil((x + innerOff * scroller.clientWidth * .9) / cw)); + for (;;) { + var estX = getX(estimated); + if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2)); + else {toX = estX; to = estimated; break;} + } + if (x > toX) return {line: lineNo, ch: to}; + // Try to guess a suitable lower bound as well. + estimated = Math.floor(to * 0.8); estX = getX(estimated); + if (estX < x) {from = estimated; fromX = estX;} + // Do a binary search between these bounds. + for (;;) { + if (to - from <= 1) return {line: lineNo, ch: (toX - x > x - fromX) ? from : to}; + var middle = Math.ceil((from + to) / 2), middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX;} + else {from = middle; fromX = middleX;} + } + } + function pageCoords(pos) { + var local = localCoords(pos, true), off = eltOffset(lineSpace); + return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot}; + } + + var cachedHeight, cachedHeightFor, measureText; + function textHeight() { + if (measureText == null) { + measureText = "
";
+        for (var i = 0; i < 49; ++i) measureText += "x
"; + measureText += "x
"; + } + var offsetHeight = lineDiv.clientHeight; + if (offsetHeight == cachedHeightFor) return cachedHeight; + cachedHeightFor = offsetHeight; + measure.innerHTML = measureText; + cachedHeight = measure.firstChild.offsetHeight / 50 || 1; + measure.innerHTML = ""; + return cachedHeight; + } + var cachedWidth, cachedWidthFor = 0; + function charWidth() { + if (scroller.clientWidth == cachedWidthFor) return cachedWidth; + cachedWidthFor = scroller.clientWidth; + return (cachedWidth = stringWidth("x")); + } + function paddingTop() {return lineSpace.offsetTop;} + function paddingLeft() {return lineSpace.offsetLeft;} + + function posFromMouse(e, liberal) { + var offW = eltOffset(scroller, true), x, y; + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX; y = e.clientY; } catch (e) { return null; } + // This is a mess of a heuristic to try and determine whether a + // scroll-bar was clicked or not, and to return null if one was + // (and !liberal). + if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight)) + return null; + var offL = eltOffset(lineSpace, true); + return coordsChar(x - offL.left, y - offL.top); + } + function onContextMenu(e) { + var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop; + if (!pos || opera) return; // Opera is difficult. + if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to)) + operation(setCursor)(pos.line, pos.ch); + + var oldCSS = input.style.cssText; + inputDiv.style.position = "absolute"; + input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " + + "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + leaveInputAlone = true; + var val = input.value = getSelection(); + focusInput(); + selectInput(input); + function rehide() { + var newVal = splitLines(input.value).join("\n"); + if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end"); + inputDiv.style.position = "relative"; + input.style.cssText = oldCSS; + if (ie_lt9) scrollbar.scrollTop = scrollPos; + leaveInputAlone = false; + resetInput(true); + slowPoll(); + } + + if (gecko) { + e_stop(e); + var mouseup = connect(window, "mouseup", function() { + mouseup(); + setTimeout(rehide, 20); + }, true); + } else { + setTimeout(rehide, 50); + } + } + + // Cursor-blinking + function restartBlink() { + clearInterval(blinker); + var on = true; + cursor.style.visibility = ""; + blinker = setInterval(function() { + cursor.style.visibility = (on = !on) ? "" : "hidden"; + }, 650); + } + + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; + function matchBrackets(autoclear) { + var head = sel.inverted ? sel.from : sel.to, line = getLine(head.line), pos = head.ch - 1; + var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; + if (!match) return; + var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles; + for (var off = pos + 1, i = 0, e = st.length; i < e; i+=2) + if ((off -= st[i].length) <= 0) {var style = st[i+1]; break;} + + var stack = [line.text.charAt(pos)], re = /[(){}[\]]/; + function scan(line, from, to) { + if (!line.text) return; + var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur; + for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) { + var text = st[i]; + if (st[i+1] != style) {pos += d * text.length; continue;} + for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) { + if (pos >= from && pos < to && re.test(cur = text.charAt(j))) { + var match = matching[cur]; + if (match.charAt(1) == ">" == forward) stack.push(cur); + else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false}; + else if (!stack.length) return {pos: pos, match: true}; + } + } + } + } + for (var i = head.line, e = forward ? Math.min(i + 100, doc.size) : Math.max(-1, i - 100); i != e; i+=d) { + var line = getLine(i), first = i == head.line; + var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length); + if (found) break; + } + if (!found) found = {pos: null, match: false}; + var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; + var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style), + two = found.pos != null && markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style); + var clear = operation(function(){one.clear(); two && two.clear();}); + if (autoclear) setTimeout(clear, 800); + else bracketHighlighted = clear; + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(n) { + var minindent, minline; + for (var search = n, lim = n - 40; search > lim; --search) { + if (search == 0) return 0; + var line = getLine(search-1); + if (line.stateAfter) return search; + var indented = line.indentation(options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + function getStateBefore(n) { + var start = findStartLine(n), state = start && getLine(start-1).stateAfter; + if (!state) state = startState(mode); + else state = copyState(mode, state); + doc.iter(start, n, function(line) { + line.highlight(mode, state, options.tabSize); + line.stateAfter = copyState(mode, state); + }); + if (start < n) changes.push({from: start, to: n}); + if (n < doc.size && !getLine(n).stateAfter) work.push(n); + return state; + } + function highlightLines(start, end) { + var state = getStateBefore(start); + doc.iter(start, end, function(line) { + line.highlight(mode, state, options.tabSize); + line.stateAfter = copyState(mode, state); + }); + } + function highlightWorker() { + var end = +new Date + options.workTime; + var foundWork = work.length; + while (work.length) { + if (!getLine(showingFrom).stateAfter) var task = showingFrom; + else var task = work.pop(); + if (task >= doc.size) continue; + var start = findStartLine(task), state = start && getLine(start-1).stateAfter; + if (state) state = copyState(mode, state); + else state = startState(mode); + + var unchanged = 0, compare = mode.compareStates, realChange = false, + i = start, bail = false; + doc.iter(i, doc.size, function(line) { + var hadState = line.stateAfter; + if (+new Date > end) { + work.push(i); + startWorker(options.workDelay); + if (realChange) changes.push({from: task, to: i + 1}); + return (bail = true); + } + var changed = line.highlight(mode, state, options.tabSize); + if (changed) realChange = true; + line.stateAfter = copyState(mode, state); + var done = null; + if (compare) { + var same = hadState && compare(hadState, state); + if (same != Pass) done = !!same; + } + if (done == null) { + if (changed !== false || !hadState) unchanged = 0; + else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, ""))) + done = true; + } + if (done) return true; + ++i; + }); + if (bail) return; + if (realChange) changes.push({from: task, to: i + 1}); + } + if (foundWork && options.onHighlightComplete) + options.onHighlightComplete(instance); + } + function startWorker(time) { + if (!work.length) return; + highlight.set(time, operation(highlightWorker)); + } + + // Operations are used to wrap changes in such a way that each + // change won't have to update the cursor and display (which would + // be awkward, slow, and error-prone), but instead updates are + // batched and then all combined and executed at once. + function startOperation() { + updateInput = userSelChange = textChanged = null; + changes = []; selectionChanged = false; callbacks = []; + } + function endOperation() { + if (updateMaxLine) computeMaxLength(); + if (maxLineChanged && !options.lineWrapping) { + var cursorWidth = widthForcer.offsetWidth, left = stringWidth(maxLine); + widthForcer.style.left = left + "px"; + lineSpace.style.minWidth = (left + cursorWidth) + "px"; + maxLineChanged = false; + } + var newScrollPos, updated; + if (selectionChanged) { + var coords = calculateCursorCoords(); + newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot); + } + if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null)); + else { + if (selectionChanged) updateSelection(); + if (gutterDirty) updateGutter(); + } + if (newScrollPos) scrollCursorIntoView(); + if (selectionChanged) {scrollEditorIntoView(); restartBlink();} + + if (focused && !leaveInputAlone && + (updateInput === true || (updateInput !== false && selectionChanged))) + resetInput(userSelChange); + + if (selectionChanged && options.matchBrackets) + setTimeout(operation(function() { + if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;} + if (posEq(sel.from, sel.to)) matchBrackets(false); + }), 20); + var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks + if (textChanged && options.onChange && instance) + options.onChange(instance, textChanged); + if (sc && options.onCursorActivity) + options.onCursorActivity(instance); + for (var i = 0; i < cbs.length; ++i) cbs[i](instance); + if (updated && options.onUpdate) options.onUpdate(instance); + } + var nestedOperation = 0; + function operation(f) { + return function() { + if (!nestedOperation++) startOperation(); + try {var result = f.apply(this, arguments);} + finally {if (!--nestedOperation) endOperation();} + return result; + }; + } + + function compoundChange(f) { + history.startCompound(); + try { return f(); } finally { history.endCompound(); } + } + + for (var ext in extensions) + if (extensions.propertyIsEnumerable(ext) && + !instance.propertyIsEnumerable(ext)) + instance[ext] = extensions[ext]; + return instance; + } // (end of function CodeMirror) + + // The default configuration options. + CodeMirror.defaults = { + value: "", + mode: null, + theme: "default", + indentUnit: 2, + indentWithTabs: false, + smartIndent: true, + tabSize: 4, + keyMap: "default", + extraKeys: null, + electricChars: true, + autoClearEmptyLines: false, + onKeyEvent: null, + onDragEvent: null, + lineWrapping: false, + lineNumbers: false, + gutter: false, + fixedGutter: false, + firstLineNumber: 1, + readOnly: false, + dragDrop: true, + onChange: null, + onCursorActivity: null, + onGutterClick: null, + onHighlightComplete: null, + onUpdate: null, + onFocus: null, onBlur: null, onScroll: null, + matchBrackets: false, + workTime: 100, + workDelay: 200, + pollInterval: 100, + undoDepth: 40, + tabindex: null, + autofocus: null, + lineNumberFormatter: function(integer) { return integer; } + }; + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var win = /Win/.test(navigator.platform); + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) { + mode.dependencies = []; + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); + } + modes[name] = mode; + }; + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) + spec = mimeModes[spec]; + else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) + return CodeMirror.resolveMode("application/xml"); + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + return mfactory(options, spec); + }; + CodeMirror.listModes = function() { + var list = []; + for (var m in modes) + if (modes.propertyIsEnumerable(m)) list.push(m); + return list; + }; + CodeMirror.listMIMEs = function() { + var list = []; + for (var m in mimeModes) + if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]}); + return list; + }; + + var extensions = CodeMirror.extensions = {}; + CodeMirror.defineExtension = function(name, func) { + extensions[name] = func; + }; + + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});}, + killLine: function(cm) { + var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); + if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0}); + else cm.replaceRange("", from, sel ? to : {line: from.line}); + }, + deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});}, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + goDocStart: function(cm) {cm.setCursor(0, 0, true);}, + goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);}, + goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);}, + goLineStartSmart: function(cm) { + var cur = cm.getCursor(); + var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/)); + cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true); + }, + goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);}, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharLeft: function(cm) {cm.deleteH(-1, "char");}, + delCharRight: function(cm) {cm.deleteH(1, "char");}, + delWordLeft: function(cm) {cm.deleteH(-1, "word");}, + delWordRight: function(cm) {cm.deleteH(1, "word");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t", "end");}, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.replaceSelection("\t", "end"); + }, + transposeChars: function(cm) { + var cur = cm.getCursor(), line = cm.getLine(cur.line); + if (cur.ch > 0 && cur.ch < line.length - 1) + cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1), + {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1}); + }, + newlineAndIndent: function(cm) { + cm.replaceSelection("\n", "end"); + cm.indentLine(cm.getCursor().line); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + var keyMap = CodeMirror.keyMap = {}; + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite" + }; + // Note that the save and find-related commands aren't defined by + // default. Unknown commands are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", + "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + fallthrough: "basic" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft", + "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft", + "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft", + "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + + function getKeyMap(val) { + if (typeof val == "string") return keyMap[val]; + else return val; + } + function lookupKey(name, extraMap, map, handle, stop) { + function lookup(map) { + map = getKeyMap(map); + var found = map[name]; + if (found != null && handle(found)) return true; + if (map.nofallthrough) { + if (stop) stop(); + return true; + } + var fallthrough = map.fallthrough; + if (fallthrough == null) return false; + if (Object.prototype.toString.call(fallthrough) != "[object Array]") + return lookup(fallthrough); + for (var i = 0, e = fallthrough.length; i < e; ++i) { + if (lookup(fallthrough[i])) return true; + } + return false; + } + if (extraMap && lookup(extraMap)) return true; + return lookup(map); + } + function isModifierKey(event) { + var name = keyNames[e_prop(event, "keyCode")]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + } + + CodeMirror.fromTextArea = function(textarea, options) { + if (!options) options = {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabindex) + options.tabindex = textarea.tabindex; + if (options.autofocus == null && textarea.getAttribute("autofocus") != null) + options.autofocus = true; + + function save() {textarea.value = instance.getValue();} + if (textarea.form) { + // Deplorable hack to make the submit method do the right thing. + var rmSubmit = connect(textarea.form, "submit", save, true); + if (typeof textarea.form.submit == "function") { + var realSubmit = textarea.form.submit; + function wrappedSubmit() { + save(); + textarea.form.submit = realSubmit; + textarea.form.submit(); + textarea.form.submit = wrappedSubmit; + } + textarea.form.submit = wrappedSubmit; + } + } + + textarea.style.display = "none"; + var instance = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + instance.save = save; + instance.getTextArea = function() { return textarea; }; + instance.toTextArea = function() { + save(); + textarea.parentNode.removeChild(instance.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + rmSubmit(); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + return instance; + }; + + // Utility functions for working with state. Exported because modes + // sometimes need to do this. + function copyState(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + } + CodeMirror.copyState = copyState; + function startState(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + } + CodeMirror.startState = startState; + + // The character stream used by a mode's parser. + function StringStream(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + } + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos);}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return countColumn(this.string, this.start, this.tabSize);}, + indentation: function() {return countColumn(this.string, null, this.tabSize);}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + function cased(str) {return caseInsensitive ? str.toLowerCase() : str;} + if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);} + }; + CodeMirror.StringStream = StringStream; + + function MarkedText(from, to, className, marker) { + this.from = from; this.to = to; this.style = className; this.marker = marker; + } + MarkedText.prototype = { + attach: function(line) { this.marker.set.push(line); }, + detach: function(line) { + var ix = indexOf(this.marker.set, line); + if (ix > -1) this.marker.set.splice(ix, 1); + }, + split: function(pos, lenBefore) { + if (this.to <= pos && this.to != null) return null; + var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore; + var to = this.to == null ? null : this.to - pos + lenBefore; + return new MarkedText(from, to, this.style, this.marker); + }, + dup: function() { return new MarkedText(null, null, this.style, this.marker); }, + clipTo: function(fromOpen, from, toOpen, to, diff) { + if (fromOpen && to > this.from && (to < this.to || this.to == null)) + this.from = null; + else if (this.from != null && this.from >= from) + this.from = Math.max(to, this.from) + diff; + if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null)) + this.to = null; + else if (this.to != null && this.to > from) + this.to = to < this.to ? this.to + diff : from; + }, + isDead: function() { return this.from != null && this.to != null && this.from >= this.to; }, + sameSet: function(x) { return this.marker == x.marker; } + }; + + function Bookmark(pos) { + this.from = pos; this.to = pos; this.line = null; + } + Bookmark.prototype = { + attach: function(line) { this.line = line; }, + detach: function(line) { if (this.line == line) this.line = null; }, + split: function(pos, lenBefore) { + if (pos < this.from) { + this.from = this.to = (this.from - pos) + lenBefore; + return this; + } + }, + isDead: function() { return this.from > this.to; }, + clipTo: function(fromOpen, from, toOpen, to, diff) { + if ((fromOpen || from < this.from) && (toOpen || to > this.to)) { + this.from = 0; this.to = -1; + } else if (this.from > from) { + this.from = this.to = Math.max(to, this.from) + diff; + } + }, + sameSet: function(x) { return false; }, + find: function() { + if (!this.line || !this.line.parent) return null; + return {line: lineNo(this.line), ch: this.from}; + }, + clear: function() { + if (this.line) { + var found = indexOf(this.line.marked, this); + if (found != -1) this.line.marked.splice(found, 1); + this.line = null; + } + } + }; + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + function Line(text, styles) { + this.styles = styles || [text, null]; + this.text = text; + this.height = 1; + this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null; + this.stateAfter = this.parent = this.hidden = null; + } + Line.inheritMarks = function(text, orig) { + var ln = new Line(text), mk = orig && orig.marked; + if (mk) { + for (var i = 0; i < mk.length; ++i) { + if (mk[i].to == null && mk[i].style) { + var newmk = ln.marked || (ln.marked = []), mark = mk[i]; + var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln); + } + } + } + return ln; + } + Line.prototype = { + // Replace a piece of a line, keeping the styles around it intact. + replace: function(from, to_, text) { + var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_; + copyStyles(0, from, this.styles, st); + if (text) st.push(text, null); + copyStyles(to, this.text.length, this.styles, st); + this.styles = st; + this.text = this.text.slice(0, from) + text + this.text.slice(to); + this.stateAfter = null; + if (mk) { + var diff = text.length - (to - from); + for (var i = 0; i < mk.length; ++i) { + var mark = mk[i]; + mark.clipTo(from == null, from || 0, to_ == null, to, diff); + if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);} + } + } + }, + // Split a part off a line, keeping styles and markers intact. + split: function(pos, textBefore) { + var st = [textBefore, null], mk = this.marked; + copyStyles(pos, this.text.length, this.styles, st); + var taken = new Line(textBefore + this.text.slice(pos), st); + if (mk) { + for (var i = 0; i < mk.length; ++i) { + var mark = mk[i]; + var newmark = mark.split(pos, textBefore.length); + if (newmark) { + if (!taken.marked) taken.marked = []; + taken.marked.push(newmark); newmark.attach(taken); + if (newmark == mark) mk.splice(i--, 1); + } + } + } + return taken; + }, + append: function(line) { + var mylen = this.text.length, mk = line.marked, mymk = this.marked; + this.text += line.text; + copyStyles(0, line.text.length, line.styles, this.styles); + if (mymk) { + for (var i = 0; i < mymk.length; ++i) + if (mymk[i].to == null) mymk[i].to = mylen; + } + if (mk && mk.length) { + if (!mymk) this.marked = mymk = []; + outer: for (var i = 0; i < mk.length; ++i) { + var mark = mk[i]; + if (!mark.from) { + for (var j = 0; j < mymk.length; ++j) { + var mymark = mymk[j]; + if (mymark.to == mylen && mymark.sameSet(mark)) { + mymark.to = mark.to == null ? null : mark.to + mylen; + if (mymark.isDead()) { + mymark.detach(this); + mk.splice(i--, 1); + } + continue outer; + } + } + } + mymk.push(mark); + mark.attach(this); + mark.from += mylen; + if (mark.to != null) mark.to += mylen; + } + } + }, + fixMarkEnds: function(other) { + var mk = this.marked, omk = other.marked; + if (!mk) return; + outer: for (var i = 0; i < mk.length; ++i) { + var mark = mk[i], close = mark.to == null; + if (close && omk) { + for (var j = 0; j < omk.length; ++j) { + var om = omk[j]; + if (!om.sameSet(mark) || om.from != null) continue + if (mark.from == this.text.length && om.to == 0) { + omk.splice(j, 1); + mk.splice(i--, 1); + continue outer; + } else { + close = false; break; + } + } + } + if (close) mark.to = this.text.length; + } + }, + fixMarkStarts: function() { + var mk = this.marked; + if (!mk) return; + for (var i = 0; i < mk.length; ++i) + if (mk[i].from == null) mk[i].from = 0; + }, + addMark: function(mark) { + mark.attach(this); + if (this.marked == null) this.marked = []; + this.marked.push(mark); + this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);}); + }, + // Run the given mode's parser over a line, update the styles + // array, which contains alternating fragments of text and CSS + // classes. + highlight: function(mode, state, tabSize) { + var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0; + var changed = false, curWord = st[0], prevWord; + if (this.text == "" && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + var substr = this.text.slice(stream.start, stream.pos); + stream.start = stream.pos; + if (pos && st[pos-1] == style) + st[pos-2] += substr; + else if (substr) { + if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true; + st[pos++] = substr; st[pos++] = style; + prevWord = curWord; curWord = st[pos]; + } + // Give up when line is ridiculously long + if (stream.pos > 5000) { + st[pos++] = this.text.slice(stream.pos); st[pos++] = null; + break; + } + } + if (st.length != pos) {st.length = pos; changed = true;} + if (pos && st[pos-2] != prevWord) changed = true; + // Short lines with simple highlights return null, and are + // counted as changed by the driver because they are likely to + // highlight the same way in various contexts. + return changed || (st.length < 5 && this.text.length < 10 ? null : false); + }, + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(mode, state, ch) { + var txt = this.text, stream = new StringStream(txt); + while (stream.pos < ch && !stream.eol()) { + stream.start = stream.pos; + var style = mode.token(stream, state); + } + return {start: stream.start, + end: stream.pos, + string: stream.current(), + className: style || null, + state: state}; + }, + indentation: function(tabSize) {return countColumn(this.text, null, tabSize);}, + // Produces an HTML fragment for the line, taking selection, + // marking, and highlighting into account. + getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) { + var html = [], first = true, col = 0; + function span_(text, style) { + if (!text) return; + // Work around a bug where, in some compat modes, IE ignores leading spaces + if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1); + first = false; + if (text.indexOf("\t") == -1) { + col += text.length; + var escaped = htmlEscape(text); + } else { + var escaped = ""; + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + escaped += htmlEscape(text.slice(pos)); + col += text.length - pos; + break; + } else { + col += idx - pos; + var tab = makeTab(col); + escaped += htmlEscape(text.slice(pos, idx)) + tab.html; + col += tab.width; + pos = idx + 1; + } + } + } + if (style) html.push('', escaped, ""); + else html.push(escaped); + } + var span = span_; + if (wrapAt != null) { + var outPos = 0, open = ""; + span = function(text, style) { + var l = text.length; + if (wrapAt >= outPos && wrapAt < outPos + l) { + if (wrapAt > outPos) { + span_(text.slice(0, wrapAt - outPos), style); + // See comment at the definition of spanAffectsWrapping + if (wrapWBR) html.push(""); + } + html.push(open); + var cut = wrapAt - outPos; + span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style); + html.push(""); + if (opera) span_(text.slice(cut + 1), style); + wrapAt--; + outPos += l; + } else { + outPos += l; + span_(text, style); + // Output empty wrapper when at end of line + // (Gecko and IE8+ do strange wrapping when adding a space + // to the end of the line. Other browsers don't react well + // to zero-width spaces. So we do hideous browser sniffing + // to determine which to use.) + if (outPos == wrapAt && outPos == len) + html.push(open + (gecko || (ie && !ie_lt8) ? "​" : " ") + ""); + // Stop outputting HTML when gone sufficiently far beyond measure + else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){}; + } + } + } + + var st = this.styles, allText = this.text, marked = this.marked; + var len = allText.length; + function styleToClass(style) { + if (!style) return null; + return "cm-" + style.replace(/ +/g, " cm-"); + } + + if (!allText && wrapAt == null) { + span(" "); + } else if (!marked || !marked.length) { + for (var i = 0, ch = 0; ch < len; i+=2) { + var str = st[i], style = st[i+1], l = str.length; + if (ch + l > len) str = str.slice(0, len - ch); + ch += l; + span(str, styleToClass(style)); + } + } else { + var pos = 0, i = 0, text = "", style, sg = 0; + var nextChange = marked[0].from || 0, marks = [], markpos = 0; + function advanceMarks() { + var m; + while (markpos < marked.length && + ((m = marked[markpos]).from == pos || m.from == null)) { + if (m.style != null) marks.push(m); + ++markpos; + } + nextChange = markpos < marked.length ? marked[markpos].from : Infinity; + for (var i = 0; i < marks.length; ++i) { + var to = marks[i].to; + if (to == null) to = Infinity; + if (to == pos) marks.splice(i--, 1); + else nextChange = Math.min(to, nextChange); + } + } + var m = 0; + while (pos < len) { + if (nextChange == pos) advanceMarks(); + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + var appliedStyle = style; + for (var j = 0; j < marks.length; ++j) + appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style; + span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle); + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + } + text = st[i++]; style = styleToClass(st[i++]); + } + } + } + return html.join(""); + }, + cleanUp: function() { + this.parent = null; + if (this.marked) + for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this); + } + }; + // Utility used by replace and split above + function copyStyles(from, to, source, dest) { + for (var i = 0, pos = 0, state = 0; pos < to; i+=2) { + var part = source[i], end = pos + part.length; + if (state == 0) { + if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]); + if (end >= from) state = 1; + } else if (state == 1) { + if (end > to) dest.push(part.slice(0, to - pos), source[i+1]); + else dest.push(part, source[i+1]); + } + pos = end; + } + } + + // Data structure that holds the sequence of lines. + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, e = lines.length, height = 0; i < e; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + remove: function(at, n, callbacks) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + line.cleanUp(); + if (line.handlers) + for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]); + } + this.lines.splice(at, n); + }, + collapse: function(lines) { + lines.splice.apply(lines, [lines.length, 0].concat(this.lines)); + }, + insertHeight: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this; + }, + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0, e = children.length; i < e; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + remove: function(at, n, callbacks) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.remove(at, rm, callbacks); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + if (this.size - n < 25) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines); + }, + insert: function(at, lines) { + var height = 0; + for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; + this.insertHeight(at, lines, height); + }, + insertHeight: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0, e = this.children.length; i < e; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertHeight(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iter: function(from, to, op) { this.iterN(from, to - from, op); }, + iterN: function(at, n, op) { + for (var i = 0, e = this.children.length; i < e; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + function getLineAt(chunk, n) { + while (!chunk.lines) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0, e = chunk.children.length; ; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no; + } + function lineAtHeight(chunk, h) { + var n = 0; + outer: do { + for (var i = 0, e = chunk.children.length; i < e; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0, e = chunk.lines.length; i < e; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + function heightAtLine(chunk, n) { + var h = 0; + outer: do { + for (var i = 0, e = chunk.children.length; i < e; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; continue outer; } + n -= sz; + h += child.height; + } + return h; + } while (!chunk.lines); + for (var i = 0; i < n; ++i) h += chunk.lines[i].height; + return h; + } + + // The history object 'chunks' changes that are made close together + // and at almost the same time into bigger undoable units. + function History() { + this.time = 0; + this.done = []; this.undone = []; + this.compound = 0; + this.closed = false; + } + History.prototype = { + addChange: function(start, added, old) { + this.undone.length = 0; + var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1]; + var dtime = time - this.time; + + if (this.compound && cur && !this.closed) { + cur.push({start: start, added: added, old: old}); + } else if (dtime > 400 || !last || this.closed || + last.start > start + old.length || last.start + last.added < start) { + this.done.push([{start: start, added: added, old: old}]); + this.closed = false; + } else { + var startBefore = Math.max(0, last.start - start), + endAfter = Math.max(0, (start + old.length) - (last.start + last.added)); + for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]); + for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]); + if (startBefore) last.start = start; + last.added += added - (old.length - startBefore - endAfter); + } + this.time = time; + }, + startCompound: function() { + if (!this.compound++) this.closed = true; + }, + endCompound: function() { + if (!--this.compound) this.closed = true; + } + }; + + function stopMethod() {e_stop(this);} + // Ensure an event has a stop method. + function addStop(event) { + if (!event.stop) event.stop = stopMethod; + return event; + } + + function e_preventDefault(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + function e_stopPropagation(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + } + function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);} + CodeMirror.e_stop = e_stop; + CodeMirror.e_preventDefault = e_preventDefault; + CodeMirror.e_stopPropagation = e_stopPropagation; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // Allow 3rd-party code to override event properties by adding an override + // object to an event object. + function e_prop(e, prop) { + var overridden = e.override && e.override.hasOwnProperty(prop); + return overridden ? e.override[prop] : e[prop]; + } + + // Event handler registration. If disconnect is true, it'll return a + // function that unregisters the handler. + function connect(node, type, handler, disconnect) { + if (typeof node.addEventListener == "function") { + node.addEventListener(type, handler, false); + if (disconnect) return function() {node.removeEventListener(type, handler, false);}; + } else { + var wrapHandler = function(event) {handler(event || window.event);}; + node.attachEvent("on" + type, wrapHandler); + if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);}; + } + } + CodeMirror.connect = connect; + + function Delayed() {this.id = null;} + Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}}; + + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + var gecko = /gecko\/\d{7}/i.test(navigator.userAgent); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent); + var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent); + var quirksMode = ie && document.documentMode == 5; + var webkit = /WebKit\//.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var opera = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var khtml = /KHTML\//.test(navigator.userAgent); + var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent); + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie_lt9) return false; + var div = document.createElement('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + // Feature-detect whether newlines in textareas are converted to \r\n + var lineSep = function () { + var te = document.createElement("textarea"); + te.value = "foo\nbar"; + if (te.value.indexOf("\r") > -1) return "\r\n"; + return "\n"; + }(); + + // For a reason I have yet to figure out, some browsers disallow + // word wrapping between certain characters *only* if a new inline + // element is started between them. This makes it hard to reliably + // measure the position of things, since that requires inserting an + // extra span. This terribly fragile set of regexps matches the + // character combinations that suffer from this phenomenon on the + // various browsers. + var spanAffectsWrapping = /^$/; // Won't match any two-character string + if (gecko) spanAffectsWrapping = /$'/; + else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/; + else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + function countColumn(string, end, tabSize) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = 0, n = 0; i < end; ++i) { + if (string.charAt(i) == "\t") n += tabSize - (n % tabSize); + else ++n; + } + return n; + } + + function computedStyle(elt) { + if (elt.currentStyle) return elt.currentStyle; + return window.getComputedStyle(elt, null); + } + + function eltOffset(node, screen) { + // Take the parts of bounding client rect that we are interested in so we are able to edit if need be, + // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page) + try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; } + catch(e) { box = {top: 0, left: 0}; } + if (!screen) { + // Get the toplevel scroll, working around browser differences. + if (window.pageYOffset == null) { + var t = document.documentElement || document.body.parentNode; + if (t.scrollTop == null) t = document.body; + box.top += t.scrollTop; box.left += t.scrollLeft; + } else { + box.top += window.pageYOffset; box.left += window.pageXOffset; + } + } + return box; + } + + // Get a node's text content. + function eltText(node) { + return node.textContent || node.innerText || node.nodeValue || ""; + } + function selectInput(node) { + if (ios) { // Mobile Safari apparently has a bug where select() is broken. + node.selectionStart = 0; + node.selectionEnd = node.value.length; + } else node.select(); + } + + // Operations on {line, ch} objects. + function posEq(a, b) {return a.line == b.line && a.ch == b.ch;} + function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);} + function copyPos(x) {return {line: x.line, ch: x.ch};} + + var escapeElement = document.createElement("pre"); + function htmlEscape(str) { + escapeElement.textContent = str; + return escapeElement.innerHTML; + } + // Recent (late 2011) Opera betas insert bogus newlines at the start + // of the textContent, so we strip those. + if (htmlEscape("a") == "\na") { + htmlEscape = function(str) { + escapeElement.textContent = str; + return escapeElement.innerHTML.slice(1); + }; + // Some IEs don't preserve tabs through innerHTML + } else if (htmlEscape("\t") != "\t") { + htmlEscape = function(str) { + escapeElement.innerHTML = ""; + escapeElement.appendChild(document.createTextNode(str)); + return escapeElement.innerHTML; + }; + } + CodeMirror.htmlEscape = htmlEscape; + + // Used to position the cursor after an undo/redo by finding the + // last edited character. + function editEnd(from, to) { + if (!to) return 0; + if (!from) return to.length; + for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j) + if (from.charAt(i) != to.charAt(j)) break; + return j + 1; + } + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + function isWordChar(ch) { + return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase(); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + CodeMirror.splitLines = splitLines; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete", + 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home", + 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + return CodeMirror; +})(); \ No newline at end of file diff --git a/lib/client/editor/codemirror/mode/xml.js b/lib/client/editor/codemirror/mode/xml.js new file mode 100644 index 00000000..7a388927 --- /dev/null +++ b/lib/client/editor/codemirror/mode/xml.js @@ -0,0 +1,326 @@ +CodeMirror.defineMode("xml", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var Kludges = parserConfig.htmlMode ? { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: false + } : { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false + }; + var alignCDATA = parserConfig.alignCDATA; + + // Return variables for tokenizers + var tagName, type; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } + else if (stream.match("--")) return chain(inBlock("comment", "-->")); + else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } + else return null; + } + else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } + else { + type = stream.eat("/") ? "closeTag" : "openTag"; + stream.eatSpace(); + tagName = ""; + var c; + while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; + state.tokenize = inTag; + return "tag"; + } + } + else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } + else { + stream.eatWhile(/[^&<]/); + return null; + } + } + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag"; + } + else if (ch == "=") { + type = "equals"; + return null; + } + else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + return state.tokenize(stream, state); + } + else { + stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/); + return "word"; + } + } + + function inAttribute(quote) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + var curState, setStyle; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + + function pushContext(tagName, startOfLine) { + var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent); + curState.context = { + prev: curState.context, + tagName: tagName, + indent: curState.indented, + startOfLine: startOfLine, + noIndent: noIndent + }; + } + function popContext() { + if (curState.context) curState.context = curState.context.prev; + } + + function element(type) { + if (type == "openTag") { + curState.tagName = tagName; + return cont(attributes, endtag(curState.startOfLine)); + } else if (type == "closeTag") { + var err = false; + if (curState.context) { + if (curState.context.tagName != tagName) { + if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) { + popContext(); + } + err = !curState.context || curState.context.tagName != tagName; + } + } else { + err = true; + } + if (err) setStyle = "error"; + return cont(endclosetag(err)); + } + return cont(); + } + function endtag(startOfLine) { + return function(type) { + if (type == "selfcloseTag" || + (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) { + maybePopContext(curState.tagName.toLowerCase()); + return cont(); + } + if (type == "endTag") { + maybePopContext(curState.tagName.toLowerCase()); + pushContext(curState.tagName, startOfLine); + return cont(); + } + return cont(); + }; + } + function endclosetag(err) { + return function(type) { + if (err) setStyle = "error"; + if (type == "endTag") { popContext(); return cont(); } + setStyle = "error"; + return cont(arguments.callee); + } + } + function maybePopContext(nextTagName) { + var parentTagName; + while (true) { + if (!curState.context) { + return; + } + parentTagName = curState.context.tagName.toLowerCase(); + if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || + !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(); + } + } + + function attributes(type) { + if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);} + if (type == "endTag" || type == "selfcloseTag") return pass(); + setStyle = "error"; + return cont(attributes); + } + function attribute(type) { + if (type == "equals") return cont(attvalue, attributes); + if (!Kludges.allowMissing) setStyle = "error"; + return (type == "endTag" || type == "selfcloseTag") ? pass() : cont(); + } + function attvalue(type) { + if (type == "string") return cont(attvaluemaybe); + if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();} + setStyle = "error"; + return (type == "endTag" || type == "selfCloseTag") ? pass() : cont(); + } + function attvaluemaybe(type) { + if (type == "string") return cont(attvaluemaybe); + else return pass(); + } + + return { + startState: function() { + return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.startOfLine = true; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + + setStyle = type = tagName = null; + var style = state.tokenize(stream, state); + state.type = type; + if ((style || type) && style != "comment") { + curState = state; + while (true) { + var comb = state.cc.pop() || element; + if (comb(type || style)) break; + } + } + state.startOfLine = false; + return setStyle || style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + if ((state.tokenize != inTag && state.tokenize != inText) || + context && context.noIndent) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + if (alignCDATA && /=0&&l=visible.to||cur.linenow-400&&posEq(lastDoubleClick.pos,start))type="triple",e_preventDefault(e),setTimeout(focusInput,20),selectLine(start.line);else if(lastClick&&lastClick.time>now-400&&posEq(lastClick.pos,start)){type="double",lastDoubleClick={time:now,pos:start},e_preventDefault(e);var word=findWordAt(start);setSelectionUser(word.from,word.to)}else lastClick={time:now,pos:start};var last=start,going;if(options.dragDrop&&dragAndDrop&&!options.readOnly&&!posEq(sel.from,sel.to)&&!posLess(start,sel.from)&&!posLess(sel.to,start)&&type=="single"){webkit&&(scroller.draggable=!0);function dragEnd(e2){webkit&&(scroller.draggable=!1),draggingText=!1,up(),drop(),Math.abs(e.clientX-e2.clientX)+Math.abs(e.clientY-e2.clientY)<10&&(e_preventDefault(e2),setCursor(start.line,start.ch,!0),focusInput())}var up=connect(document,"mouseup",operation(dragEnd),!0),drop=connect(scroller,"drop",operation(dragEnd),!0);draggingText=!0,scroller.dragDrop&&scroller.dragDrop();return}e_preventDefault(e),type=="single"&&setCursor(start.line,start.ch,!0);var startstart=sel.from,startend=sel.to,move=connect(document,"mousemove",operation(function(e){clearTimeout(going),e_preventDefault(e),!ie&&!e_button(e)?done(e):extend(e)}),!0),up=connect(document,"mouseup",operation(done),!0)}function onDoubleClick(e){for(var n=e_target(e);n!=wrapper;n=n.parentNode)if(n.parentNode==gutterText)return e_preventDefault(e);e_preventDefault(e)}function onDrop(e){if(options.onDragEvent&&options.onDragEvent(instance,addStop(e)))return;e.preventDefault();var pos=posFromMouse(e,!0),files=e.dataTransfer.files;if(!pos||options.readOnly)return;if(files&&files.length&&window.FileReader&&window.File){function loadFile(file,i){var reader=new FileReader;reader.onload=function(){text[i]=reader.result,++read==n&&(pos=clipPos(pos),operation(function(){var end=replaceRange(text.join(""),pos,pos);setSelectionUser(pos,end)})())},reader.readAsText(file)}var n=files.length,text=Array(n),read=0;for(var i=0;i-1&&setTimeout(operation(function(){indentLine(sel.to.line,"smart")}),75);if(handleCharBinding(e,ch))return;fastPoll()}function onKeyUp(e){if(options.onKeyEvent&&options.onKeyEvent(instance,addStop(e)))return;e_prop(e,"keyCode")==16&&(shiftSelecting=null)}function onFocus(){if(options.readOnly=="nocursor")return;focused||(options.onFocus&&options.onFocus(instance),focused=!0,scroller.className.search(/\bCodeMirror-focused\b/)==-1&&(scroller.className+=" CodeMirror-focused"),leaveInputAlone||resetInput(!0)),slowPoll(),restartBlink()}function onBlur(){focused&&(options.onBlur&&options.onBlur(instance),focused=!1,bracketHighlighted&&operation(function(){bracketHighlighted&&(bracketHighlighted(),bracketHighlighted=null)})(),scroller.className=scroller.className.replace(" CodeMirror-focused","")),clearInterval(blinker),setTimeout(function(){focused||(shiftSelecting=null)},150)}function chopDelta(delta){return delta>0&&delta<1?1:delta>-1&&delta<0?-1:Math.round(delta)}function onMouseWheel(e){var deltaX=0,deltaY=0;if(e.type=="DOMMouseScroll"){var delta=-e.detail*8;e.axis==e.HORIZONTAL_AXIS?deltaX=delta:e.axis==e.VERTICAL_AXIS&&(deltaY=delta)}else e.wheelDeltaX!==undefined&&e.wheelDeltaY!==undefined?(deltaX=e.wheelDeltaX/3,deltaY=e.wheelDeltaY/3):e.wheelDelta!==undefined&&(deltaY=e.wheelDelta/3);var scrolled=!1;deltaX=chopDelta(deltaX),deltaY=chopDelta(deltaY);if(deltaX>0&&scroller.scrollLeft>0||deltaX<0&&scroller.scrollLeft+scroller.clientWidth0&&scrollbar.scrollTop>0||deltaY<0&&scrollbar.scrollTop+scrollbar.clientHeightoptions.undoDepth)history.done.shift()}updateLinesNoUndo(from,to,newText,selFrom,selTo)}function unredoHelper(from,to){if(!from.length)return;var set=from.pop(),out=[];for(var i=set.length-1;i>=0;i-=1){var change=set[i],replaced=[],end=change.start+change.added;doc.iter(change.start,end,function(line){replaced.push(line.text)}),out.push({start:change.start,added:change.old.length,old:replaced});var pos={line:change.start+change.old.length-1,ch:editEnd(replaced[replaced.length-1],change.old[change.old.length-1])};updateLinesNoUndo({line:change.start,ch:0},{line:end-1,ch:getLine(end-1).text.length},change.old,pos,pos)}updateInput=!0,to.push(out)}function undo(){unredoHelper(history.done,history.undone)}function redo(){unredoHelper(history.undone,history.done)}function updateLinesNoUndo(from,to,newText,selFrom,selTo){function updateLine(n){return n<=Math.min(to.line,to.line+lendiff)?n:n+lendiff}if(suppressEdits)return;var recomputeMaxLength=!1,maxLineLength=maxLine.length;options.lineWrapping||doc.iter(from.line,to.line+1,function(line){if(!line.hidden&&line.text.length==maxLineLength)return recomputeMaxLength=!0,!0});if(from.line!=to.line||newText.length>1)gutterDirty=!0;var nlines=to.line-from.line,firstLine=getLine(from.line),lastLine=getLine(to.line);if(from.ch==0&&to.ch==0&&newText[newText.length-1]==""){var added=[],prevLine=null;from.line?(prevLine=getLine(from.line-1),prevLine.fixMarkEnds(lastLine)):lastLine.fixMarkStarts();for(var i=0,e=newText.length-1;i1&&doc.remove(from.line+1,nlines-1,callbacks),doc.insert(from.line+1,added)}if(options.lineWrapping){var perLine=Math.max(5,scroller.clientWidth/charWidth()-3);doc.iter(from.line,from.line+newText.length,function(line){if(line.hidden)return;var guess=Math.ceil(line.text.length/perLine)||1;guess!=line.height&&updateLineHeight(line,guess)})}else doc.iter(from.line,from.line+newText.length,function(line){var l=line.text;!line.hidden&&l.length>maxLineLength&&(maxLine=l,maxLineLength=l.length,maxLineChanged=!0,recomputeMaxLength=!1)}),recomputeMaxLength&&(updateMaxLine=!0);var newWork=[],lendiff=newText.length-nlines-1;for(var i=0,l=work.length;ito.line&&newWork.push(task+lendiff)}var hlEnd=from.line+Math.min(newText.length,500);highlightLines(from.line,hlEnd),newWork.push(hlEnd),work=newWork,startWorker(100),changes.push({from:from.line,to:to.line+1,diff:lendiff});var changeObj={from:from,to:to,text:newText};if(textChanged){for(var cur=textChanged;cur.next;cur=cur.next);cur.next=changeObj}else textChanged=changeObj;setSelection(clipPos(selFrom),clipPos(selTo),updateLine(sel.from.line),updateLine(sel.to.line))}function needsScrollbar(){var realHeight=doc.height*textHeight()+2*paddingTop();return realHeight-1>scroller.offsetHeight?realHeight:!1}function updateVerticalScroll(scrollTop){var scrollHeight=needsScrollbar();scrollbar.style.display=scrollHeight?"block":"none",scrollHeight&&(scrollbarInner.style.height=scrollHeight+"px",scrollbar.style.height=scroller.offsetHeight+"px",scrollTop!=null&&(scrollbar.scrollTop=scrollTop)),mover.style.top=displayOffset*textHeight()-scrollbar.scrollTop+"px"}function overlapScrollbars(){var tmpSb=document.createElement("div"),tmpSbInner=document.createElement("div");tmpSb.className="CodeMirror-scrollbar",tmpSb.style.cssText="position: absolute; left: -9999px; height: 100px;",tmpSbInner.className="CodeMirror-scrollbar-inner",tmpSbInner.style.height="200px",tmpSb.appendChild(tmpSbInner),document.body.appendChild(tmpSb);var result=tmpSb.offsetWidth<=1;return document.body.removeChild(tmpSb),result}function computeMaxLength(){var maxLineLength=0;maxLine="",maxLineChanged=!0,doc.iter(0,doc.size,function(line){var l=line.text;!line.hidden&&l.length>maxLineLength&&(maxLineLength=l.length,maxLine=l)}),updateMaxLine=!1}function replaceRange(code,from,to){function adjustPos(pos){if(posLess(pos,from))return pos;if(!posLess(to,pos))return end;var line=pos.line+code.length-(to.line-from.line)-1,ch=pos.ch;return pos.line==to.line&&(ch+=code[code.length-1].length-(to.ch-(to.line==from.line?from.ch:0))),{line:line,ch:ch}}from=clipPos(from),to?to=clipPos(to):to=from,code=splitLines(code);var end;return replaceRange1(code,from,to,function(end1){return end=end1,{from:adjustPos(sel.from),to:adjustPos(sel.to)}}),end}function replaceSelection(code,collapse){replaceRange1(splitLines(code),sel.from,sel.to,function(end){return collapse=="end"?{from:end,to:end}:collapse=="start"?{from:sel.from,to:sel.from}:{from:sel.from,to:end}})}function replaceRange1(code,from,to,computeSel){var endch=code.length==1?code[0].length+from.ch:code[code.length-1].length,newSel=computeSel({line:from.line+code.length-1,ch:endch});updateLines(from,to,code,newSel.from,newSel.to)}function getRange(from,to,lineSep){var l1=from.line,l2=to.line;if(l1==l2)return getLine(l1).text.slice(from.ch,to.ch);var code=[getLine(l1).text.slice(from.ch)];return doc.iter(l1+1,l2,function(line){code.push(line.text)}),code.push(getLine(l2).text.slice(0,to.ch)),code.join(lineSep||"\n")}function getSelection(lineSep){return getRange(sel.from,sel.to,lineSep)}function slowPoll(){if(pollingFast)return;poll.set(options.pollInterval,function(){startOperation(),readInput(),focused&&slowPoll(),endOperation()})}function fastPoll(){function p(){startOperation();var changed=readInput();!changed&&!missed?(missed=!0,poll.set(60,p)):(pollingFast=!1,slowPoll()),endOperation()}var missed=!1;pollingFast=!0,poll.set(20,p)}function readInput(){if(leaveInputAlone||!focused||hasSelection(input)||options.readOnly)return!1;var text=input.value;if(text==prevInput)return!1;shiftSelecting=null;var same=0,l=Math.min(prevInput.length,text.length);while(same1e3?input.value=prevInput="":prevInput=text,!0}function resetInput(user){posEq(sel.from,sel.to)?user&&(prevInput=input.value=""):(prevInput="",input.value=getSelection(),selectInput(input))}function focusInput(){options.readOnly!="nocursor"&&input.focus()}function scrollEditorIntoView(){var rect=cursor.getBoundingClientRect();if(ie&&rect.top==rect.bottom)return;var winH=window.innerHeight||Math.max(document.body.offsetHeight,document.documentElement.offsetHeight);(rect.top<0||rect.bottom>winH)&&scrollCursorIntoView()}function scrollCursorIntoView(){var coords=calculateCursorCoords();return scrollIntoView(coords.x,coords.y,coords.x,coords.yBot)}function calculateCursorCoords(){var cursor=localCoords(sel.inverted?sel.from:sel.to),x=options.lineWrapping?Math.min(cursor.x,lineSpace.offsetWidth):cursor.x;return{x:x,y:cursor.y,yBot:cursor.yBot}}function scrollIntoView(x1,y1,x2,y2){var scrollPos=calculateScrollPos(x1,y1,x2,y2),scrolled=!1;scrollPos.scrollLeft!=null&&(scroller.scrollLeft=scrollPos.scrollLeft,scrolled=!0),scrollPos.scrollTop!=null&&(scrollbar.scrollTop=scrollPos.scrollTop,scrolled=!0),scrolled&&options.onScroll&&options.onScroll(instance)}function calculateScrollPos(x1,y1,x2,y2){var pl=paddingLeft(),pt=paddingTop();y1+=pt,y2+=pt,x1+=pl,x2+=pl;var screen=scroller.clientHeight,screentop=scrollbar.scrollTop,result={},docBottom=scroller.scrollHeight,atTop=y1docBottom-10;y1screentop+screen&&(result.scrollTop=(atBottom?docBottom:y2)-screen);var screenw=scroller.clientWidth,screenleft=scroller.scrollLeft,gutterw=options.fixedGutter?gutter.clientWidth:0,atLeft=x1screenw+screenleft-3&&(result.scrollLeft=x2+10-screenw),result}function visibleLines(scrollTop){var lh=textHeight(),top=(scrollTop!=null?scrollTop:scrollbar.scrollTop)-paddingTop(),fromHeight=Math.max(0,Math.floor(top/lh)),toHeight=Math.ceil((top+scroller.clientHeight)/lh);return{from:lineAtHeight(doc,fromHeight),to:lineAtHeight(doc,toHeight)}}function updateDisplay(changes,suppressCallback,scrollTop){function checkHeights(){var curNode=lineDiv.firstChild,heightChanged=!1;return doc.iter(showingFrom,showingTo,function(line){if(!line.hidden){var height=Math.round(curNode.offsetHeight/th)||1;line.height!=height&&(updateLineHeight(line,height),gutterDirty=heightChanged=!0)}curNode=curNode.nextSibling}),heightChanged}if(!scroller.clientWidth){showingFrom=showingTo=displayOffset=0;return}var visible=visibleLines(scrollTop);if(changes!==!0&&changes.length==0&&visible.from>showingFrom&&visible.toto&&showingTo-to<20&&(to=Math.min(doc.size,showingTo));var intact=changes===!0?[]:computeIntact([{from:showingFrom,to:showingTo,domStart:0}],changes),intactLines=0;for(var i=0;ito&&(range.to=to),range.from>=range.to?intact.splice(i--,1):intactLines+=range.to-range.from}if(intactLines==to-from&&from==showingFrom&&to==showingTo){updateVerticalScroll(scrollTop);return}intact.sort(function(a,b){return a.domStart-b.domStart});var th=textHeight(),gutterDisplay=gutter.style.display;lineDiv.style.display="none",patchDisplay(from,to,intact),lineDiv.style.display=gutter.style.display="";var different=from!=showingFrom||to!=showingTo||lastSizeC!=scroller.clientHeight+th;different&&(lastSizeC=scroller.clientHeight+th),showingFrom=from,showingTo=to,displayOffset=heightAtLine(doc,from);if(lineDiv.childNodes.length!=showingTo-showingFrom)throw new Error("BAD PATCH! "+JSON.stringify(intact)+" size="+(showingTo-showingFrom)+" nodes="+lineDiv.childNodes.length);if(options.lineWrapping){checkHeights();var scrollHeight=needsScrollbar(),shouldHaveScrollbar=scrollHeight?"block":"none";scrollbar.style.display!=shouldHaveScrollbar&&(scrollbar.style.display=shouldHaveScrollbar,scrollHeight&&(scrollbarInner.style.height=scrollHeight+"px"),checkHeights())}return gutter.style.display=gutterDisplay,(different||gutterDirty)&&updateGutter()&&options.lineWrapping&&checkHeights()&&updateGutter(),updateVerticalScroll(scrollTop),updateSelection(),!suppressCallback&&options.onUpdate&&options.onUpdate(instance),!0}function computeIntact(intact,changes){for(var i=0,l=changes.length||0;i=range.to?intact2.push(range):(change.from>range.from&&intact2.push({from:range.from,to:change.from,domStart:range.domStart}),change.todomPos)curNode=killNode(curNode),domPos++;for(var j=0,e=cur.to-cur.from;jj){if(line.hidden)var html=scratch.innerHTML="
";else{var html=""+line.getHTML(makeTab)+"
";line.bgClassName&&(html='
 
'+html+"
")}scratch.innerHTML=html,lineDiv.insertBefore(scratch.firstChild,curNode)}else curNode=curNode.nextSibling;++j})}function updateGutter(){if(!options.gutter&&!options.lineNumbers)return;var hText=mover.offsetHeight,hEditor=scroller.clientHeight;gutter.style.height=(hText-hEditor<2?hEditor:hText)+"px";var html=[],i=showingFrom,normalNode;doc.iter(showingFrom,Math.max(showingTo,showingFrom+1),function(line){if(line.hidden)html.push("
");else{var marker=line.gutterMarker,text=options.lineNumbers?options.lineNumberFormatter(i+options.firstLineNumber):null;marker&&marker.text?text=marker.text.replace("%N%",text!=null?text:""):text==null&&(text=" "),html.push(marker&&marker.style?'
':"
",text);for(var j=1;j ");html.push("
"),marker||(normalNode=i)}++i}),gutter.style.display="none",gutterText.innerHTML=html.join("");if(normalNode!=null&&options.lineNumbers){var node=gutterText.childNodes[normalNode-showingFrom],minwidth=String(doc.size).length,val=eltText(node.firstChild),pad="";while(val.length+pad.length2;return lineSpace.style.marginLeft=gutter.offsetWidth+"px",gutterDirty=!1,resized}function updateSelection(){var collapsed=posEq(sel.from,sel.to),fromPos=localCoords(sel.from,!0),toPos=collapsed?fromPos:localCoords(sel.to,!0),headPos=sel.inverted?fromPos:toPos,th=textHeight(),wrapOff=eltOffset(wrapper),lineOff=eltOffset(lineDiv);inputDiv.style.top=Math.max(0,Math.min(scroller.offsetHeight,headPos.y+lineOff.top-wrapOff.top))+"px",inputDiv.style.left=Math.max(0,Math.min(scroller.offsetWidth,headPos.x+lineOff.left-wrapOff.left))+"px";if(collapsed)cursor.style.top=headPos.y+"px",cursor.style.left=(options.lineWrapping?Math.min(headPos.x,lineSpace.offsetWidth):headPos.x)+"px",cursor.style.display="",selectionDiv.style.display="none";else{var sameLine=fromPos.y==toPos.y,html="",clientWidth=lineSpace.clientWidth||lineSpace.offsetWidth,clientHeight=lineSpace.clientHeight||lineSpace.offsetHeight;function add(left,top,right,height){var rstyle=quirksMode?"width: "+(right?clientWidth-right-left:clientWidth)+"px":"right: "+right+"px";html+='
'}if(sel.from.ch&&fromPos.y>=0){var right=sameLine?clientWidth-toPos.x:0;add(fromPos.x,fromPos.y,right,th)}var middleStart=Math.max(0,fromPos.y+(sel.from.ch?th:0)),middleHeight=Math.min(toPos.y,clientHeight)-middleStart;middleHeight>.2*th&&add(0,middleStart,0,middleHeight),(!sameLine||!sel.from.ch)&&toPos.yoldCh||ch>line.text.length)ch=line.text.length;return{line:lNo,ch:ch}}lNo+=dir}}var line=getLine(pos.line),toEnd=pos.ch==line.text.length&&pos.ch!=oldCh;return line.hidden?pos.line>=oldLine?getNonHidden(1)||getNonHidden(-1):getNonHidden(-1)||getNonHidden(1):pos}function setCursor(line,ch,user){var pos=clipPos({line:line,ch:ch||0});(user?setSelectionUser:setSelection)(pos,pos)}function clipLine(n){return Math.max(0,Math.min(n,doc.size-1))}function clipPos(pos){if(pos.line<0)return{line:0,ch:0};if(pos.line>=doc.size)return{line:doc.size-1,ch:getLine(doc.size-1).text.length};var ch=pos.ch,linelen=getLine(pos.line).text.length;return ch==null||ch>linelen?{line:pos.line,ch:linelen}:ch<0?{line:pos.line,ch:0}:pos}function findPosH(dir,unit){function findNextLine(){for(var l=line+dir,e=dir<0?-1:doc.size;l!=e;l+=dir){var lo=getLine(l);if(!lo.hidden)return line=l,lineObj=lo,!0}}function moveOnce(boundToLine){if(ch==(dir<0?0:lineObj.text.length)){if(!!boundToLine||!findNextLine())return!1;ch=dir<0?lineObj.text.length:0}else ch+=dir;return!0}var end=sel.inverted?sel.from:sel.to,line=end.line,ch=end.ch,lineObj=getLine(line);if(unit=="char")moveOnce();else if(unit=="column")moveOnce(!0);else if(unit=="word"){var sawWord=!1;for(;;){if(dir<0&&!moveOnce())break;if(isWordChar(lineObj.text.charAt(ch)))sawWord=!0;else if(sawWord){dir<0&&(dir=1,moveOnce());break}if(dir>0&&!moveOnce())break}}return{line:line,ch:ch}}function moveH(dir,unit){var pos=dir<0?sel.from:sel.to;if(shiftSelecting||posEq(sel.from,sel.to))pos=findPosH(dir,unit);setCursor(pos.line,pos.ch,!0)}function deleteH(dir,unit){posEq(sel.from,sel.to)?dir<0?replaceRange("",findPosH(dir,unit),sel.to):replaceRange("",sel.from,findPosH(dir,unit)):replaceRange("",sel.from,sel.to),userSelChange=!0}function moveV(dir,unit){var dist=0,pos=localCoords(sel.inverted?sel.from:sel.to,!0);goalColumn!=null&&(pos.x=goalColumn),unit=="page"?dist=Math.min(scroller.clientHeight,window.innerHeight||document.documentElement.clientHeight):unit=="line"&&(dist=textHeight());var target=coordsChar(pos.x,pos.y+dist*dir+2);unit=="page"&&(scrollbar.scrollTop+=localCoords(target,!0).y-pos.y),setCursor(target.line,target.ch,!0),goalColumn=pos.x}function findWordAt(pos){var line=getLine(pos.line).text,start=pos.ch,end=pos.ch,check=isWordChar(line.charAt(start0&&check(line.charAt(start-1)))--start;while(endmaxLine.length&&(maxLine=line.text)});changes.push({from:0,to:doc.size})}function makeTab(col){var w=options.tabSize-col%options.tabSize,cached=tabCache[w];if(cached)return cached;for(var str='',i=0;i",width:w}}function themeChanged(){scroller.className=scroller.className.replace(/\s*cm-s-\S+/g,"")+options.theme.replace(/(^|\s)\s*/g," cm-s-")}function keyMapChanged(){var style=keyMap[options.keyMap].style;wrapper.className=wrapper.className.replace(/\s*cm-keymap-\S+/g,"")+(style?" cm-keymap-"+style:"")}function TextMarker(){this.set=[]}function markText(from,to,className){function add(line,from,to,className){getLine(line).addMark(new MarkedText(from,to,className,tm))}from=clipPos(from),to=clipPos(to);var tm=new TextMarker;if(!posLess(from,to))return tm;if(from.line==to.line)add(from.line,from.ch,to.ch,className);else{add(from.line,from.ch,null,className);for(var i=from.line+1,e=to.line;i=pos.ch)&&markers.push(m.marker||m)}return markers}function addGutterMarker(line,text,className){return typeof line=="number"&&(line=getLine(clipLine(line))),line.gutterMarker={text:text,style:className},gutterDirty=!0,line}function removeGutterMarker(line){typeof line=="number"&&(line=getLine(clipLine(line))),line.gutterMarker=null,gutterDirty=!0}function changeLine(handle,op){var no=handle,line=handle;return typeof handle=="number"?line=getLine(clipLine(handle)):no=lineNo(handle),no==null?null:op(line,no)?(changes.push({from:no,to:no+1}),line):null}function setLineClass(handle,className,bgClassName){return changeLine(handle,function(line){if(line.className!=className||line.bgClassName!=bgClassName)return line.className=className,line.bgClassName=bgClassName,!0})}function setLineHidden(handle,hidden){return changeLine(handle,function(line,no){if(line.hidden!=hidden){line.hidden=hidden;if(!options.lineWrapping){var l=line.text;hidden&&l.length==maxLine.length?updateMaxLine=!0:!hidden&&l.length>maxLine.length&&(maxLine=l,updateMaxLine=!1)}updateLineHeight(line,hidden?0:1);var fline=sel.from.line,tline=sel.to.line;if(hidden&&(fline==no||tline==no)){var from=fline==no?skipHidden({line:fline,ch:0},fline,0):sel.from,to=tline==no?skipHidden({line:tline,ch:0},tline,0):sel.to;if(!to)return;setSelection(from,to)}return gutterDirty=!0}})}function lineInfo(line){if(typeof line=="number"){if(!isLine(line))return null;var n=line;line=getLine(line);if(!line)return null}else{var n=lineNo(line);if(n==null)return null}var marker=line.gutterMarker;return{line:n,handle:line,text:line.text,markerText:marker&&marker.text,markerClass:marker&&marker.style,lineClass:line.className,bgClass:line.bgClassName}}function stringWidth(str){return measure.innerHTML="
x
",measure.firstChild.firstChild.firstChild.nodeValue=str,measure.firstChild.firstChild.offsetWidth||10}function charFromX(line,x){function getX(len){return measureLine(lineObj,len).left}if(x<=0)return 0;var lineObj=getLine(line),text=lineObj.text,from=0,fromX=0,to=text.length,toX,estimated=Math.min(to,Math.ceil(x/charWidth()));for(;;){var estX=getX(estimated);if(!(estX<=x&&estimatedtoX)return to;estimated=Math.floor(to*.8),estX=getX(estimated),estXx-fromX?from:to;var middle=Math.ceil((from+to)/2),middleX=getX(middle);middleX>x?(to=middle,toX=middleX):(from=middle,fromX=middleX)}}function measureLine(line,ch){if(ch==0)return{top:0,left:0};var wbr=options.lineWrapping&&ch"+line.getHTML(makeTab,ch,tempId,wbr)+"
";var elt=document.getElementById(tempId),top=elt.offsetTop,left=elt.offsetLeft;if(ie&&top==0&&left==0){var backup=document.createElement("span");backup.innerHTML="x",elt.parentNode.insertBefore(backup,elt.nextSibling),top=backup.offsetTop}return{top:top,left:left}}function localCoords(pos,inLineWrap){var x,lh=textHeight(),y=lh*(heightAtLine(doc,pos.line)-(inLineWrap?displayOffset:0));if(pos.ch==0)x=0;else{var sp=measureLine(getLine(pos.line),pos.ch);x=sp.left,options.lineWrapping&&(y+=Math.max(0,sp.top))}return{x:x,y:y,yBot:y+lh}}function coordsChar(x,y){function getX(len){var sp=measureLine(lineObj,len);if(tw){var off=Math.round(sp.top/th);return Math.max(0,sp.left+(off-innerOff)*scroller.clientWidth)}return sp.left}y<0&&(y=0);var th=textHeight(),cw=charWidth(),heightPos=displayOffset+Math.floor(y/th),lineNo=lineAtHeight(doc,heightPos);if(lineNo>=doc.size)return{line:doc.size-1,ch:getLine(doc.size-1).text.length};var lineObj=getLine(lineNo),text=lineObj.text,tw=options.lineWrapping,innerOff=tw?heightPos-heightAtLine(doc,lineNo):0;if(x<=0&&innerOff==0)return{line:lineNo,ch:0};var from=0,fromX=0,to=text.length,toX,estimated=Math.min(to,Math.ceil((x+innerOff*scroller.clientWidth*.9)/cw));for(;;){var estX=getX(estimated);if(!(estX<=x&&estimatedtoX)return{line:lineNo,ch:to};estimated=Math.floor(to*.8),estX=getX(estimated),estXx-fromX?from:to};var middle=Math.ceil((from+to)/2),middleX=getX(middle);middleX>x?(to=middle,toX=middleX):(from=middle,fromX=middleX)}}function pageCoords(pos){var local=localCoords(pos,!0),off=eltOffset(lineSpace);return{x:off.left+local.x,y:off.top+local.y,yBot:off.top+local.yBot}}function textHeight(){if(measureText==null){measureText="
";for(var i=0;i<49;++i)measureText+="x
";measureText+="x
"}var offsetHeight=lineDiv.clientHeight;return offsetHeight==cachedHeightFor?cachedHeight:(cachedHeightFor=offsetHeight,measure.innerHTML=measureText,cachedHeight=measure.firstChild.offsetHeight/50||1,measure.innerHTML="",cachedHeight)}function charWidth(){return scroller.clientWidth==cachedWidthFor?cachedWidth:(cachedWidthFor=scroller.clientWidth,cachedWidth=stringWidth("x"))}function paddingTop(){return lineSpace.offsetTop}function paddingLeft(){return lineSpace.offsetLeft}function posFromMouse(e,liberal){var offW=eltOffset(scroller,!0),x,y;try{x=e.clientX,y=e.clientY}catch(e){return null}if(!liberal&&(x-offW.left>scroller.clientWidth||y-offW.top>scroller.clientHeight))return null;var offL=eltOffset(lineSpace,!0);return coordsChar(x-offL.left,y-offL.top)}function onContextMenu(e){function rehide(){var newVal=splitLines(input.value).join("\n");newVal!=val&&!options.readOnly&&operation(replaceSelection)(newVal,"end"),inputDiv.style.position="relative",input.style.cssText=oldCSS,ie_lt9&&(scrollbar.scrollTop=scrollPos),leaveInputAlone=!1,resetInput(!0),slowPoll()}var pos=posFromMouse(e),scrollPos=scrollbar.scrollTop;if(!pos||opera)return;(posEq(sel.from,sel.to)||posLess(pos,sel.from)||!posLess(pos,sel.to))&&operation(setCursor)(pos.line,pos.ch);var oldCSS=input.style.cssText;inputDiv.style.position="absolute",input.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(e.clientY-5)+"px; left: "+(e.clientX-5)+"px; z-index: 1000; background: white; "+"border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",leaveInputAlone=!0;var val=input.value=getSelection();focusInput(),selectInput(input);if(gecko){e_stop(e);var mouseup=connect(window,"mouseup",function(){mouseup(),setTimeout(rehide,20)},!0)}else setTimeout(rehide,50)}function restartBlink(){clearInterval(blinker);var on=!0;cursor.style.visibility="",blinker=setInterval(function(){cursor.style.visibility=(on=!on)?"":"hidden"},650)}function matchBrackets(autoclear){function scan(line,from,to){if(!line.text)return;var st=line.styles,pos=forward?0:line.text.length-1,cur;for(var i=forward?0:st.length-2,e=forward?st.length:-2;i!=e;i+=2*d){var text=st[i];if(st[i+1]!=style){pos+=d*text.length;continue}for(var j=forward?0:text.length-1,te=forward?text.length:-1;j!=te;j+=d,pos+=d)if(pos>=from&&pos"==forward)stack.push(cur);else{if(stack.pop()!=match.charAt(0))return{pos:pos,match:!1};if(!stack.length)return{pos:pos,match:!0}}}}}var head=sel.inverted?sel.from:sel.to,line=getLine(head.line),pos=head.ch-1,match=pos>=0&&matching[line.text.charAt(pos)]||matching[line.text.charAt(++pos)];if(!match)return;var ch=match.charAt(0),forward=match.charAt(1)==">",d=forward?1:-1,st=line.styles;for(var off=pos+1,i=0,e=st.length;ilim;--search){if(search==0)return 0;var line=getLine(search-1);if(line.stateAfter)return search;var indented=line.indentation(options.tabSize);if(minline==null||minindent>indented)minline=search-1,minindent=indented}return minline}function getStateBefore(n){var start=findStartLine(n),state=start&&getLine(start-1).stateAfter;return state?state=copyState(mode,state):state=startState(mode),doc.iter(start,n,function(line){line.highlight(mode,state,options.tabSize),line.stateAfter=copyState(mode,state)}),start=doc.size)continue;var start=findStartLine(task),state=start&&getLine(start-1).stateAfter;state?state=copyState(mode,state):state=startState(mode);var unchanged=0,compare=mode.compareStates,realChange=!1,i=start,bail=!1;doc.iter(i,doc.size,function(line){var hadState=line.stateAfter;if(+(new Date)>end)return work.push(i),startWorker(options.workDelay),realChange&&changes.push({from:task,to:i+1}),bail=!0;var changed=line.highlight(mode,state,options.tabSize);changed&&(realChange=!0),line.stateAfter=copyState(mode,state);var done=null;if(compare){var same=hadState&&compare(hadState,state);same!=Pass&&(done=!!same)}done==null&&(changed!==!1||!hadState?unchanged=0:++unchanged>3&&(!mode.indent||mode.indent(hadState,"")==mode.indent(state,""))&&(done=!0));if(done)return!0;++i});if(bail)return;realChange&&changes.push({from:task,to:i+1})}foundWork&&options.onHighlightComplete&&options.onHighlightComplete(instance)}function startWorker(time){if(!work.length)return;highlight.set(time,operation(highlightWorker))}function startOperation(){updateInput=userSelChange=textChanged=null,changes=[],selectionChanged=!1,callbacks=[]}function endOperation(){updateMaxLine&&computeMaxLength();if(maxLineChanged&&!options.lineWrapping){var cursorWidth=widthForcer.offsetWidth,left=stringWidth(maxLine);widthForcer.style.left=left+"px",lineSpace.style.minWidth=left+cursorWidth+"px",maxLineChanged=!1}var newScrollPos,updated;if(selectionChanged){var coords=calculateCursorCoords();newScrollPos=calculateScrollPos(coords.x,coords.y,coords.x,coords.yBot)}changes.length?updated=updateDisplay(changes,!0,newScrollPos?newScrollPos.scrollTop:null):(selectionChanged&&updateSelection(),gutterDirty&&updateGutter()),newScrollPos&&scrollCursorIntoView(),selectionChanged&&(scrollEditorIntoView(),restartBlink()),focused&&!leaveInputAlone&&(updateInput===!0||updateInput!==!1&&selectionChanged)&&resetInput(userSelChange),selectionChanged&&options.matchBrackets&&setTimeout(operation(function(){bracketHighlighted&&(bracketHighlighted(),bracketHighlighted=null),posEq(sel.from,sel.to)&&matchBrackets(!1)}),20);var sc=selectionChanged,cbs=callbacks;textChanged&&options.onChange&&instance&&options.onChange(instance,textChanged),sc&&options.onCursorActivity&&options.onCursorActivity(instance);for(var i=0;ivspace&&pos.y>node.offsetHeight&&(top=pos.y-node.offsetHeight),left+node.offsetWidth>hspace&&(left=hspace-node.offsetWidth)}node.style.top=top+paddingTop()+"px",node.style.left=node.style.right="",horiz=="right"?(left=code.clientWidth-node.offsetWidth,node.style.right="0px"):(horiz=="left"?left=0:horiz=="middle"&&(left=(code.clientWidth-node.offsetWidth)/2),node.style.left=left+paddingLeft()+"px"),scroll&&scrollIntoView(left,top,left+node.offsetWidth,top+node.offsetHeight)},lineCount:function(){return doc.size},clipPos:clipPos,getCursor:function(start){return start==null&&(start=sel.inverted),copyPos(start?sel.from:sel.to)},somethingSelected:function(){return!posEq(sel.from,sel.to)},setCursor:operation(function(line,ch,user){ch==null&&typeof line.line=="number"?setCursor(line.line,line.ch,user):setCursor(line,ch,user)}),setSelection:operation(function(from,to,user){(user?setSelectionUser:setSelection)(clipPos(from),clipPos(to||from))}),getLine:function(line){if(isLine(line))return getLine(line).text},getLineHandle:function(line){if(isLine(line))return getLine(line)},setLine:operation(function(line,text){isLine(line)&&replaceRange(text,{line:line,ch:0},{line:line,ch:getLine(line).text.length})}),removeLine:operation(function(line){isLine(line)&&replaceRange("",{line:line,ch:0},clipPos({line:line+1,ch:0}))}),replaceRange:operation(replaceRange),getRange:function(from,to,lineSep){return getRange(clipPos(from),clipPos(to),lineSep)},triggerOnKeyDown:operation(onKeyDown),execCommand:function(cmd){return commands[cmd](instance)},moveH:operation(moveH),deleteH:operation(deleteH),moveV:operation(moveV),toggleOverwrite:function(){overwrite?(overwrite=!1,cursor.className=cursor.className.replace(" CodeMirror-overwrite","")):(overwrite=!0,cursor.className+=" CodeMirror-overwrite")},posFromIndex:function(off){var lineNo=0,ch;return doc.iter(0,doc.size,function(line){var sz=line.text.length+1;if(sz>off)return ch=off,!0;off-=sz,++lineNo}),clipPos({line:lineNo,ch:ch})},indexFromPos:function(coords){if(coords.line<0||coords.ch<0)return 0;var index=coords.ch;return doc.iter(0,coords.line,function(line){index+=line.text.length+1}),index},scrollTo:function(x,y){x!=null&&(scroller.scrollLeft=x),y!=null&&(scrollbar.scrollTop=y),updateDisplay([])},getScrollInfo:function(){return{x:scroller.scrollLeft,y:scrollbar.scrollTop,height:scrollbar.scrollHeight,width:scroller.scrollWidth}},setSize:function(width,height){function interpret(val){return val=String(val),/^\d+$/.test(val)?val+"px":val}width!=null&&(wrapper.style.width=interpret(width)),height!=null&&(scroller.style.height=interpret(height))},operation:function(f){return operation(f)()},compoundChange:function(f){return compoundChange(f)},refresh:function(){updateDisplay(!0,null,lastScrollTop),scrollbar.scrollHeight>lastScrollTop&&(scrollbar.scrollTop=lastScrollTop)},getInputField:function(){return input},getWrapperElement:function(){return wrapper},getScrollerElement:function(){return scroller},getGutterElement:function(){return gutter}},lastStoppedKey=null,maybeTransition,pollingFast=!1,prevInput="",goalColumn=null;TextMarker.prototype.clear=operation(function(){var min=Infinity,max=-Infinity;for(var i=0,e=this.set.length;i",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},nestedOperation=0;for(var ext in extensions)extensions.propertyIsEnumerable(ext)&&!instance.propertyIsEnumerable(ext)&&(instance[ext]=extensions[ext]);return instance}function getKeyMap(val){return typeof val=="string"?keyMap[val]:val}function lookupKey(name,extraMap,map,handle,stop){function lookup(map){map=getKeyMap(map);var found=map[name];if(found!=null&&handle(found))return!0;if(map.nofallthrough)return stop&&stop(),!0;var fallthrough=map.fallthrough;if(fallthrough==null)return!1;if(Object.prototype.toString.call(fallthrough)!="[object Array]")return lookup(fallthrough);for(var i=0,e=fallthrough.length;ifrom&&dest.push(part.slice(from-pos,Math.min(part.length,to-pos)),source[i+1]),end>=from&&(state=1)):state==1&&(end>to?dest.push(part.slice(0,to-pos),source[i+1]):dest.push(part,source[i+1])),pos=end}}function LeafChunk(lines){this.lines=lines,this.parent=null;for(var i=0,e=lines.length,height=0;i=0&&j>=0;--i,--j)if(from.charAt(i)!=to.charAt(j))break;return j+1}function indexOf(collection,elt){if(collection.indexOf)return collection.indexOf(elt);for(var i=0,e=collection.length;i2){mode.dependencies=[];for(var i=2;i0&&cur.ch=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)},next:function(){if(this.posstart},eatSpace:function(){var start=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>start},skipToEnd:function(){this.pos=this.string.length},skipTo:function(ch){var found=this.string.indexOf(ch,this.pos);if(found>-1)return this.pos=found,!0},backUp:function(n){this.pos-=n},column:function(){return countColumn(this.string,this.start,this.tabSize)},indentation:function(){return countColumn(this.string,null,this.tabSize)},match:function(pattern,consume,caseInsensitive){if(typeof pattern!="string"){var match=this.string.slice(this.pos).match(pattern);return match&&consume!==!1&&(this.pos+=match[0].length),match}function cased(str){return caseInsensitive?str.toLowerCase():str}if(cased(this.string).indexOf(cased(pattern),this.pos)==this.pos)return consume!==!1&&(this.pos+=pattern.length),!0},current:function(){return this.string.slice(this.start,this.pos)}},CodeMirror.StringStream=StringStream,MarkedText.prototype={attach:function(line){this.marker.set.push(line)},detach:function(line){var ix=indexOf(this.marker.set,line);ix>-1&&this.marker.set.splice(ix,1)},split:function(pos,lenBefore){if(this.to<=pos&&this.to!=null)return null;var from=this.fromthis.from&&(to=from&&(this.from=Math.max(to,this.from)+diff),toOpen&&(fromthis.from||this.from==null)?this.to=null:this.to!=null&&this.to>from&&(this.to=to=this.to},sameSet:function(x){return this.marker==x.marker}},Bookmark.prototype={attach:function(line){this.line=line},detach:function(line){this.line==line&&(this.line=null)},split:function(pos,lenBefore){if(posthis.to},clipTo:function(fromOpen,from,toOpen,to,diff){(fromOpen||fromthis.to)?(this.from=0,this.to=-1):this.from>from&&(this.from=this.to=Math.max(to,this.from)+diff)},sameSet:function(x){return!1},find:function(){return!this.line||!this.line.parent?null:{line:lineNo(this.line),ch:this.from}},clear:function(){if(this.line){var found=indexOf(this.line.marked,this);found!=-1&&this.line.marked.splice(found,1),this.line=null}}},Line.inheritMarks=function(text,orig){var ln=new Line(text),mk=orig&&orig.marked;if(mk)for(var i=0;i5e3){st[pos++]=this.text.slice(stream.pos),st[pos++]=null;break}}return st.length!=pos&&(st.length=pos,changed=!0),pos&&st[pos-2]!=prevWord&&(changed=!0),changed||(st.length<5&&this.text.length<10?null:!1)},getTokenAt:function(mode,state,ch){var txt=this.text,stream=new StringStream(txt);while(stream.pos',escaped,""):html.push(escaped)}function styleToClass(style){return style?"cm-"+style.replace(/ +/g," cm-"):null}var html=[],first=!0,col=0,span=span_;if(wrapAt!=null){var outPos=0,open='';span=function(text,style){var l=text.length;if(wrapAt>=outPos&&wrapAtoutPos&&(span_(text.slice(0,wrapAt-outPos),style),wrapWBR&&html.push("")),html.push(open);var cut=wrapAt-outPos;span_(opera?text.slice(cut,cut+1):text.slice(cut),style),html.push(""),opera&&span_(text.slice(cut+1),style),wrapAt--,outPos+=l}else outPos+=l,span_(text,style),outPos==wrapAt&&outPos==len?html.push(open+(gecko||ie&&!ie_lt8?"​":" ")+""):outPos>wrapAt+10&&/\s/.test(text)&&(span=function(){})}}var st=this.styles,allText=this.text,marked=this.marked,len=allText.length;if(!allText&&wrapAt==null)span(" ");else if(!marked||!marked.length)for(var i=0,ch=0;chlen&&(str=str.slice(0,len-ch)),ch+=l,span(str,styleToClass(style))}else{var pos=0,i=0,text="",style,sg=0,nextChange=marked[0].from||0,marks=[],markpos=0;function advanceMarks(){var m;while(markposupto?text.slice(0,upto-pos):text,appliedStyle);if(end>=upto){text=text.slice(upto-pos),pos=upto;break}pos=end}text=st[i++],style=styleToClass(st[i++])}}}return html.join("")},cleanUp:function(){this.parent=null;if(this.marked)for(var i=0,e=this.marked.length;i50){while(child.lines.length>50){var spilled=child.lines.splice(child.lines.length-25,25),newleaf=new LeafChunk(spilled);child.height-=newleaf.height,this.children.splice(i+1,0,newleaf),newleaf.parent=this}this.maybeSpill()}break}at-=sz}},maybeSpill:function(){if(this.children.length<=10)return;var me=this;do{var spilled=me.children.splice(me.children.length-5,5),sibling=new BranchChunk(spilled);if(!me.parent){var copy=new BranchChunk(me.children);copy.parent=me,me.children=[copy,sibling],me=copy}else{me.size-=sibling.size,me.height-=sibling.height;var myIndex=indexOf(me.parent.children,me);me.parent.children.splice(myIndex+1,0,sibling)}sibling.parent=me.parent}while(me.children.length>10);me.parent.maybeSpill()},iter:function(from,to,op){this.iterN(from,to-from,op)},iterN:function(at,n,op){for(var i=0,e=this.children.length;i400||!last||this.closed||last.start>start+old.length||last.start+last.added0;--i)last.old.unshift(old[i-1]);for(var i=endAfter;i>0;--i)last.old.push(old[old.length-i]);startBefore&&(last.start=start),last.added+=added-(old.length-startBefore-endAfter)}this.time=time},startCompound:function(){this.compound++||(this.closed=!0)},endCompound:function(){--this.compound||(this.closed=!0)}},CodeMirror.e_stop=e_stop,CodeMirror.e_preventDefault=e_preventDefault,CodeMirror.e_stopPropagation=e_stopPropagation,CodeMirror.connect=connect,Delayed.prototype={set:function(ms,f){clearTimeout(this.id),this.id=setTimeout(f,ms)}};var Pass=CodeMirror.Pass={toString:function(){return"CodeMirror.Pass"}},gecko=/gecko\/\d{7}/i.test(navigator.userAgent),ie=/MSIE \d/.test(navigator.userAgent),ie_lt8=/MSIE [1-7]\b/.test(navigator.userAgent),ie_lt9=/MSIE [1-8]\b/.test(navigator.userAgent),quirksMode=ie&&document.documentMode==5,webkit=/WebKit\//.test(navigator.userAgent),chrome=/Chrome\//.test(navigator.userAgent),opera=/Opera\//.test(navigator.userAgent),safari=/Apple Computer/.test(navigator.vendor),khtml=/KHTML\//.test(navigator.userAgent),mac_geLion=/Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent),dragAndDrop=function(){if(ie_lt9)return!1;var div=document.createElement("div");return"draggable"in div||"dragDrop"in div}(),lineSep=function(){var te=document.createElement("textarea");return te.value="foo\nbar",te.value.indexOf("\r")>-1?"\r\n":"\n"}(),spanAffectsWrapping=/^$/;gecko?spanAffectsWrapping=/$'/:safari?spanAffectsWrapping=/\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/:chrome&&(spanAffectsWrapping=/\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/);var escapeElement=document.createElement("pre");htmlEscape("a")=="\na"?htmlEscape=function(str){return escapeElement.textContent=str,escapeElement.innerHTML.slice(1)}:htmlEscape(" ")!=" "&&(htmlEscape=function(str){return escapeElement.innerHTML="",escapeElement.appendChild(document.createTextNode(str)),escapeElement.innerHTML}),CodeMirror.htmlEscape=htmlEscape;var splitLines="\n\nb".split(/\n/).length!=3?function(string){var pos=0,result=[],l=string.length;while(pos<=l){var nl=string.indexOf("\n",pos);nl==-1&&(nl=string.length);var line=string.slice(pos,string.charAt(nl-1)=="\r"?nl-1:nl),rt=line.indexOf("\r");rt!=-1?(result.push(line.slice(0,rt)),pos+=rt+1):(result.push(line),pos=nl+1)}return result}:function(string){return string.split(/\r\n?|\n/)};CodeMirror.splitLines=splitLines;var hasSelection=window.getSelection?function(te){try{return te.selectionStart!=te.selectionEnd}catch(e){return!1}}:function(te){try{var range=te.ownerDocument.selection.createRange()}catch(e){}return!range||range.parentElement()!=te?!1:range.compareEndPoints("StartToEnd",range)!=0};CodeMirror.defineMode("null",function(){return{token:function(stream){stream.skipToEnd()}}}),CodeMirror.defineMIME("text/plain","null");var keyNames={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",91:"Mod",92:"Mod",93:"Mod",109:"-",107:"=",127:"Delete",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63276:"PageUp",63277:"PageDown",63275:"End",63273:"Home",63234:"Left",63232:"Up",63235:"Right",63233:"Down",63302:"Insert",63272:"Delete"};return CodeMirror.keyNames=keyNames,function(){for(var i=0;i<10;i++)keyNames[i+48]=String(i);for(var i=65;i<=90;i++)keyNames[i]=String.fromCharCode(i);for(var i=1;i<=12;i++)keyNames[i+111]=keyNames[i+63235]="F"+i}(),CodeMirror}() \ No newline at end of file diff --git a/lib/client/editor/codemirror/pack/night.pack.css b/lib/client/editor/codemirror/pack/night.pack.css new file mode 100644 index 00000000..43cbf85a --- /dev/null +++ b/lib/client/editor/codemirror/pack/night.pack.css @@ -0,0 +1 @@ +.cm-s-night{background:#0a001f;color:#f8f8f8}.cm-s-night div.CodeMirror-selected{background:#447!important}.cm-s-night .CodeMirror-gutter{background:#0a001f;border-right:1px solid #aaa}.cm-s-night .CodeMirror-gutter-text{color:#f8f8f8}.cm-s-night .CodeMirror-cursor{border-left:1px solid white!important}.cm-s-night span.cm-comment{color:#6900a1}.cm-s-night span.cm-atom{color:#845dc4}.cm-s-night span.cm-number,.cm-s-night span.cm-attribute{color:#ffd500}.cm-s-night span.cm-keyword{color:#599eff}.cm-s-night span.cm-string{color:#37f14a}.cm-s-night span.cm-meta{color:#7678e2}.cm-s-night span.cm-variable-2,.cm-s-night span.cm-tag{color:#99b2ff}.cm-s-night span.cm-variable-3,.cm-s-night span.cm-def{color:#fff}.cm-s-night span.cm-error{color:#9d1e15}.cm-s-night span.cm-bracket{color:#8da6ce}.cm-s-night span.cm-comment{color:#6900a1}.cm-s-night span.cm-builtin,.cm-s-night span.cm-special{color:#ff9e59}.cm-s-night span.cm-link{color:#845dc4} \ No newline at end of file diff --git a/lib/client/editor/codemirror/pack/xml.pack.js b/lib/client/editor/codemirror/pack/xml.pack.js new file mode 100644 index 00000000..08e1ea97 --- /dev/null +++ b/lib/client/editor/codemirror/pack/xml.pack.js @@ -0,0 +1 @@ +CodeMirror.defineMode("xml",function(config,parserConfig){function inText(stream,state){function chain(parser){return state.tokenize=parser,parser(stream,state)}var ch=stream.next();if(ch=="<"){if(stream.eat("!"))return stream.eat("[")?stream.match("CDATA[")?chain(inBlock("atom","]]>")):null:stream.match("--")?chain(inBlock("comment","-->")):stream.match("DOCTYPE",!0,!0)?(stream.eatWhile(/[\w\._\-]/),chain(doctype(1))):null;if(stream.eat("?"))return stream.eatWhile(/[\w\._\-]/),state.tokenize=inBlock("meta","?>"),"meta";type=stream.eat("/")?"closeTag":"openTag",stream.eatSpace(),tagName="";var c;while(c=stream.eat(/[^\s\u00a0=<>\"\'\/?]/))tagName+=c;return state.tokenize=inTag,"tag"}if(ch=="&"){var ok;return stream.eat("#")?stream.eat("x")?ok=stream.eatWhile(/[a-fA-F\d]/)&&stream.eat(";"):ok=stream.eatWhile(/[\d]/)&&stream.eat(";"):ok=stream.eatWhile(/[\w\.\-:]/)&&stream.eat(";"),ok?"atom":"error"}return stream.eatWhile(/[^&<]/),null}function inTag(stream,state){var ch=stream.next();return ch==">"||ch=="/"&&stream.eat(">")?(state.tokenize=inText,type=ch==">"?"endTag":"selfcloseTag","tag"):ch=="="?(type="equals",null):/[\'\"]/.test(ch)?(state.tokenize=inAttribute(ch),state.tokenize(stream,state)):(stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/),"word")}function inAttribute(quote){return function(stream,state){while(!stream.eol())if(stream.next()==quote){state.tokenize=inTag;break}return"string"}}function inBlock(style,terminator){return function(stream,state){while(!stream.eol()){if(stream.match(terminator)){state.tokenize=inText;break}stream.next()}return style}}function doctype(depth){return function(stream,state){var ch;while((ch=stream.next())!=null){if(ch=="<")return state.tokenize=doctype(depth+1),state.tokenize(stream,state);if(ch==">"){if(depth==1){state.tokenize=inText;break}return state.tokenize=doctype(depth-1),state.tokenize(stream,state)}}return"meta"}}function pass(){for(var i=arguments.length-1;i>=0;i--)curState.cc.push(arguments[i])}function cont(){return pass.apply(null,arguments),!0}function pushContext(tagName,startOfLine){var noIndent=Kludges.doNotIndent.hasOwnProperty(tagName)||curState.context&&curState.context.noIndent;curState.context={prev:curState.context,tagName:tagName,indent:curState.indented,startOfLine:startOfLine,noIndent:noIndent}}function popContext(){curState.context&&(curState.context=curState.context.prev)}function element(type){if(type=="openTag")return curState.tagName=tagName,cont(attributes,endtag(curState.startOfLine));if(type=="closeTag"){var err=!1;return curState.context?curState.context.tagName!=tagName&&(Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())&&popContext(),err=!curState.context||curState.context.tagName!=tagName):err=!0,err&&(setStyle="error"),cont(endclosetag(err))}return cont()}function endtag(startOfLine){return function(type){return type=="selfcloseTag"||type=="endTag"&&Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())?(maybePopContext(curState.tagName.toLowerCase()),cont()):type=="endTag"?(maybePopContext(curState.tagName.toLowerCase()),pushContext(curState.tagName,startOfLine),cont()):cont()}}function endclosetag(err){return function(type){return err&&(setStyle="error"),type=="endTag"?(popContext(),cont()):(setStyle="error",cont(arguments.callee))}}function maybePopContext(nextTagName){var parentTagName;for(;;){if(!curState.context)return;parentTagName=curState.context.tagName.toLowerCase();if(!Kludges.contextGrabbers.hasOwnProperty(parentTagName)||!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName))return;popContext()}}function attributes(type){return type=="word"?(setStyle="attribute",cont(attribute,attributes)):type=="endTag"||type=="selfcloseTag"?pass():(setStyle="error",cont(attributes))}function attribute(type){return type=="equals"?cont(attvalue,attributes):(Kludges.allowMissing||(setStyle="error"),type=="endTag"||type=="selfcloseTag"?pass():cont())}function attvalue(type){return type=="string"?cont(attvaluemaybe):type=="word"&&Kludges.allowUnquoted?(setStyle="string",cont()):(setStyle="error",type=="endTag"||type=="selfCloseTag"?pass():cont())}function attvaluemaybe(type){return type=="string"?cont(attvaluemaybe):pass()}var indentUnit=config.indentUnit,Kludges=parserConfig.htmlMode?{autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!1}:{autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1},alignCDATA=parserConfig.alignCDATA,tagName,type,curState,setStyle;return{startState:function(){return{tokenize:inText,cc:[],indented:0,startOfLine:!0,tagName:null,context:null}},token:function(stream,state){stream.sol()&&(state.startOfLine=!0,state.indented=stream.indentation());if(stream.eatSpace())return null;setStyle=type=tagName=null;var style=state.tokenize(stream,state);state.type=type;if((style||type)&&style!="comment"){curState=state;for(;;){var comb=state.cc.pop()||element;if(comb(type||style))break}}return state.startOfLine=!1,setStyle||style},indent:function(state,textAfter,fullLine){var context=state.context;if(state.tokenize!=inTag&&state.tokenize!=inText||context&&context.noIndent)return fullLine?fullLine.match(/^(\s*)/)[0].length:0;if(alignCDATA&&/ Date: Fri, 27 Jul 2012 10:09:40 -0400 Subject: [PATCH 007/170] minor changes --- lib/client/viewer.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 3d03b0c1..b58bb694 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -3,9 +3,11 @@ var CloudCommander, CloudFunc, $; * https://github.com/fancyapps/fancyBox */ CloudCommander.Viewer = { - dir : CloudCommander.LIBDIRCLIENT + 'viewer/', + LIBDIR : './lib', + LIBDIRSERVER : './lib/server', + dir : this.LIBDIRCLIENT + 'viewer/', - getByClass : function(pClass){ + getByClass : function(pClass){ return document.getElementsByClassName(pClass); } }; From 273e8c2c57807cec3930c5d41f2f38fb9093b46c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:10:40 -0400 Subject: [PATCH 008/170] minor changes --- lib/client/viewer.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index b58bb694..67cb6faa 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -2,10 +2,8 @@ var CloudCommander, CloudFunc, $; /* object contains viewer FancyBox * https://github.com/fancyapps/fancyBox */ -CloudCommander.Viewer = { - LIBDIR : './lib', - LIBDIRSERVER : './lib/server', - dir : this.LIBDIRCLIENT + 'viewer/', +CloudCommander.Viewer = { + dir : './lib/viewer/', getByClass : function(pClass){ return document.getElementsByClassName(pClass); From 325163a41fc84e204a92f4226a69f808f5d5d1e5 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:13:20 -0400 Subject: [PATCH 009/170] minor changes --- lib/client/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 67cb6faa..72558d94 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -3,7 +3,7 @@ var CloudCommander, CloudFunc, $; * https://github.com/fancyapps/fancyBox */ CloudCommander.Viewer = { - dir : './lib/viewer/', + dir : './lib/client/viewer/', getByClass : function(pClass){ return document.getElementsByClassName(pClass); From 27ac265a405c5c9279b57b8070df7ec34eef0763 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:23:17 -0400 Subject: [PATCH 010/170] now fancybox loads when f3 key pressed --- client.js | 3 +-- lib/client/keyBinding.js | 6 ++++++ lib/client/viewer.js | 36 ++++++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/client.js b/client.js index 4cf02c70..cb4dc831 100644 --- a/client.js +++ b/client.js @@ -822,8 +822,7 @@ try{ CloudCommander.init(); /* привязываем клавиши к функциям */ CloudCommander.keyBinding(); - CloudCommander.Editor(); - CloudCommander.Viewer(); + CloudCommander.Editor(); }; } catch(err){} \ No newline at end of file diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 3a8397fe..c465d1c9 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -19,6 +19,12 @@ CloudCommander.keyBinding=(function(){ lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; }catch(error){console.log(error);} } + /* if f3 pressed */ + else if(event.keyCode===114){ + if (typeof CloudCommander.Viewer === 'function'){ + CloudCommander.Viewer(); + } + } /* навигация по таблице файлов*/ /* если нажали клавишу вверх*/ else if(event.keyCode===38){ diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 72558d94..cc967908 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -89,6 +89,22 @@ CloudCommander.Viewer.FancyBox = { console.log(pError); } }, + + show : (function(pParent){ + CloudCommander.Viewer.FancyBox.set(); + var lCurrent = pParent.getByClass('current-file'); + lCurrent.length && + (lCurrent = lCurrent[0]); + + var lA = lCurrent.getElementsByClassName('fancybox'); + + var lConfig = pParent.FancyBox.getConfig(); + + lA.length && + $.fancybox.open({ href : lA[0].href }, + lConfig); + }), + getById : function(pId){return document.getElementById(pId);}, getByClass : function(pClass){ @@ -104,21 +120,10 @@ CloudCommander.Viewer.Keys = (function(){ /* если клавиши можно обрабатывать */ if(CloudCommander.keyBinded){ /* if f3 pressed */ - if(event.keyCode===114){ - CloudCommander.Viewer.FancyBox.set(); - var lCurrent = pParent.getByClass('current-file'); - lCurrent.length && - (lCurrent = lCurrent[0]); - - var lA = lCurrent.getElementsByClassName('fancybox'); - - var lConfig = pParent.FancyBox.getConfig(); - - lA.length && - $.fancybox.open({ href : lA[0].href }, - lConfig); + if(event.keyCode===114){ + CloudCommander.Viewer.FancyBox.show(); - event.preventDefault(); + event.preventDefault(pParent); } } }; @@ -130,6 +135,9 @@ CloudCommander.Viewer.Keys = (function(){ else document.onkeypress=key_event; + + /* showing image previewer */ + CloudCommander.Viewer.FancyBox.show(); }); CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f(this)); From 0dec9cc2ac1d7242ed5582e2b741901368e65cfe Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:37:55 -0400 Subject: [PATCH 011/170] now fancybox loads when f3 key pressed --- lib/client/keyBinding.js | 2 ++ lib/client/viewer.js | 51 ++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index c465d1c9..1282ea07 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -23,6 +23,8 @@ CloudCommander.keyBinding=(function(){ else if(event.keyCode===114){ if (typeof CloudCommander.Viewer === 'function'){ CloudCommander.Viewer(); + + event.preventDefault(); } } /* навигация по таблице файлов*/ diff --git a/lib/client/viewer.js b/lib/client/viewer.js index cc967908..752ad63d 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -92,17 +92,18 @@ CloudCommander.Viewer.FancyBox = { show : (function(pParent){ CloudCommander.Viewer.FancyBox.set(); - var lCurrent = pParent.getByClass('current-file'); - lCurrent.length && - (lCurrent = lCurrent[0]); - - var lA = lCurrent.getElementsByClassName('fancybox'); - - var lConfig = pParent.FancyBox.getConfig(); - - lA.length && - $.fancybox.open({ href : lA[0].href }, - lConfig); + + var lCurrent = this.getByClass('current-file'); + lCurrent.length && + (lCurrent = lCurrent[0]); + + var lA = lCurrent.getElementsByClassName('fancybox'); + + var lConfig = this.getConfig(); + + lA.length && + $.fancybox.open({ href : lA[0].href }, + lConfig); }), getById : function(pId){return document.getElementById(pId);}, @@ -114,31 +115,29 @@ CloudCommander.Viewer.FancyBox = { CloudCommander.Viewer.Keys = (function(){ "use strict"; - var lCallBack_f = (function(pParent){ - var key_event = function(){ - return function(event){ - /* если клавиши можно обрабатывать */ - if(CloudCommander.keyBinded){ - /* if f3 pressed */ - if(event.keyCode===114){ - CloudCommander.Viewer.FancyBox.show(); - - event.preventDefault(pParent); - } + var lCallBack_f = (function(){ + var key_event = function(event){ + /* если клавиши можно обрабатывать */ + if(CloudCommander.keyBinded){ + /* if f3 pressed */ + if(event.keyCode===114){ + CloudCommander.Viewer.FancyBox.show(); + + event.preventDefault(); } - }; + } }; /* добавляем обработчик клавишь */ if (document.addEventListener) - document.addEventListener('keydown', key_event(pParent),false); + document.addEventListener('keydown', key_event(),false); else document.onkeypress=key_event; - /* showing image previewer */ + /* showing images preview*/ CloudCommander.Viewer.FancyBox.show(); }); - CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f(this)); + CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f()); }); \ No newline at end of file From 51a4b7e35566d9e1ad9268aa3313e21d4b1ed0a9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:40:42 -0400 Subject: [PATCH 012/170] now fancybox loads when f3 key pressed --- lib/client/viewer.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 752ad63d..2eb1de96 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -116,17 +116,19 @@ CloudCommander.Viewer.Keys = (function(){ "use strict"; var lCallBack_f = (function(){ - var key_event = function(event){ - /* если клавиши можно обрабатывать */ - if(CloudCommander.keyBinded){ - /* if f3 pressed */ - if(event.keyCode===114){ - CloudCommander.Viewer.FancyBox.show(); - - event.preventDefault(); + var key_event = (function(){ + return function(event){ + /* если клавиши можно обрабатывать */ + if(CloudCommander.keyBinded){ + /* if f3 pressed */ + if(event.keyCode===114){ + CloudCommander.Viewer.FancyBox.show(); + + event.preventDefault(); + } } - } - }; + }; + }); /* добавляем обработчик клавишь */ if (document.addEventListener) From 0bf067664175bf8c167289e4d0e28a38d754460b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Fri, 27 Jul 2012 10:43:55 -0400 Subject: [PATCH 013/170] minor changes --- lib/client/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/viewer.js b/lib/client/viewer.js index 2eb1de96..8533ade1 100644 --- a/lib/client/viewer.js +++ b/lib/client/viewer.js @@ -141,5 +141,5 @@ CloudCommander.Viewer.Keys = (function(){ CloudCommander.Viewer.FancyBox.show(); }); - CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f()); + CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f); }); \ No newline at end of file From 2d3612150720a3431151c3236d91d921484f9449 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 03:00:54 -0400 Subject: [PATCH 014/170] moved event.preventDefault() to end of if-codition --- lib/client/keyBinding.js | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 1282ea07..d596fa14 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -22,9 +22,7 @@ CloudCommander.keyBinding=(function(){ /* if f3 pressed */ else if(event.keyCode===114){ if (typeof CloudCommander.Viewer === 'function'){ - CloudCommander.Viewer(); - - event.preventDefault(); + CloudCommander.Viewer(); } } /* навигация по таблице файлов*/ @@ -54,9 +52,7 @@ CloudCommander.keyBinding=(function(){ lTop % (CloudCommander.HEIGHT - CloudCommander.HEIGHT/10) < 70 && - lCurrentFile.parentElement.scrollByLines(-2); - - event.preventDefault(); + lCurrentFile.parentElement.scrollByLines(-2); } } /* если нажали клавишу в низ*/ @@ -84,9 +80,7 @@ CloudCommander.keyBinding=(function(){ lMod < 70 && lMod > 50 && console.log(lCurrentFile .parentElement - .scrollByLines(2) || '!'); - - event.preventDefault(); + .scrollByLines(2) || '!'); } } /* если нажали клавишу page up или Home @@ -194,9 +188,7 @@ CloudCommander.keyBinding=(function(){ break; } } - } - - event.preventDefault();//запрет на дальнейшее действие + } } } /* если нажали +d чистим кэш */ @@ -207,9 +199,7 @@ CloudCommander.keyBinding=(function(){ console.log('press +q to remove all key-handlers'); var lClearCache=document.getElementById('clear-cache'); - if(lClearCache && lClearCache.onclick)lClearCache.onclick(); - - event.preventDefault();//запрет на дальнейшее действие + if(lClearCache && lClearCache.onclick)lClearCache.onclick(); } /* если нажали +q * убираем все обработчики @@ -243,9 +233,11 @@ CloudCommander.keyBinding=(function(){ console.log('+r reload key-handerl - set'); console.log('+s clear cache key-handler - set'); console.log('press +q to remove them'); - } - - return false; + } + + event.preventDefault();//запрет на дальнейшее действие + + return false; }; /* добавляем обработчик клавишь */ if(document.addEventListener) From 804dd90dc6c84ffb2738cb5fcb23a797de3e0c91 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 03:07:36 -0400 Subject: [PATCH 015/170] added short functions getByClass and getById --- lib/client/keyBinding.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index d596fa14..0e25dd0d 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -1,7 +1,16 @@ var CloudCommander; var CloudFunc; -CloudCommander.keyBinding=(function(){ +CloudCommander.keyBinding=(function(){ "use strict"; + + var getByClass = function(pClass){ + return document.getElementsByClassName(pClass); + }; + + var getById = function(pId){ + return document.getElementById(pId); + }; + var key_event=function(event){ var lCurrentFile; var lName, lTop; @@ -16,7 +25,7 @@ CloudCommander.keyBinding=(function(){ if(event.keyCode===9){ console.log('Tab pressed'); try{ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE)[0]; }catch(error){console.log(error);} } /* if f3 pressed */ @@ -29,7 +38,7 @@ CloudCommander.keyBinding=(function(){ /* если нажали клавишу вверх*/ else if(event.keyCode===38){ /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE); /* если ненайдены выделенные файлы - выходим*/ if(lCurrentFile.length===0)return; lCurrentFile=lCurrentFile[0]; @@ -58,7 +67,7 @@ CloudCommander.keyBinding=(function(){ /* если нажали клавишу в низ*/ else if(event.keyCode===40){ /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE); /* если ненайдены выделенные файлы - выходим*/ if(lCurrentFile.length===0)return; lCurrentFile=lCurrentFile[0]; @@ -88,7 +97,7 @@ CloudCommander.keyBinding=(function(){ * элементу */ else if(/*event.keyCode===33 ||*/ event.keyCode===36){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE)[0]; /* убираем выделение с текущего файла*/ lCurrentFile.className=''; /* получаем первый элемент*/ @@ -102,7 +111,7 @@ CloudCommander.keyBinding=(function(){ * выделяем последний элемент */ else if(/*event.keyCode===34 ||*/ event.keyCode===35){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE)[0]; /* снимаем выделение с текущего файла*/ lCurrentFile.className=''; /* выделяем самый нижний файл */ @@ -110,7 +119,7 @@ CloudCommander.keyBinding=(function(){ } /* если нажали Enter - открываем папку*/ else if(event.keyCode===13){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE); /* если ненайдены выделенные файлы - выходим*/ if(!lCurrentFile.length)return; lCurrentFile=lCurrentFile[0]; @@ -152,11 +161,11 @@ CloudCommander.keyBinding=(function(){ /* Программно нажимаем на кнопку перезагрузки * содержимого каталога */ - var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); + var lRefreshIcon=getByClass(CloudFunc.REFRESHICON); if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; if(lRefreshIcon){ /* находим файл который сейчас выделен */ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + lCurrentFile=getByClass(CloudCommander.CURRENT_FILE); if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; /* получаем название файла*/ var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].textContent; @@ -171,7 +180,7 @@ CloudCommander.keyBinding=(function(){ /* перебираем файлы левой панели * в поисках подсвеченого файла */ - var lLeft=document.getElementById('left'); + var lLeft=getById('left'); if(lLeft){ /* перебираем все файлы в панели */ var lLi=lLeft.getElementsByTagName('li'); @@ -198,7 +207,7 @@ CloudCommander.keyBinding=(function(){ console.log('clearing cache...'); console.log('press +q to remove all key-handlers'); - var lClearCache=document.getElementById('clear-cache'); + var lClearCache=getById('clear-cache'); if(lClearCache && lClearCache.onclick)lClearCache.onclick(); } /* если нажали +q From 9dc2c318895219338f496ffaec34afbd3254cf63 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 03:15:19 -0400 Subject: [PATCH 016/170] added tab support --- lib/client/keyBinding.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 0e25dd0d..1ff103b1 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -24,9 +24,22 @@ CloudCommander.keyBinding=(function(){ */ if(event.keyCode===9){ console.log('Tab pressed'); + + var lCURRENT_FILE = CloudCommander.CURRENT_FILE; try{ - lCurrentFile=getByClass(CloudCommander.CURRENT_FILE)[0]; - }catch(error){console.log(error);} + lCurrentFile = getByClass(lCURRENT_FILE)[0]; + + /* changing parent panel of curent-file */ + var lId = lCurrentFile.parentElement.id; + if(lId === 'right')lId = 'left'; + else lId = 'right'; + + lCurrentFile.className = ''; + + getById(lId).getByTagName('li')[2] + .className = lCURRENT_FILE; + + }catch(error){console.log(error);} } /* if f3 pressed */ else if(event.keyCode===114){ From a9d5041756f4cedfbbf76391ee11d58bc01428d3 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:23:33 +0300 Subject: [PATCH 017/170] Update lib/client/keyBinding.js --- lib/client/keyBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 1ff103b1..0e359478 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -36,7 +36,7 @@ CloudCommander.keyBinding=(function(){ lCurrentFile.className = ''; - getById(lId).getByTagName('li')[2] + getById(lId).getElementsByTagName('li')[2] .className = lCURRENT_FILE; }catch(error){console.log(error);} From 4d8348e663ef148e364bb1a13098067d9b81a7c4 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:38:28 +0300 Subject: [PATCH 018/170] added tab positioning --- lib/client/keyBinding.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 0e359478..6d1b5b83 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -11,6 +11,11 @@ CloudCommander.keyBinding=(function(){ return document.getElementById(pId); }; + var lTabPanel = { + left : {}, + right : {} + + }; var key_event=function(event){ var lCurrentFile; var lName, lTop; @@ -31,14 +36,20 @@ CloudCommander.keyBinding=(function(){ /* changing parent panel of curent-file */ var lId = lCurrentFile.parentElement.id; - if(lId === 'right')lId = 'left'; - else lId = 'right'; - lCurrentFile.className = ''; + lTabPanel[lId] = lCurrentFile; + if (lTabPanel[lId]) + lTabPanel[lId].className = lCurrentFile; + else + getById(lId).getElementsByTagName('li')[2] + .className = lCURRENT_FILE; - getById(lId).getElementsByTagName('li')[2] - .className = lCURRENT_FILE; + lId === 'right' && + (lId = 'left') || + (lId = 'right'); + lCurrentFile.className = ''; + }catch(error){console.log(error);} } /* if f3 pressed */ From 8d60348975751df7f0fa694db5150153f8bd2a9b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:42:01 +0300 Subject: [PATCH 019/170] Update lib/client/keyBinding.js --- lib/client/keyBinding.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 6d1b5b83..edfd0e7d 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -38,16 +38,17 @@ CloudCommander.keyBinding=(function(){ var lId = lCurrentFile.parentElement.id; lTabPanel[lId] = lCurrentFile; - if (lTabPanel[lId]) - lTabPanel[lId].className = lCurrentFile; - else - getById(lId).getElementsByTagName('li')[2] - .className = lCURRENT_FILE; - + lId === 'right' && (lId = 'left') || (lId = 'right'); + + lTabPanel[lId] && + (lTabPanel[lId].className = lCurrentFile) || + (getById(lId).getElementsByTagName('li')[2] + .className = lCURRENT_FILE); + lCurrentFile.className = ''; }catch(error){console.log(error);} From 9e0e1b20d28e6306e45ee1e49ebf1b4b6d572ee5 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:45:05 +0300 Subject: [PATCH 020/170] Update lib/client/keyBinding.js --- lib/client/keyBinding.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index edfd0e7d..871b93d7 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -39,15 +39,15 @@ CloudCommander.keyBinding=(function(){ lTabPanel[lId] = lCurrentFile; - lId === 'right' && - (lId = 'left') || - (lId = 'right'); + lId = (lId === 'right')? + 'left':'right'; + if(lTabPanel[lId]) + lTabPanel[lId].className = lCurrentFile; - lTabPanel[lId] && - (lTabPanel[lId].className = lCurrentFile) || - (getById(lId).getElementsByTagName('li')[2] - .className = lCURRENT_FILE); + else + getById(lId).getElementsByTagName('li')[2] + .className = lCURRENT_FILE; lCurrentFile.className = ''; From 29a71503af00ae1f096bad50bfcea76e98bd8ca6 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 03:46:24 -0400 Subject: [PATCH 021/170] minor changes --- lib/client/keyBinding.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 1ff103b1..894d25e9 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -11,6 +11,11 @@ CloudCommander.keyBinding=(function(){ return document.getElementById(pId); }; + var lTabPanel = { + left : 0, + right : 0 + + }; var key_event=function(event){ var lCurrentFile; var lName, lTop; @@ -31,14 +36,21 @@ CloudCommander.keyBinding=(function(){ /* changing parent panel of curent-file */ var lId = lCurrentFile.parentElement.id; - if(lId === 'right')lId = 'left'; - else lId = 'right'; - lCurrentFile.className = ''; + lTabPanel[lId] = lCurrentFile; + + lId = (lId === 'right')? + 'left':'right'; - getById(lId).getByTagName('li')[2] - .className = lCURRENT_FILE; + if(lTabPanel[lId]) + lTabPanel[lId].className = lCurrentFile; + else + getById(lId).getElementsByTagName('li')[2] + .className = lCURRENT_FILE; + + lCurrentFile.className = ''; + }catch(error){console.log(error);} } /* if f3 pressed */ From 0e1b8cde9153bf2419a9df603b9f3a53eceac049 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:47:07 +0300 Subject: [PATCH 022/170] Update lib/client/keyBinding.js --- lib/client/keyBinding.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 871b93d7..894d25e9 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -12,8 +12,8 @@ CloudCommander.keyBinding=(function(){ }; var lTabPanel = { - left : {}, - right : {} + left : 0, + right : 0 }; var key_event=function(event){ From 90ae7a2b0f7cc6e448e782e386bd9a1a095c0aaf Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 03:50:25 -0400 Subject: [PATCH 023/170] minor changes --- lib/client/keyBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 894d25e9..dd11dfb9 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -43,7 +43,7 @@ CloudCommander.keyBinding=(function(){ 'left':'right'; if(lTabPanel[lId]) - lTabPanel[lId].className = lCurrentFile; + lTabPanel[lId].className = lCURRENT_FILE; else getById(lId).getElementsByTagName('li')[2] From 0e6a9ab2f4e6b9f4e6061001b68ca2c141d256dd Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:09:57 -0400 Subject: [PATCH 024/170] added tab support --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 36a88245..22d8465e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012.07.*, Version 0.1.5 + +* Added tab support. + + 2012.07.27, Version 0.1.4 * Added local version of Droids font for offline mode From fbffbdae548cc67d1ccac26f11f826b46445a5cb Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:16:10 -0400 Subject: [PATCH 025/170] added short functions getByClass and getById --- client.js | 59 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/client.js b/client.js index cb4dc831..cfbb708f 100644 --- a/client.js +++ b/client.js @@ -49,6 +49,15 @@ var CloudClient={ HEIGHT :0 }; +/* short names used all the time functions */ +var getByClass = function(pClass){ + return getByClass(pClass); +}; + +var getById = function(pId){ + return document.getElementById(pId); +}; + /* * Обьект для работы с кэшем * в него будут включены функции для @@ -190,7 +199,7 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ catch(error){console.log(error);} } - var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lCurrentFile=getByClass(CloudClient.CURRENT_FILE); /* получаем имя каталога в котором находимся*/ var lHref; try{ @@ -239,7 +248,7 @@ CloudClient._setCurrent=(function(){ * вызоветься _loadDir */ return function(pFromEnter){ - var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lCurrentFile=getByClass(CloudClient.CURRENT_FILE); if(lCurrentFile && lCurrentFile.length > 0){ /* если мы находимся не на * пути и не на заголовках @@ -277,13 +286,13 @@ CloudClient._currentToParent = (function(pDirName){ /* опредиляем в какой мы панели: * правой или левой */ - var lCurrentFile = document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lCurrentFile = getByClass(CloudClient.CURRENT_FILE); var lPanel = lCurrentFile[0].parentElement; /* убираем слэш с имени каталога*/ pDirName=pDirName.replace('/',''); - var lRootDir = document.getElementById(pDirName + '(' + lPanel.id + ')'); + var lRootDir = getById(pDirName + '(' + lPanel.id + ')'); /* if found li element with ID directory name * set it to current file @@ -354,7 +363,7 @@ CloudClient.init=(function() LoadingImage=CloudClient._images.loading(); /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ try{ - document.getElementsByClassName('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); + getByClass('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); LoadingImage.className+=' hidden'; /* прячем её */ }catch(error){console.log(error);} ErrorImage=CloudClient._images.error(); @@ -364,16 +373,17 @@ CloudClient.init=(function() */ /* выделяем строку с первым файлом */ - var lFmHeader=document.getElementsByClassName('fm_header'); + var lFmHeader=getByClass('fm_header'); if(lFmHeader && lFmHeader[0].nextSibling) lFmHeader[0].nextSibling.className=CloudClient.CURRENT_FILE; /* показываем элементы, которые будут работать только, если есть js */ - var lFM=document.getElementById('fm'); - if(lFM)lFM.className='localstorage'; + var lFM = getById('fm'); + if(lFM) + lFM.className='localstorage'; /* если есть js - показываем правую панель*/ - var lRight=document.getElementById('right'); + var lRight=getById('right'); if(lRight)lRight.className=lRight.className.replace('hidden',''); /* формируем и округляем высоту экрана @@ -381,7 +391,10 @@ CloudClient.init=(function() * 658 -> 700 */ - var lHeight=window.screen.height - (window.screen.height/3).toFixed(); + var lHeight = + window.screen.height - + (window.screen.height/3).toFixed(); + lHeight=(lHeight/100).toFixed()*100; CloudClient.HEIGHT = lHeight; @@ -397,11 +410,11 @@ CloudClient.init=(function() CloudClient._changeLinks = function(pPanelID) { /* назначаем кнопку очистить кэш и показываем её*/ - var lClearcache=document.getElementById('clear-cache'); + var lClearcache=getById('clear-cache'); if(lClearcache)lClearcache.onclick=CloudClient.Cache.clear; /* меняем ссылки на ajax-запросы */ - var lPanel=document.getElementById(pPanelID); + var lPanel=getById(pPanelID); var a=lPanel.getElementsByTagName('a'); /* Если нажмут на кнопку перезагрузить страниц - её нужно будет обязательно @@ -482,7 +495,7 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) */ var lPanel; try{ - lPanel=document.getElementsByClassName(CloudClient.CURRENT_FILE)[0].parentElement.id; + lPanel=getByClass(CloudClient.CURRENT_FILE)[0].parentElement.id; }catch(error){console.log("Current file not found\n"+error);} if(pNeedRefresh===undefined && lPanel){ @@ -508,13 +521,11 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) url: path, error: function(jqXHR, textStatus, errorThrown){ console.log(textStatus+' : '+errorThrown); - var lLoading=document.getElementById('loading-image'); + var lLoading=getById('loading-image'); ErrorImage.className='icon error'; ErrorImage.title=errorThrown; lLoading.parentElement.appendChild(ErrorImage); - lLoading.className='hidden'; - //document.getElementsByClassName('path')[0].appendChild(ErrorImage); - + lLoading.className='hidden'; }, success:function(data, textStatus, jqXHR){ /* если такой папки (или файла) нет @@ -538,7 +549,7 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) } else ErrorImage.title = jqXHR.responseText; ErrorImage.className ='icon error'; - lLoading = document.getElementById('loading-image'); + lLoading = getById('loading-image'); lLoading.parentElement.appendChild(ErrorImage); lLoading.className = 'hidden'; @@ -573,7 +584,7 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) */ CloudClient._createFileTable = function(pElem,pJSON) { - var lElem=document.getElementById(pElem); + var lElem=getById(pElem); /* говорим построителю, * что бы он в нужный момент * выделил строку с первым файлом @@ -627,7 +638,7 @@ CloudClient._anyload = function(pParams_o) if(!lID){ lID = this._getIdBySrc(lSrc); } - var element = document.getElementById(lID); + var element = getById(lID); /* если скрипт еще не загружен */ if(!element) { @@ -734,8 +745,8 @@ CloudClient.cssLoad = function(pParams_o){ */ CloudClient._getJSONfromFileTable=function() { - var lLeft=document.getElementById('left'); - var lPath=document.getElementsByClassName('path')[0].textContent; + var lLeft=getById('left'); + var lPath=getByClass('path')[0].textContent; var lFileTable=[{path:lPath,size:'dir'}]; var lLI=lLeft.getElementsByTagName('li'); @@ -797,14 +808,14 @@ CloudClient._getJSONfromFileTable=function() CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',{ onload: function(){ /* сохраняем переменную jQuery себе в область видимости */ - document.getElementsByClassName=function(pClassName){ + document.getElementsByClassName = function(pClassName){ return window.jQuery('.'+pClassName)[0]; }; }, onerror: function(){ CloudClient.jsload(CloudClient.LIBDIRCLIENT + 'jquery.js', function(){ - document.getElementsByClassName=function(pClassName){ + getByClass=function(pClassName){ return window.jQuery('.'+pClassName)[0]; }; }); From b419f1d61e5cb6bfda4b4ff78985011fe895a859 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:19:02 -0400 Subject: [PATCH 026/170] fixed bug: Maximum call stack size exceeded --- client.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client.js b/client.js index cfbb708f..93429c89 100644 --- a/client.js +++ b/client.js @@ -363,8 +363,11 @@ CloudClient.init=(function() LoadingImage=CloudClient._images.loading(); /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ try{ - getByClass('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); - LoadingImage.className+=' hidden'; /* прячем её */ + var lPath = getByClass('path')[0] + lPath.getElementsByTagName('a')[0] + .appendChild(LoadingImage); + + LoadingImage.className += ' hidden'; /* прячем её */ }catch(error){console.log(error);} ErrorImage=CloudClient._images.error(); From 519cbe88f3fabd3364cb6b480b55a3b30ca1ce4f Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:20:06 -0400 Subject: [PATCH 027/170] minor changes --- client.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client.js b/client.js index 93429c89..aa111170 100644 --- a/client.js +++ b/client.js @@ -362,13 +362,12 @@ CloudClient.init=(function() LoadingImage=CloudClient._images.loading(); /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ - try{ - var lPath = getByClass('path')[0] - lPath.getElementsByTagName('a')[0] - .appendChild(LoadingImage); - - LoadingImage.className += ' hidden'; /* прячем её */ - }catch(error){console.log(error);} + var lPath = getByClass('path')[0]; + lPath.getElementsByTagName('a')[0] + .appendChild(LoadingImage); + + LoadingImage.className += ' hidden'; /* прячем её */ + ErrorImage=CloudClient._images.error(); /* устанавливаем размер высоты таблицы файлов From 4a41880c7dda821f7b1d0df18aec260738cab8f0 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:21:33 -0400 Subject: [PATCH 028/170] minor changes --- client.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client.js b/client.js index aa111170..d973d6e0 100644 --- a/client.js +++ b/client.js @@ -362,12 +362,13 @@ CloudClient.init=(function() LoadingImage=CloudClient._images.loading(); /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ - var lPath = getByClass('path')[0]; - lPath.getElementsByTagName('a')[0] - .appendChild(LoadingImage); - - LoadingImage.className += ' hidden'; /* прячем её */ - + try{ + getByClass('path')[0] + .getElementsByTagName('a')[0] + .appendChild(LoadingImage); + + LoadingImage.className+=' hidden'; /* прячем её */ + }catch(error){console.log(error);} ErrorImage=CloudClient._images.error(); /* устанавливаем размер высоты таблицы файлов From a0eaeadbbe27f0ab4e6c05442487dd607c5d6ff7 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:21:56 -0400 Subject: [PATCH 029/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index d973d6e0..8bdcbfbc 100644 --- a/client.js +++ b/client.js @@ -51,7 +51,7 @@ var CloudClient={ /* short names used all the time functions */ var getByClass = function(pClass){ - return getByClass(pClass); + return document.getElementsByClassName(pClass); }; var getById = function(pId){ From 47d835547a21564aee1e5cde445254a431ac1374 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:49:15 -0400 Subject: [PATCH 030/170] fixed bug with path links --- client.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/client.js b/client.js index 8bdcbfbc..5a238fe7 100644 --- a/client.js +++ b/client.js @@ -454,14 +454,23 @@ CloudClient._changeLinks = function(pPanelID) * двойное нажатие на левую кнопку мышки */ else{ + var lLi; + try{ - var lLi = a[i].parentElement.parentElement; - + lLi = a[i].parentElement.parentElement; + }catch(error){console.log(error);} + + /* if we in path changing onclick events*/ + if (lLi.className === 'path'){ + a[i].onclick = CloudClient._setCurrent(); + a[i].ondblclick = CloudClient._loadDir(link); + } + else { lLi.onclick = CloudClient._setCurrent(); lLi.ondblclick = CloudClient._loadDir(link); lLi.id = (a[i].title ? a[i].title : a[i].textContent) + '(' + pPanelID + ')'; - }catch(error){console.log(error);} + } } } } From 39a8ece33579b925fc1dc7d05889934a95b46a9e Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:49:35 -0400 Subject: [PATCH 031/170] fixed bug with path links --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 22d8465e..fb808e0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ * Added tab support. +* Fixed bug with Path links. + 2012.07.27, Version 0.1.4 From 4a7299e3cb3e8dddfc5d0f24798aae898465f6c2 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:54:57 -0400 Subject: [PATCH 032/170] minor changes --- client.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.js b/client.js index 5a238fe7..d4355e76 100644 --- a/client.js +++ b/client.js @@ -461,8 +461,7 @@ CloudClient._changeLinks = function(pPanelID) }catch(error){console.log(error);} /* if we in path changing onclick events*/ - if (lLi.className === 'path'){ - a[i].onclick = CloudClient._setCurrent(); + if (lLi.className === 'path') { a[i].ondblclick = CloudClient._loadDir(link); } else { From b1ee070dcd1f3393d2ac481d7d98360144d8d51e Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 04:57:59 -0400 Subject: [PATCH 033/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index d4355e76..cca5b785 100644 --- a/client.js +++ b/client.js @@ -462,7 +462,7 @@ CloudClient._changeLinks = function(pPanelID) /* if we in path changing onclick events*/ if (lLi.className === 'path') { - a[i].ondblclick = CloudClient._loadDir(link); + a[i].onclick = CloudClient._loadDir(link); } else { lLi.onclick = CloudClient._setCurrent(); From 4ef45e73fead11551ed63c28e3a37c54c9a359db Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:06:56 -0400 Subject: [PATCH 034/170] from now CodeMirror js files loads, when f4 key pressd --- lib/client/keyBinding.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index dd11dfb9..69b9c187 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -54,10 +54,15 @@ CloudCommander.keyBinding=(function(){ }catch(error){console.log(error);} } /* if f3 pressed */ - else if(event.keyCode===114){ - if (typeof CloudCommander.Viewer === 'function'){ + else if(event.keyCode===114){ + if (typeof CloudCommander.Viewer === 'function') CloudCommander.Viewer(); - } + } + + /* if f4 pressed */ + else if(event.keyCode === 115) { + if (typeof CloudCommander.Editor === 'function') + CloudCommander.Editor(); } /* навигация по таблице файлов*/ /* если нажали клавишу вверх*/ From 11e1c82936b113179cb1d8ba872ead3e1463905f Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:09:26 -0400 Subject: [PATCH 035/170] minor changes --- client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client.js b/client.js index cca5b785..4b9eaeda 100644 --- a/client.js +++ b/client.js @@ -844,7 +844,6 @@ try{ CloudCommander.init(); /* привязываем клавиши к функциям */ CloudCommander.keyBinding(); - CloudCommander.Editor(); }; } catch(err){} \ No newline at end of file From 77a2fbdfabb3ab3df742d9adb655d342b6e6f0eb Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:11:48 -0400 Subject: [PATCH 036/170] fixed bug with page reloadin --- lib/client/keyBinding.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 69b9c187..3b241b16 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -244,7 +244,7 @@ CloudCommander.keyBinding=(function(){ * убираем все обработчики * нажатий клавиш */ - else if(event.keyCode===81 && + else if(event.keyCode === 81 && event.altKey){ //document.removeEventListener('keydown', key_event,false); console.log('+q pressed'); @@ -255,6 +255,8 @@ CloudCommander.keyBinding=(function(){ /* обработчик нажатий клавиш снят*/ CloudCommander.keyBinded=false; } + + event.preventDefault();//запрет на дальнейшее действие } /* если нажали +s * устанавливаем все обработчики @@ -274,8 +276,6 @@ CloudCommander.keyBinding=(function(){ console.log('press +q to remove them'); } - event.preventDefault();//запрет на дальнейшее действие - return false; }; /* добавляем обработчик клавишь */ From 49789f92d189479ba9577c0bec1e304f2ac82bb0 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:19:21 -0400 Subject: [PATCH 037/170] minor changes --- lib/client/editor.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 3ba93df1..5bcd0013 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -12,7 +12,6 @@ CloudCommander.Editor.CodeMirror = { if (!document.getElementById('CloudEditor')) { var lEditor=document.createElement('div'); lEditor.id ='CloudEditor'; - lEditor.className = 'hidden'; var lFM = document.getElementById('fm'); if(lFM){ @@ -134,7 +133,4 @@ CloudCommander.Editor.Keys = (function(){ else document.onkeypress=key_event; - - /* клавиши назначены*/ - CloudCommander.keyBinded=true; }); \ No newline at end of file From d64f9d0f4468df86cb2ffd96fe2aaeb35d54e867 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:23:28 -0400 Subject: [PATCH 038/170] minor changes --- lib/client/editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 5bcd0013..f483c487 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -80,7 +80,7 @@ CloudCommander.Editor.CodeMirror = { var lLeft = this.getById('left'); var lCloudEditor = this.getById('CloudEditor'); - lLeft && + lLeft && (lLeft.className = 'panel hidden'); lCloudEditor && @@ -114,7 +114,7 @@ CloudCommander.Editor.Keys = (function(){ "use strict"; /* loading js and css of CodeMirror */ - CloudCommander.Editor.CodeMirror.load(); + CloudCommander.Editor.CodeMirror.show(); var key_event=function(event){ From 9ca039c4b002290d6d18953b7193027ef7141682 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:25:10 -0400 Subject: [PATCH 039/170] from now CodeMirror js files loads, when f4 key pressed --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index fb808e0e..192b4ea1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ * Fixed bug with Path links. +* From now CodeMirror js files loads, when f4 key pressed. + 2012.07.27, Version 0.1.4 From bda47450c3a15ce1a8e729ce19348837e2cfbc6b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:32:57 -0400 Subject: [PATCH 040/170] minor changes --- lib/client/editor.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index f483c487..f2c245cb 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -7,7 +7,7 @@ CloudCommander.Editor.CodeMirror = { load: (function(){ /* function loads CodeMirror js and css files */ /* function shows editor */ - var showEditor = function (pParent){ + var createEditorDiv = function (pParent){ return function(){ if (!document.getElementById('CloudEditor')) { var lEditor=document.createElement('div'); @@ -15,20 +15,7 @@ CloudCommander.Editor.CodeMirror = { var lFM = document.getElementById('fm'); if(lFM){ - lFM.appendChild(lEditor); - - CodeMirror(lEditor,{ - mode : "xml", - htmlMode : true, - theme : 'night', - lineNumbers : true, - //переносим длинные строки - lineWrapping: true, - extraKeys: { - //Сохранение - "Esc": pParent.hide(pParent) - } - }); + lFM.appendChild(lEditor); }else console.log('Error. Something went wrong FM not found'); } }; @@ -62,7 +49,7 @@ CloudCommander.Editor.CodeMirror = { }); CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js', - showEditor(pParent)); + createEditorDiv); }; }; @@ -70,7 +57,7 @@ CloudCommander.Editor.CodeMirror = { CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', loadAll(this)); }), - show : (function(){ /* function shows CodeMirror editor */ + show : (function(pParent){ /* function shows CodeMirror editor */ /* if CloudEditor is not loaded - loading him */ document.getElementById('CloudEditor') || this.load(); @@ -83,6 +70,21 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel hidden'); + + CodeMirror(lCloudEditor,{ + mode : "xml", + htmlMode : true, + theme : 'night', + lineNumbers : true, + //переносим длинные строки + lineWrapping: true, + extraKeys: { + //Сохранение + "Esc": pParent.hide(pParent) + } + }); + + lCloudEditor && (lCloudEditor.className = ''); }), @@ -114,7 +116,7 @@ CloudCommander.Editor.Keys = (function(){ "use strict"; /* loading js and css of CodeMirror */ - CloudCommander.Editor.CodeMirror.show(); + CloudCommander.Editor.CodeMirror.show(CloudCommander.Editor.CodeMirror); var key_event=function(event){ From 6392d4d97833a46ce58fb3ac459a5c2fbe365f47 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:35:45 -0400 Subject: [PATCH 041/170] minor changes --- lib/client/editor.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index f2c245cb..23cd0fd6 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -15,7 +15,8 @@ CloudCommander.Editor.CodeMirror = { var lFM = document.getElementById('fm'); if(lFM){ - lFM.appendChild(lEditor); + lFM.appendChild(lEditor); + this.show(); }else console.log('Error. Something went wrong FM not found'); } }; @@ -57,10 +58,10 @@ CloudCommander.Editor.CodeMirror = { CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', loadAll(this)); }), - show : (function(pParent){ /* function shows CodeMirror editor */ + show : (function(){ /* function shows CodeMirror editor */ /* if CloudEditor is not loaded - loading him */ - document.getElementById('CloudEditor') || - this.load(); + if(!document.getElementById('CloudEditor')) + return this.load(); /* removing keyBinding if set */ CloudCommander.keyBinded = false; @@ -80,7 +81,7 @@ CloudCommander.Editor.CodeMirror = { lineWrapping: true, extraKeys: { //Сохранение - "Esc": pParent.hide(pParent) + "Esc": this.hide(this) } }); From fa4b92677df442d3edaf0e47fab208a625673a36 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:45:54 -0400 Subject: [PATCH 042/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 23cd0fd6..ea93825c 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -7,7 +7,7 @@ CloudCommander.Editor.CodeMirror = { load: (function(){ /* function loads CodeMirror js and css files */ /* function shows editor */ - var createEditorDiv = function (pParent){ + var createEditorDiv = function() { return function(){ if (!document.getElementById('CloudEditor')) { var lEditor=document.createElement('div'); From f4c5d4f240a9531653656da37b2cb12716f80df3 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:48:17 -0400 Subject: [PATCH 043/170] minor changes --- lib/client/editor.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index ea93825c..ac04bdb2 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -8,18 +8,16 @@ CloudCommander.Editor.CodeMirror = { /* function shows editor */ var createEditorDiv = function() { - return function(){ - if (!document.getElementById('CloudEditor')) { - var lEditor=document.createElement('div'); - lEditor.id ='CloudEditor'; - var lFM = document.getElementById('fm'); - - if(lFM){ - lFM.appendChild(lEditor); - this.show(); - }else console.log('Error. Something went wrong FM not found'); - } - }; + if (!document.getElementById('CloudEditor')) { + var lEditor=document.createElement('div'); + lEditor.id ='CloudEditor'; + var lFM = document.getElementById('fm'); + + if(lFM){ + lFM.appendChild(lEditor); + this.show(); + }else console.log('Error. Something went wrong FM not found'); + } }; /* function loads css files * of CodeMirror From 9c7d46a6c92b6c559e19f1ee1ccd83918dc6b1c9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:49:35 -0400 Subject: [PATCH 044/170] minor changes --- lib/client/editor.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index ac04bdb2..9070941a 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -7,17 +7,19 @@ CloudCommander.Editor.CodeMirror = { load: (function(){ /* function loads CodeMirror js and css files */ /* function shows editor */ - var createEditorDiv = function() { - if (!document.getElementById('CloudEditor')) { - var lEditor=document.createElement('div'); - lEditor.id ='CloudEditor'; - var lFM = document.getElementById('fm'); - - if(lFM){ - lFM.appendChild(lEditor); - this.show(); - }else console.log('Error. Something went wrong FM not found'); - } + var createEditorDiv = function(pParent){ + return function(){ + if (!document.getElementById('CloudEditor')) { + var lEditor=document.createElement('div'); + lEditor.id ='CloudEditor'; + var lFM = document.getElementById('fm'); + + if(lFM){ + lFM.appendChild(lEditor); + this.show(); + }else console.log('Error. Something went wrong FM not found'); + } + }; }; /* function loads css files * of CodeMirror @@ -48,7 +50,7 @@ CloudCommander.Editor.CodeMirror = { }); CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js', - createEditorDiv); + createEditorDiv(this)); }; }; From ccfb64a9008aa6ac818d085217e7965d513ca79b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:50:31 -0400 Subject: [PATCH 045/170] minor changes --- lib/client/editor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 9070941a..383f3777 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -15,9 +15,10 @@ CloudCommander.Editor.CodeMirror = { var lFM = document.getElementById('fm'); if(lFM){ - lFM.appendChild(lEditor); - this.show(); + lFM.appendChild(lEditor); }else console.log('Error. Something went wrong FM not found'); + + pParent.show(); } }; }; From 13de3ae93055f769b21aacf403ec0ea628b0c7b9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 05:52:06 -0400 Subject: [PATCH 046/170] minor changes --- lib/client/editor.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 383f3777..82c704b9 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -4,23 +4,21 @@ var CloudCommander, CodeMirror; */ CloudCommander.Editor = {}; CloudCommander.Editor.CodeMirror = { - load: (function(){ /* function loads CodeMirror js and css files */ + load: (function(pParent){ /* function loads CodeMirror js and css files */ /* function shows editor */ - var createEditorDiv = function(pParent){ - return function(){ - if (!document.getElementById('CloudEditor')) { - var lEditor=document.createElement('div'); - lEditor.id ='CloudEditor'; - var lFM = document.getElementById('fm'); - - if(lFM){ - lFM.appendChild(lEditor); - }else console.log('Error. Something went wrong FM not found'); - - pParent.show(); - } - }; + var createEditorDiv = function(){ + if (!document.getElementById('CloudEditor')) { + var lEditor=document.createElement('div'); + lEditor.id ='CloudEditor'; + var lFM = document.getElementById('fm'); + + if(lFM){ + lFM.appendChild(lEditor); + }else console.log('Error. Something went wrong FM not found'); + + pParent.show(); + } }; /* function loads css files * of CodeMirror @@ -51,7 +49,7 @@ CloudCommander.Editor.CodeMirror = { }); CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js', - createEditorDiv(this)); + createEditorDiv); }; }; @@ -62,7 +60,7 @@ CloudCommander.Editor.CodeMirror = { show : (function(){ /* function shows CodeMirror editor */ /* if CloudEditor is not loaded - loading him */ if(!document.getElementById('CloudEditor')) - return this.load(); + return this.load(this); /* removing keyBinding if set */ CloudCommander.keyBinded = false; From 53f2adcaaed14160b1f849b0f9fdd0b1217aee5a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:17:23 -0400 Subject: [PATCH 047/170] minor changes --- lib/client/editor.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 82c704b9..908491c8 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -69,8 +69,7 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel hidden'); - - + CodeMirror(lCloudEditor,{ mode : "xml", htmlMode : true, @@ -100,6 +99,10 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel'); + + var lCodeMirror = pParent.getByClassName('CodeMirror'); + if(lCodeMirror.length) + document.body.removeChild([0]); }; }), getById: function(pId){return document.getElementById(pId);}, From 316dafc661c1f68e8709b574fd6b12856eedd79b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:18:15 -0400 Subject: [PATCH 048/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 908491c8..bfad6262 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -100,7 +100,7 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel'); - var lCodeMirror = pParent.getByClassName('CodeMirror'); + var lCodeMirror = pParent.getByClass('CodeMirror'); if(lCodeMirror.length) document.body.removeChild([0]); }; From c3169814db08a7667d8303e0a9f6eb21f4f12fcd Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:19:31 -0400 Subject: [PATCH 049/170] minor changes --- lib/client/editor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index bfad6262..5b84651b 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -105,9 +105,13 @@ CloudCommander.Editor.CodeMirror = { document.body.removeChild([0]); }; }), - getById: function(pId){return document.getElementById(pId);}, + getById : function(pId){return document.getElementById(pId);}, - getPanel: function(){ + getByClass : function(pClass){ + return document.getElementsByClassName(pClass); + }, + + getPanel : function(){ var lCurrent = document.getElementsByClassName('current-file'); lCurrent.length && (lCurrent = lCurrent[0].parentElement); From 823425e396c9a257eca81b4194287fa35be3756a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:20:20 -0400 Subject: [PATCH 050/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 5b84651b..fbacb6b5 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -102,7 +102,7 @@ CloudCommander.Editor.CodeMirror = { var lCodeMirror = pParent.getByClass('CodeMirror'); if(lCodeMirror.length) - document.body.removeChild([0]); + document.body.removeChild(lCodeMirror[0]); }; }), getById : function(pId){return document.getElementById(pId);}, From d1aac214bf593501c342fd63cf1e2bc35d66b448 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:21:33 -0400 Subject: [PATCH 051/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index fbacb6b5..4031a68a 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -102,7 +102,7 @@ CloudCommander.Editor.CodeMirror = { var lCodeMirror = pParent.getByClass('CodeMirror'); if(lCodeMirror.length) - document.body.removeChild(lCodeMirror[0]); + lLeft.removeChild(lCodeMirror[0]); }; }), getById : function(pId){return document.getElementById(pId);}, From 0715a2db940494074996f0aefe9c485cd8dc5cf1 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:22:55 -0400 Subject: [PATCH 052/170] minor changes --- lib/client/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 4031a68a..70a60e58 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -102,7 +102,8 @@ CloudCommander.Editor.CodeMirror = { var lCodeMirror = pParent.getByClass('CodeMirror'); if(lCodeMirror.length) - lLeft.removeChild(lCodeMirror[0]); + lLeft.parentElement + .removeChild(lCodeMirror[0]); }; }), getById : function(pId){return document.getElementById(pId);}, From b5962535f23dd47e441f85e528f6aeaa947d2cf9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:24:42 -0400 Subject: [PATCH 053/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 70a60e58..12fdd880 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -102,7 +102,7 @@ CloudCommander.Editor.CodeMirror = { var lCodeMirror = pParent.getByClass('CodeMirror'); if(lCodeMirror.length) - lLeft.parentElement + lCloudEditor .removeChild(lCodeMirror[0]); }; }), From 92a2163a6896a91bd4c54cbc09964355dbb7b926 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:28:10 -0400 Subject: [PATCH 054/170] minor changes --- lib/client/editor.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 12fdd880..cf0237a6 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -70,18 +70,20 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel hidden'); - CodeMirror(lCloudEditor,{ - mode : "xml", - htmlMode : true, - theme : 'night', - lineNumbers : true, - //переносим длинные строки - lineWrapping: true, - extraKeys: { - //Сохранение - "Esc": this.hide(this) - } - }); + var lCodeMirror = CodeMirror(lCloudEditor,{ + mode : "xml", + htmlMode : true, + theme : 'night', + lineNumbers : true, + //переносим длинные строки + lineWrapping: true, + extraKeys: { + //Сохранение + "Esc": this.hide(this) + } + }); + + lCodeMirror.setCursor({line:1,ch:1}); lCloudEditor && From a25036b0c060a7c1388055e14470a4e30ad950de Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:29:52 -0400 Subject: [PATCH 055/170] minor changes --- lib/client/editor.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index cf0237a6..0564370c 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -70,21 +70,20 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel hidden'); - var lCodeMirror = CodeMirror(lCloudEditor,{ - mode : "xml", - htmlMode : true, - theme : 'night', - lineNumbers : true, - //переносим длинные строки - lineWrapping: true, - extraKeys: { - //Сохранение - "Esc": this.hide(this) - } + CodeMirror(lCloudEditor,{ + mode : "xml", + htmlMode : true, + theme : 'night', + lineNumbers : true, + //переносим длинные строки + lineWrapping: true, + autofocus : true, + extraKeys: { + //Сохранение + "Esc": this.hide(this) + } }); - - lCodeMirror.setCursor({line:1,ch:1}); - + lCloudEditor && (lCloudEditor.className = ''); From 3d5bcb73522fb763df3807d41497ddb0b0ede155 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:31:36 -0400 Subject: [PATCH 056/170] minor changes --- lib/client/editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 0564370c..90e16ccb 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -71,8 +71,8 @@ CloudCommander.Editor.CodeMirror = { (lLeft.className = 'panel hidden'); CodeMirror(lCloudEditor,{ - mode : "xml", - htmlMode : true, + mode : 'javascript', + value : '', theme : 'night', lineNumbers : true, //переносим длинные строки From 3689faf7ee7c64d8aa7ff47802560f7532510803 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:32:36 -0400 Subject: [PATCH 057/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 90e16ccb..8fbe3274 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -71,7 +71,7 @@ CloudCommander.Editor.CodeMirror = { (lLeft.className = 'panel hidden'); CodeMirror(lCloudEditor,{ - mode : 'javascript', + mode : 'xml', value : '', theme : 'night', lineNumbers : true, From b1ec78da3dce168d60f58be1a43f34115322582c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:37:05 -0400 Subject: [PATCH 058/170] minor changes --- lib/client/editor.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 8fbe3274..96b87351 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -35,10 +35,12 @@ CloudCommander.Editor.CodeMirror = { CloudCommander.cssSet({id:'editor', inner : '.CodeMirror{' + - 'font-family:\'Droid Sans Mono\';' + - 'font-size:15px;' + - 'resize:vertical;' + - 'padding:20px;' + + 'font-family :\'Droid Sans Mono\';' + + 'font-size :15px;' + + 'resize :vertical;' + + 'padding :20px;' + + 'top :26px;' + + 'left :52px;' + '}' + '.CodeMirror-scroll{' + 'height: 660px;' + From c74270fedb80f9531e68ddf1d363e6d4e20d2c66 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:37:45 -0400 Subject: [PATCH 059/170] minor changes --- lib/client/editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 96b87351..2a4721bf 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -43,10 +43,10 @@ CloudCommander.Editor.CodeMirror = { 'left :52px;' + '}' + '.CodeMirror-scroll{' + - 'height: 660px;' + + 'height : 660px;' + '}' + '.CodeMirror-scrollbar{' + - 'overflow-y:auto' + + 'overflow-y :auto' + '}' }); From 93797b3525683851b2c547ad0129352be864dc57 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:38:27 -0400 Subject: [PATCH 060/170] minor changes --- lib/client/editor.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 2a4721bf..b6438df3 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -39,8 +39,6 @@ CloudCommander.Editor.CodeMirror = { 'font-size :15px;' + 'resize :vertical;' + 'padding :20px;' + - 'top :26px;' + - 'left :52px;' + '}' + '.CodeMirror-scroll{' + 'height : 660px;' + From f921e4845dc22f907887d2f7ad0a449b610881cb Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 13:44:13 +0300 Subject: [PATCH 061/170] Update lib/client/editor.js --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index b6438df3..fb58089b 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -83,7 +83,7 @@ CloudCommander.Editor.CodeMirror = { "Esc": this.hide(this) } }); - + console.log(document.getElementsByClassName('CodeMirror')); lCloudEditor && (lCloudEditor.className = ''); From c24cbab2cff41ae54918649d72b7df62cba6f980 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 13:48:44 +0300 Subject: [PATCH 062/170] Update lib/client/editor.js fixing after first showinng CodeMirror bug --- lib/client/editor.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index fb58089b..243b8119 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -83,8 +83,13 @@ CloudCommander.Editor.CodeMirror = { "Esc": this.hide(this) } }); - console.log(document.getElementsByClassName('CodeMirror')); - + /* fixing after first showinng CodeMirror bug */ + var lCodeMirror = this.getByClass('CodeMirror'); + if(lCodeMirror.length) { + var lDiv = lCodeMirror[0].getElementsByTagName('div'); + if(lDiv.length) + lDiv.style.cssText += lDiv.style.cssText + ';top:26px;left:57px'; + } lCloudEditor && (lCloudEditor.className = ''); }), From ff8033b62f779510c6d46b85567fd8fef3690b8c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 13:51:15 +0300 Subject: [PATCH 063/170] Update lib/client/editor.js --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 243b8119..95d042ab 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -88,7 +88,7 @@ CloudCommander.Editor.CodeMirror = { if(lCodeMirror.length) { var lDiv = lCodeMirror[0].getElementsByTagName('div'); if(lDiv.length) - lDiv.style.cssText += lDiv.style.cssText + ';top:26px;left:57px'; + lDiv[0].style.cssText += lDiv.style.cssText + ';top:26px;left:57px'; } lCloudEditor && (lCloudEditor.className = ''); From 2fc0c1dcf37bf118c51e8bfc2c42390e8c2e4c3c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 13:53:00 +0300 Subject: [PATCH 064/170] Update lib/client/editor.js --- lib/client/editor.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 95d042ab..4313abc1 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -86,9 +86,15 @@ CloudCommander.Editor.CodeMirror = { /* fixing after first showinng CodeMirror bug */ var lCodeMirror = this.getByClass('CodeMirror'); if(lCodeMirror.length) { + var lDiv = lCodeMirror[0].getElementsByTagName('div'); - if(lDiv.length) - lDiv[0].style.cssText += lDiv.style.cssText + ';top:26px;left:57px'; + if(lDiv.length){ + lDiv = lDiv[0]; + + lDiv.style.cssText += + lDiv.style.cssText + + ';top:26px;left:57px'; + } } lCloudEditor && (lCloudEditor.className = ''); From 057c32075454286c3db3f3edb154cc40164e8dc8 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:58:38 -0400 Subject: [PATCH 065/170] minor changes --- lib/client/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 4313abc1..4467d7f2 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -106,9 +106,10 @@ CloudCommander.Editor.CodeMirror = { var lLeft = pParent.getById('left'); var lCloudEditor = pParent.getById('CloudEditor'); + /* lCloudEditor && (lCloudEditor.className = 'hidden'); - + */ lLeft && (lLeft.className = 'panel'); From 22a0c75be71fa802a492b7a3f49d3baec56d4e8c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 06:59:58 -0400 Subject: [PATCH 066/170] minor changes --- lib/client/editor.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 4467d7f2..ef8ca39a 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -82,22 +82,7 @@ CloudCommander.Editor.CodeMirror = { //Сохранение "Esc": this.hide(this) } - }); - /* fixing after first showinng CodeMirror bug */ - var lCodeMirror = this.getByClass('CodeMirror'); - if(lCodeMirror.length) { - - var lDiv = lCodeMirror[0].getElementsByTagName('div'); - if(lDiv.length){ - lDiv = lDiv[0]; - - lDiv.style.cssText += - lDiv.style.cssText + - ';top:26px;left:57px'; - } - } - lCloudEditor && - (lCloudEditor.className = ''); + }); }), hide : (function(pParent) { return function(){ From 9544c66633582816053b6687074b3aab8d22281a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 07:01:06 -0400 Subject: [PATCH 067/170] minor changes --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 192b4ea1..d33ea004 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ * From now CodeMirror js files loads, when f4 key pressed. +* Fixed bug with showing CodeMirror after first show. + 2012.07.27, Version 0.1.4 From e6a997776bf97719e46227b95d53b4891b4a81e8 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:29:39 -0400 Subject: [PATCH 068/170] added ability to read files in CodeMirror --- lib/client/editor.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index ef8ca39a..5d11fc76 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -54,7 +54,8 @@ CloudCommander.Editor.CodeMirror = { }; /* load CodeMirror main module */ - CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', loadAll(this)); + CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', + loadAll(this)); }), show : (function(){ /* function shows CodeMirror editor */ @@ -67,12 +68,24 @@ CloudCommander.Editor.CodeMirror = { var lLeft = this.getById('left'); var lCloudEditor = this.getById('CloudEditor'); + var lCurrent = this.getById(CloudCommander.CURRENCURRENT_FILE); + var lA; + if(lCurrent.length) + lA = lCurrent.getElementsByTagName('a'); + + if(lA.length) + lA = lA[0].href; + + var lValue = $.ajax(lA); + if(lValue.responseText) + lValue = lValue.responseText; + lLeft && (lLeft.className = 'panel hidden'); CodeMirror(lCloudEditor,{ mode : 'xml', - value : '', + value : lValue, theme : 'night', lineNumbers : true, //переносим длинные строки From 6eff3d127749a9a79b82b061033cf0c689d5efad Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:30:40 -0400 Subject: [PATCH 069/170] added ability to read files in CodeMirror --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index d33ea004..83f16a8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ * Fixed bug with showing CodeMirror after first show. +* Added ability to read files in CodeMirror. 2012.07.27, Version 0.1.4 From c884bd1abd6c691e61df779064c0955ac9292030 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:33:16 -0400 Subject: [PATCH 070/170] minor changes --- lib/client/editor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 5d11fc76..3ee3fb2b 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -67,11 +67,12 @@ CloudCommander.Editor.CodeMirror = { var lLeft = this.getById('left'); var lCloudEditor = this.getById('CloudEditor'); + var lCURRENTFILE = CloudCommander.CURRENCURRENT_FILE; - var lCurrent = this.getById(CloudCommander.CURRENCURRENT_FILE); + var lCurrent = this.getByClassName(lCURRENTFILE); var lA; if(lCurrent.length) - lA = lCurrent.getElementsByTagName('a'); + lA = lCurrent[0].getElementsByTagName('a'); if(lA.length) lA = lA[0].href; From 7c27ac63b3116536f01cf27fb8669a602cb74f95 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:36:43 -0400 Subject: [PATCH 071/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 3ee3fb2b..9fd121a9 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -69,7 +69,7 @@ CloudCommander.Editor.CodeMirror = { var lCloudEditor = this.getById('CloudEditor'); var lCURRENTFILE = CloudCommander.CURRENCURRENT_FILE; - var lCurrent = this.getByClassName(lCURRENTFILE); + var lCurrent = this.getByClass(lCURRENTFILE); var lA; if(lCurrent.length) lA = lCurrent[0].getElementsByTagName('a'); From a6afafe2e46d677b802aa0422f8f66f1c5d4c0a7 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:37:43 -0400 Subject: [PATCH 072/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 9fd121a9..7d3f52f4 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -67,7 +67,7 @@ CloudCommander.Editor.CodeMirror = { var lLeft = this.getById('left'); var lCloudEditor = this.getById('CloudEditor'); - var lCURRENTFILE = CloudCommander.CURRENCURRENT_FILE; + var lCURRENTFILE = CloudCommander.CURRENT_FILE; var lCurrent = this.getByClass(lCURRENTFILE); var lA; From 1038e1a028ada18f231e0a3bd32facbaea6f6304 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:43:48 -0400 Subject: [PATCH 073/170] minor changes --- lib/client/editor.js | 47 +++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 7d3f52f4..c2c29882 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -65,10 +65,27 @@ CloudCommander.Editor.CodeMirror = { /* removing keyBinding if set */ CloudCommander.keyBinded = false; + var initCodeMirror_f = function(pValue){ + CodeMirror(lCloudEditor,{ + mode : 'xml', + value : pValue, + theme : 'night', + lineNumbers : true, + //переносим длинные строки + lineWrapping: true, + autofocus : true, + extraKeys: { + //Сохранение + "Esc": this.hide(this) + } + }); + }; + var lLeft = this.getById('left'); var lCloudEditor = this.getById('CloudEditor'); var lCURRENTFILE = CloudCommander.CURRENT_FILE; + var lCurrent = this.getByClass(lCURRENTFILE); var lA; if(lCurrent.length) @@ -76,27 +93,25 @@ CloudCommander.Editor.CodeMirror = { if(lA.length) lA = lA[0].href; + + /* reading data from current file */ + var lValue = $.ajax({ + url:lA, - var lValue = $.ajax(lA); + error: function(jqXHR, textStatus, errorThrown){ + console.log(textStatus+' : '+errorThrown); + initCodeMirror_f(''); + }, + + success:function(data, textStatus, jqXHR){ + initCodeMirror_f(data); + } + }); if(lValue.responseText) lValue = lValue.responseText; lLeft && - (lLeft.className = 'panel hidden'); - - CodeMirror(lCloudEditor,{ - mode : 'xml', - value : lValue, - theme : 'night', - lineNumbers : true, - //переносим длинные строки - lineWrapping: true, - autofocus : true, - extraKeys: { - //Сохранение - "Esc": this.hide(this) - } - }); + (lLeft.className = 'panel hidden'); }), hide : (function(pParent) { return function(){ From e65ec7fb9ffab9a09e1271d645e9f99a0e78c260 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:47:05 -0400 Subject: [PATCH 074/170] minor changes --- lib/client/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index c2c29882..ae14b678 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -65,6 +65,7 @@ CloudCommander.Editor.CodeMirror = { /* removing keyBinding if set */ CloudCommander.keyBinded = false; + var lParent = this; var initCodeMirror_f = function(pValue){ CodeMirror(lCloudEditor,{ mode : 'xml', @@ -76,7 +77,7 @@ CloudCommander.Editor.CodeMirror = { autofocus : true, extraKeys: { //Сохранение - "Esc": this.hide(this) + "Esc": lParent.hide(this) } }); }; From 41481d6810173484a9690f67ba6d2fc36e1dd102 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:50:03 -0400 Subject: [PATCH 075/170] minor changes --- lib/client/editor.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index ae14b678..5440eb31 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -77,7 +77,7 @@ CloudCommander.Editor.CodeMirror = { autofocus : true, extraKeys: { //Сохранение - "Esc": lParent.hide(this) + "Esc": lParent.hide(lParent) } }); }; @@ -96,23 +96,20 @@ CloudCommander.Editor.CodeMirror = { lA = lA[0].href; /* reading data from current file */ - var lValue = $.ajax({ + $.ajax({ url:lA, error: function(jqXHR, textStatus, errorThrown){ - console.log(textStatus+' : '+errorThrown); - initCodeMirror_f(''); + console.log(textStatus+' : '+errorThrown); }, success:function(data, textStatus, jqXHR){ initCodeMirror_f(data); + + lLeft && + (lLeft.className = 'panel hidden'); } - }); - if(lValue.responseText) - lValue = lValue.responseText; - - lLeft && - (lLeft.className = 'panel hidden'); + }); }), hide : (function(pParent) { return function(){ From e28476956395e886b3f37d00c42bbf821abb7395 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 10:51:46 -0400 Subject: [PATCH 076/170] minor changes --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 5440eb31..71c2367d 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -73,7 +73,7 @@ CloudCommander.Editor.CodeMirror = { theme : 'night', lineNumbers : true, //переносим длинные строки - lineWrapping: true, + lineWrapping: false, autofocus : true, extraKeys: { //Сохранение From a5c6b563470f647e2f4c7a819055a3a50d139457 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jul 2012 11:06:37 -0400 Subject: [PATCH 077/170] minor changes --- lib/client/editor.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 71c2367d..a95d4ad9 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -100,7 +100,9 @@ CloudCommander.Editor.CodeMirror = { url:lA, error: function(jqXHR, textStatus, errorThrown){ - console.log(textStatus+' : '+errorThrown); + console.log(textStatus+' : '+ errorThrown); + + return false; }, success:function(data, textStatus, jqXHR){ From e1b71753903cde4ff0c7ed4642f4da0b5aab998a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:30:53 -0400 Subject: [PATCH 078/170] added ability rename files --- client.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/client.js b/client.js index 4b9eaeda..a3edc350 100644 --- a/client.js +++ b/client.js @@ -256,10 +256,19 @@ CloudClient._setCurrent=(function(){ if(this.className!=='path' && this.className!=='fm_header'){ - lCurrentFile[0].className=''; - /* устанавливаем курсор на файл, - * на который нажали */ - this.className=CloudClient.CURRENT_FILE; + if (this.className === CloudClient.CURRENT_FILE){ + var lA = this.getEgetElementsByTagName('a'); + if (lA.length){ + lA[0].contentEditable = true; + CloudCommander.keyBinding = false; + } + } + else{ + lCurrentFile[0].className=''; + /* устанавливаем курсор на файл, + * на который нажали */ + this.className = CloudClient.CURRENT_FILE; + } } } /* если мы попали сюда с энтера*/ From cde67dc0ce83d8801b5855afe18970a3218ad6b9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:33:36 -0400 Subject: [PATCH 079/170] added ability rename files --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 83f16a8c..03f07292 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,8 @@ * Added ability to read files in CodeMirror. +* Added ability rename files. + 2012.07.27, Version 0.1.4 * Added local version of Droids font for offline mode From e9364e7f1e75de653a92dea646dad49853fbc2bb Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:36:37 -0400 Subject: [PATCH 080/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index a3edc350..21ded037 100644 --- a/client.js +++ b/client.js @@ -257,7 +257,7 @@ CloudClient._setCurrent=(function(){ this.className!=='fm_header'){ if (this.className === CloudClient.CURRENT_FILE){ - var lA = this.getEgetElementsByTagName('a'); + var lA = this.getElementsByTagName('a'); if (lA.length){ lA[0].contentEditable = true; CloudCommander.keyBinding = false; From 9fadbd08284e74bcb865b59f31654f4e2e60bc0d Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:39:12 -0400 Subject: [PATCH 081/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index 21ded037..e374c4b9 100644 --- a/client.js +++ b/client.js @@ -260,7 +260,7 @@ CloudClient._setCurrent=(function(){ var lA = this.getElementsByTagName('a'); if (lA.length){ lA[0].contentEditable = true; - CloudCommander.keyBinding = false; + CloudCommander.keyBinded = false; } } else{ From 7f345951d3ab85d14f53991e95fcd90416012b92 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:47:14 -0400 Subject: [PATCH 082/170] minor changes --- client.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/client.js b/client.js index e374c4b9..13fc1f8f 100644 --- a/client.js +++ b/client.js @@ -261,6 +261,25 @@ CloudClient._setCurrent=(function(){ if (lA.length){ lA[0].contentEditable = true; CloudCommander.keyBinded = false; + + var lDocumentOnclick = document.onclick; + + /* setting event handler onclick + * if user clicks somewhere keyBinded + * backs + */ + document.onclick = (function(){ + CloudCommander.keyBinded = true; + + /* backs old document.onclick + * and call it if it was + * setted up earlier + */ + document.onclick = lDocumentOnclick; + if(typeof lDocumentOnclick === 'function') + lDocumentOnclick(); + + }); } } else{ From f50ece9bfde059d92de66cfb3ec6fc2cca55e9f6 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:50:33 -0400 Subject: [PATCH 083/170] minor changes --- client.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client.js b/client.js index 13fc1f8f..061ed4d9 100644 --- a/client.js +++ b/client.js @@ -264,11 +264,19 @@ CloudClient._setCurrent=(function(){ var lDocumentOnclick = document.onclick; + var lFirstClick = true; /* setting event handler onclick * if user clicks somewhere keyBinded * backs */ document.onclick = (function(){ + /* exiting if it was + * first click, because + * we geetting here to + * fast + */ + if (lFirstClick) + return; CloudCommander.keyBinded = true; /* backs old document.onclick From 25e74161e3e6369f8d236e3d690023de998b0adc Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:51:21 -0400 Subject: [PATCH 084/170] minor changes --- client.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client.js b/client.js index 061ed4d9..9b106aa7 100644 --- a/client.js +++ b/client.js @@ -275,8 +275,10 @@ CloudClient._setCurrent=(function(){ * we geetting here to * fast */ - if (lFirstClick) + if (lFirstClick){ + lFirstClick = false; return; + } CloudCommander.keyBinded = true; /* backs old document.onclick From 761e91af26ad07f9a1a29009574628960c463629 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:53:25 -0400 Subject: [PATCH 085/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index 9b106aa7..62576597 100644 --- a/client.js +++ b/client.js @@ -258,7 +258,7 @@ CloudClient._setCurrent=(function(){ if (this.className === CloudClient.CURRENT_FILE){ var lA = this.getElementsByTagName('a'); - if (lA.length){ + if (lA.length && lA.textContent !== '..'){ lA[0].contentEditable = true; CloudCommander.keyBinded = false; From c38cd5182e7e95dbdd599c23d023b45021215d22 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 03:59:39 -0400 Subject: [PATCH 086/170] minor changes --- client.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.js b/client.js index 62576597..f7a029ab 100644 --- a/client.js +++ b/client.js @@ -258,7 +258,8 @@ CloudClient._setCurrent=(function(){ if (this.className === CloudClient.CURRENT_FILE){ var lA = this.getElementsByTagName('a'); - if (lA.length && lA.textContent !== '..'){ + if (lA.length && lA.textContent !== '..' && + event.keyCode !== 13/*enter*/){ lA[0].contentEditable = true; CloudCommander.keyBinded = false; From 554ae2bd9fa3645d3301675b0d535f2172f6ba04 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:42:49 -0400 Subject: [PATCH 087/170] minor changes --- client.js | 85 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/client.js b/client.js index f7a029ab..b2be4268 100644 --- a/client.js +++ b/client.js @@ -238,6 +238,48 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ }; }); + +/* + * Function edits file name + */ +CloudClient._editFileName = (function(){ +var lA = this.getElementsByTagName('a'); + if (lA.length && lA.textContent !== '..' && + event.keyCode !== 13/*enter*/){ + lA[0].contentEditable = true; + CloudCommander.keyBinded = false; + + var lDocumentOnclick = document.onclick; + + var lFirstClick = true; + /* setting event handler onclick + * if user clicks somewhere keyBinded + * backs + */ + document.onclick = (function(){ + /* exiting if it was + * first click, because + * we geetting here to + * fast + */ + if (lFirstClick){ + lFirstClick = false; + return; + } + CloudCommander.keyBinded = true; + + /* backs old document.onclick + * and call it if it was + * setted up earlier + */ + document.onclick = lDocumentOnclick; + if(typeof lDocumentOnclick === 'function') + lDocumentOnclick(); + + }); + } +}); + /* Функция устанавливает текущим файлом, тот * на который кликнули единожды */ @@ -257,41 +299,16 @@ CloudClient._setCurrent=(function(){ this.className!=='fm_header'){ if (this.className === CloudClient.CURRENT_FILE){ - var lA = this.getElementsByTagName('a'); - if (lA.length && lA.textContent !== '..' && - event.keyCode !== 13/*enter*/){ - lA[0].contentEditable = true; - CloudCommander.keyBinded = false; - - var lDocumentOnclick = document.onclick; - - var lFirstClick = true; - /* setting event handler onclick - * if user clicks somewhere keyBinded - * backs + setTimeout(function(){ + /* waiting a few seconds + * and if classes still equal + * make file name editable + * in other case + * double click event happend */ - document.onclick = (function(){ - /* exiting if it was - * first click, because - * we geetting here to - * fast - */ - if (lFirstClick){ - lFirstClick = false; - return; - } - CloudCommander.keyBinded = true; - - /* backs old document.onclick - * and call it if it was - * setted up earlier - */ - document.onclick = lDocumentOnclick; - if(typeof lDocumentOnclick === 'function') - lDocumentOnclick(); - - }); - } + if(this.className === CloudClient.CURRENT_FILE) + CloudClient._editFileName(); + },400); } else{ lCurrentFile[0].className=''; From 56dc73f4316ee416d95e53e9e4785b02ba1eeb38 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:44:51 -0400 Subject: [PATCH 088/170] minor changes --- client.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client.js b/client.js index b2be4268..5414c617 100644 --- a/client.js +++ b/client.js @@ -299,6 +299,8 @@ CloudClient._setCurrent=(function(){ this.className!=='fm_header'){ if (this.className === CloudClient.CURRENT_FILE){ + var lParent = this; + setTimeout(function(){ /* waiting a few seconds * and if classes still equal @@ -306,7 +308,7 @@ CloudClient._setCurrent=(function(){ * in other case * double click event happend */ - if(this.className === CloudClient.CURRENT_FILE) + if(lParent.className === CloudClient.CURRENT_FILE) CloudClient._editFileName(); },400); } From aa18b3867b059e616c19e889fac6f2f9b50ef40b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:46:07 -0400 Subject: [PATCH 089/170] minor changes --- client.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client.js b/client.js index 5414c617..fd1c6d83 100644 --- a/client.js +++ b/client.js @@ -241,9 +241,11 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ /* * Function edits file name + * + * @pParent - parent element */ -CloudClient._editFileName = (function(){ -var lA = this.getElementsByTagName('a'); +CloudClient._editFileName = (function(pParent){ +var lA = pParent.getElementsByTagName('a'); if (lA.length && lA.textContent !== '..' && event.keyCode !== 13/*enter*/){ lA[0].contentEditable = true; @@ -309,7 +311,7 @@ CloudClient._setCurrent=(function(){ * double click event happend */ if(lParent.className === CloudClient.CURRENT_FILE) - CloudClient._editFileName(); + CloudClient._editFileName(lParent); },400); } else{ From 38c391683b9173e020eb23da0cb8cb97748fab9b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:47:30 -0400 Subject: [PATCH 090/170] minor changes --- client.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.js b/client.js index fd1c6d83..fd1c646d 100644 --- a/client.js +++ b/client.js @@ -246,8 +246,7 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ */ CloudClient._editFileName = (function(pParent){ var lA = pParent.getElementsByTagName('a'); - if (lA.length && lA.textContent !== '..' && - event.keyCode !== 13/*enter*/){ + if (lA.length && lA.textContent !== '..'){ lA[0].contentEditable = true; CloudCommander.keyBinded = false; From 2baf2376538056a3239796c8fef0efad71afbcf4 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:49:47 -0400 Subject: [PATCH 091/170] minor changes --- client.js | 63 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/client.js b/client.js index fd1c646d..08d674fa 100644 --- a/client.js +++ b/client.js @@ -243,41 +243,43 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ * Function edits file name * * @pParent - parent element + * @pEvent */ CloudClient._editFileName = (function(pParent){ var lA = pParent.getElementsByTagName('a'); if (lA.length && lA.textContent !== '..'){ - lA[0].contentEditable = true; - CloudCommander.keyBinded = false; - - var lDocumentOnclick = document.onclick; - - var lFirstClick = true; - /* setting event handler onclick - * if user clicks somewhere keyBinded - * backs - */ - document.onclick = (function(){ - /* exiting if it was - * first click, because - * we geetting here to - * fast - */ - if (lFirstClick){ - lFirstClick = false; - return; - } - CloudCommander.keyBinded = true; - /* backs old document.onclick - * and call it if it was - * setted up earlier - */ - document.onclick = lDocumentOnclick; - if(typeof lDocumentOnclick === 'function') - lDocumentOnclick(); + lA[0].contentEditable = true; + CloudCommander.keyBinded = false; - }); + var lDocumentOnclick = document.onclick; + + var lFirstClick = true; + /* setting event handler onclick + * if user clicks somewhere keyBinded + * backs + */ + document.onclick = (function(){ + /* exiting if it was + * first click, because + * we geetting here to + * fast + */ + if (lFirstClick){ + lFirstClick = false; + return; + } + CloudCommander.keyBinded = true; + + /* backs old document.onclick + * and call it if it was + * setted up earlier + */ + document.onclick = lDocumentOnclick; + if(typeof lDocumentOnclick === 'function') + lDocumentOnclick(); + + }); } }); @@ -299,7 +301,8 @@ CloudClient._setCurrent=(function(){ if(this.className!=='path' && this.className!=='fm_header'){ - if (this.className === CloudClient.CURRENT_FILE){ + if (this.className === CloudClient.CURRENT_FILE && + !pFromEnter){ var lParent = this; setTimeout(function(){ From 298f6a1a9611d95b73a667cbea2aa584afbb72c2 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:52:35 -0400 Subject: [PATCH 092/170] minor changes --- client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.js b/client.js index 08d674fa..74ffa2c9 100644 --- a/client.js +++ b/client.js @@ -302,7 +302,7 @@ CloudClient._setCurrent=(function(){ this.className!=='fm_header'){ if (this.className === CloudClient.CURRENT_FILE && - !pFromEnter){ + typeof pFromEnter !== 'boolean'){ var lParent = this; setTimeout(function(){ From 0fb9361984c00bfce6b7d31f3428403792fe857a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 04:54:16 -0400 Subject: [PATCH 093/170] minor changes --- client.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/client.js b/client.js index 74ffa2c9..4156c445 100644 --- a/client.js +++ b/client.js @@ -254,21 +254,11 @@ var lA = pParent.getElementsByTagName('a'); var lDocumentOnclick = document.onclick; - var lFirstClick = true; /* setting event handler onclick * if user clicks somewhere keyBinded * backs */ - document.onclick = (function(){ - /* exiting if it was - * first click, because - * we geetting here to - * fast - */ - if (lFirstClick){ - lFirstClick = false; - return; - } + document.onclick = (function(){ CloudCommander.keyBinded = true; /* backs old document.onclick From 647867a01042972f76bffb97c4b12c02dc12a047 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 05:09:21 -0400 Subject: [PATCH 094/170] minor changes --- client.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client.js b/client.js index 4156c445..891326a9 100644 --- a/client.js +++ b/client.js @@ -258,7 +258,11 @@ var lA = pParent.getElementsByTagName('a'); * if user clicks somewhere keyBinded * backs */ - document.onclick = (function(){ + document.onclick = (function(){ + var lA = pParent.getElementsByTagName('a'); + if (lA.length && lA.textContent !== '..') + lA[0].contentEditable = false; + CloudCommander.keyBinded = true; /* backs old document.onclick From b06848b0266ed9256d1ff2b14eeabf67154e8d23 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 06:20:52 -0400 Subject: [PATCH 095/170] added mime type for mp3 --- lib/client/keyBinding.js | 5 ++++- server.js | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 3b241b16..4a50dd64 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -53,7 +53,10 @@ CloudCommander.keyBinding=(function(){ }catch(error){console.log(error);} } - /* if f3 pressed */ + /* if f2 pressed */ + else if(event.keyCode===113){ + + } else if(event.keyCode===114){ if (typeof CloudCommander.Viewer === 'function') CloudCommander.Viewer(); diff --git a/server.js b/server.js index f6a35588..a4eac94b 100644 --- a/server.js +++ b/server.js @@ -202,22 +202,24 @@ CloudServer.generateHeaders = function(pName, pGzip){ * загружаем стили */ if(CloudFunc.checkExtension(pName,'css')) - lType='text/css'; + lType = 'text/css'; /* загружаем js */ else if(CloudFunc.checkExtension(pName,'js')) - lType='text/javascript'; + lType = 'text/javascript'; /* загружаем картинки*/ else if(CloudFunc.checkExtension(pName,'png')) - lType='image/png'; + lType = 'image/png'; /* загружаем json*/ else if(CloudFunc.checkExtension(pName,'json')) - lType='application/json'; + lType = 'application/json'; else if(CloudFunc.checkExtension(pName,'html')) - lType='text/html'; + lType = 'text/html'; else if(CloudFunc.checkExtension(pName,'woff')) - lType='font/woff'; + lType = 'font/woff'; else if(CloudFunc.checkExtension(pName,'appcache')) - lType='text/cache-manifest'; + lType = 'text/cache-manifest'; + else if(CloudFunc.checkExtension(pName,'mp3')) + lType = 'audio/mpeg'; /* если это неизвестный тип файла - * высылаем его просто как текст */ From e912b7e61bdb6d7c86dbd2f698d94bbb5da10303 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 10:29:31 -0400 Subject: [PATCH 096/170] fixed bug with CodeMirror vertical scroll bar --- lib/client/editor.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index a95d4ad9..41a84efd 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -37,14 +37,10 @@ CloudCommander.Editor.CodeMirror = { inner : '.CodeMirror{' + 'font-family :\'Droid Sans Mono\';' + 'font-size :15px;' + - 'resize :vertical;' + 'padding :20px;' + '}' + '.CodeMirror-scroll{' + 'height : 660px;' + - '}' + - '.CodeMirror-scrollbar{' + - 'overflow-y :auto' + '}' }); @@ -72,7 +68,7 @@ CloudCommander.Editor.CodeMirror = { value : pValue, theme : 'night', lineNumbers : true, - //переносим длинные строки + //переносим длинные строки lineWrapping: false, autofocus : true, extraKeys: { From 877c7fbc083bb829461f1d864bfba1cc0a990cb5 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 10:29:53 -0400 Subject: [PATCH 097/170] fixed bug with CodeMirror vertical scroll bar --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 03f07292..1ccd567f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,8 @@ * Added ability rename files. +* Fixed bug with CodeMirror vertical scroll bar + 2012.07.27, Version 0.1.4 * Added local version of Droids font for offline mode From 38545c2f94091241dc09ad16607b11781060c803 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 10:30:09 -0400 Subject: [PATCH 098/170] minor changes --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 1ccd567f..a3138af5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ * Fixed bug with CodeMirror vertical scroll bar + 2012.07.27, Version 0.1.4 * Added local version of Droids font for offline mode From a9cf5aa3808557ae7aa1994e743260da61a9a444 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 10:54:58 -0400 Subject: [PATCH 099/170] fixed bug with CodeMirror ajax error processing --- lib/client/editor.js | 10 ++++------ lib/client/keyBinding.js | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 41a84efd..270474e2 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -58,8 +58,7 @@ CloudCommander.Editor.CodeMirror = { /* if CloudEditor is not loaded - loading him */ if(!document.getElementById('CloudEditor')) return this.load(this); - /* removing keyBinding if set */ - CloudCommander.keyBinded = false; + /* removing keyBinding if set */ var lParent = this; var initCodeMirror_f = function(pValue){ @@ -94,16 +93,15 @@ CloudCommander.Editor.CodeMirror = { /* reading data from current file */ $.ajax({ url:lA, - error: function(jqXHR, textStatus, errorThrown){ - console.log(textStatus+' : '+ errorThrown); - - return false; + console.log(textStatus+' : '+ errorThrown); }, success:function(data, textStatus, jqXHR){ initCodeMirror_f(data); + CloudCommander.keyBinded = false; + lLeft && (lLeft.className = 'panel hidden'); } diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 4a50dd64..43e39fe7 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -284,7 +284,7 @@ CloudCommander.keyBinding=(function(){ /* добавляем обработчик клавишь */ if(document.addEventListener) document.addEventListener('keydown', key_event,false); - else document.onkeypress=key_event; + else document.onkeypress = key_event; /* клавиши назначены*/ CloudCommander.keyBinded=true; }); \ No newline at end of file From 1dc17522a201b0ca2e4ac22e6f9674a5f0860141 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 31 Jul 2012 11:09:04 -0400 Subject: [PATCH 100/170] minor changes --- client.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client.js b/client.js index 891326a9..cff65078 100644 --- a/client.js +++ b/client.js @@ -588,11 +588,13 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) url: path, error: function(jqXHR, textStatus, errorThrown){ console.log(textStatus+' : '+errorThrown); + var lLoading=getById('loading-image'); + ErrorImage.className='icon error'; ErrorImage.title=errorThrown; lLoading.parentElement.appendChild(ErrorImage); - lLoading.className='hidden'; + lLoading.className='hidden'; }, success:function(data, textStatus, jqXHR){ /* если такой папки (или файла) нет From c01dc90226cc34f249d368355fd49b9ce7ea2f44 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 1 Aug 2012 06:00:40 -0400 Subject: [PATCH 101/170] added loading image when file going to be edited --- client.js | 6 ++++-- config.json | 4 ++-- lib/client/editor.js | 33 +++++++++++++++++++++++++++------ server.js | 42 ++++++++++++++++++++---------------------- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/client.js b/client.js index cff65078..ce3e32da 100644 --- a/client.js +++ b/client.js @@ -587,12 +587,12 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) $.ajax({ url: path, error: function(jqXHR, textStatus, errorThrown){ - console.log(textStatus+' : '+errorThrown); + console.log(jqXHR.responseText); var lLoading=getById('loading-image'); ErrorImage.className='icon error'; - ErrorImage.title=errorThrown; + ErrorImage.title = errorThrown; lLoading.parentElement.appendChild(ErrorImage); lLoading.className='hidden'; }, @@ -622,6 +622,8 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) lLoading.parentElement.appendChild(ErrorImage); lLoading.className = 'hidden'; + console.log(jqXHR.responseText); + return; } CloudClient._createFileTable(lPanel,data); diff --git a/config.json b/config.json index 0de340e3..d58f0b2d 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { - "cache" : {"allowed" : true}, + "cache" : {"allowed" : false}, "minification" : { - "js" : true, + "js" : false, "css" : true, "html" : true, "img" : true diff --git a/lib/client/editor.js b/lib/client/editor.js index 270474e2..e2c07755 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -84,17 +84,36 @@ CloudCommander.Editor.CodeMirror = { var lCurrent = this.getByClass(lCURRENTFILE); var lA; - if(lCurrent.length) - lA = lCurrent[0].getElementsByTagName('a'); - - if(lA.length) - lA = lA[0].href; + if(lCurrent.length){ + lCurrent = lCurrent[0]; + + lA = lCurrent.getElementsByTagName('a'); + + if(lA.length) + lA = lA[0].href; + } + + /* показываем гиф загрузки возле пути папки сверху*/ + var lLoadingImage = CloudCommander._images.loading(); + var lErrorImage = CloudCommander._images.error(); + + lLoadingImage.className='icon loading';/* показываем загрузку*/ + lErrorImage.className='icon error hidden';/* прячем ошибку */ + /* show loading icon */ + lCurrent.firstChild.nextSibling.appendChild(lLoadingImage); /* reading data from current file */ $.ajax({ url:lA, error: function(jqXHR, textStatus, errorThrown){ - console.log(textStatus+' : '+ errorThrown); + lErrorImage.className ='icon error'; + lErrorImage.title = jqXHR.responseText; + + lCurrent.firstChild.nextSibling.appendChild(lErrorImage); + + lLoadingImage.className ='hidden'; + + console.log(jqXHR.responseText); }, success:function(data, textStatus, jqXHR){ @@ -104,6 +123,8 @@ CloudCommander.Editor.CodeMirror = { lLeft && (lLeft.className = 'panel hidden'); + + lLoadingImage.className ='hidden'; } }); }), diff --git a/server.js b/server.js index a4eac94b..ff6b8249 100644 --- a/server.js +++ b/server.js @@ -400,32 +400,30 @@ CloudServer._controller=function(pReq, pRes) /* если это каталог - * читаем его содержимое */ - try{ - /* если установлено сжатие - * меняем название html-файла и - * загружаем сжатый html-файл в дальнейшем - */ - CloudServer.INDEX=(CloudServer.Minify._allowed.html? - '.' + CloudServer.Minify.MinFolder + 'index.min.html' - :CloudServer.INDEX); - /* - * сохраним указатель на response - * и на статус ответа - */ - CloudServer.Responses[CloudServer.INDEX]=pRes; - CloudServer.Statuses[CloudServer.INDEX] = 200; - - if(lStat.isDirectory()){ - Fs.readdir(DirPath,CloudServer._readDir); - - } + + /* если установлено сжатие + * меняем название html-файла и + * загружаем сжатый html-файл в дальнейшем + */ + CloudServer.INDEX=(CloudServer.Minify._allowed.html? + '.' + CloudServer.Minify.MinFolder + 'index.min.html' + :CloudServer.INDEX); + /* + * сохраним указатель на response + * и на статус ответа + */ + CloudServer.Responses[CloudServer.INDEX]=pRes; + CloudServer.Statuses[CloudServer.INDEX] = 200; + + if(lStat){ + if(lStat.isDirectory()) + Fs.readdir(DirPath,CloudServer._readDir); /* отдаём файл */ - else if(lStat.isFile()){ - + else if(lStat.isFile()){ Fs.readFile(DirPath,CloudServer.getReadFileFunc(DirPath)); console.log('reading file: '+DirPath); } - }catch(error){console.log(error);} + } } } }; From 782592a34bc0f5a93001f800a827531e8fae4835 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 1 Aug 2012 06:01:12 -0400 Subject: [PATCH 102/170] added loading image when file going to be edited --- ChangeLog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a3138af5..2c1420db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,7 +12,9 @@ * Added ability rename files. -* Fixed bug with CodeMirror vertical scroll bar +* Fixed bug with CodeMirror vertical scroll bar. + +* Added loading image when file going to be edited. 2012.07.27, Version 0.1.4 From 2c89597fc9ae7be94d2afe2364015e628c699eea Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 1 Aug 2012 10:37:52 -0400 Subject: [PATCH 103/170] changed statSync to async version --- .travis.yml | 1 - server.js | 53 +++++++++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index c9d0f66f..2b9c686d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ node_js: #- 0.4 #jshint fails to install (no gzip, jshint test not working out) - 0.6 - - 0.7 # development version of 0.8, may be unstable - 0.8 notifications: webhooks: diff --git a/server.js b/server.js index ff6b8249..62175388 100644 --- a/server.js +++ b/server.js @@ -387,20 +387,8 @@ CloudServer._controller=function(pReq, pRes) /* Проверяем с папкой ли мы имеем дело */ /* читаем сновные данные о файле */ - var lStat; - try{ - lStat=Fs.statSync(DirPath); - }catch(error){ - console.log(error); - - CloudServer.Statuses[DirPath] = 404; - - CloudServer.sendResponse('OK',error.toString(),DirPath); - } - /* если это каталог - - * читаем его содержимое - */ - + Fs.stat(DirPath, CloudServer._stated); + /* если установлено сжатие * меняем название html-файла и * загружаем сжатый html-файл в дальнейшем @@ -414,22 +402,39 @@ CloudServer._controller=function(pReq, pRes) */ CloudServer.Responses[CloudServer.INDEX]=pRes; CloudServer.Statuses[CloudServer.INDEX] = 200; + } + } +}; + +/* + * Function geted stat information about file + */ +CloudServer._stated = function(pError, pStat){ + if(pError){ + CloudServer.Statuses[DirPath] = 404; + CloudServer.sendResponse('OK',pError.toString(),DirPath); + + return; + } + + /* + * если это каталог - + * читаем его содержимое + */ - if(lStat){ - if(lStat.isDirectory()) - Fs.readdir(DirPath,CloudServer._readDir); - /* отдаём файл */ - else if(lStat.isFile()){ - Fs.readFile(DirPath,CloudServer.getReadFileFunc(DirPath)); - console.log('reading file: '+DirPath); - } - } + if(pStat){ + if(pStat.isDirectory()) + Fs.readdir(DirPath,CloudServer._readDir); + /* отдаём файл */ + else if(pStat.isFile()){ + Fs.readFile(DirPath,CloudServer.getReadFileFunc(DirPath)); + console.log('reading file: '+DirPath); } } }; /* Функция читает ссылку или выводит информацию об ошибке*/ -CloudServer._readDir=function (pError, pFiles) +CloudServer._readDir = function (pError, pFiles) { if(!pError) { From 57ca62acc8814129921fe0bec62dba03cbaf9af0 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 1 Aug 2012 10:53:10 -0400 Subject: [PATCH 104/170] changed sync reading of index.html to async --- server.js | 117 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/server.js b/server.js index 62175388..450ec74f 100644 --- a/server.js +++ b/server.js @@ -511,54 +511,21 @@ CloudServer._readDir = function (pError, pFiles) lList+=''; - try{ - var lIndex; - /* пробуем достать данные из кэша - * с жатием или без, взависимости - * от настроек - */ - var lFileData=CloudServer.Cache.get(CloudServer.INDEX); - /* если их нет там - вычитываем из файла*/ - if(!lFileData){ - lIndex=Fs.readFileSync(CloudServer.INDEX); - /* и сохраняем в кэш */ - CloudServer.Cache.set(CloudServer.INDEX,lIndex); - }else lIndex=lFileData; - - /* если выбрана опция минифизировать скрпиты - * меняем в index.html обычный client.js на - * минифицированый - */ - lIndex=lIndex.toString(); - - /* if scripts shoud be minified and - * minification proceed sucessfully - * we include minified version of - * clien.js to index.html - */ - lIndex = CloudServer.Minify._allowed.css? - lIndex.replace('','') - .replace('/css/style.css',CloudServer.Minify.MinFolder + 'all.min.css') - :lIndex; - - lIndex = CloudServer.Minify._allowed.js?lIndex.replace('client.js', - CloudServer.Minify.MinFolder + - 'client.min.js') - :lIndex; - - lIndex=lIndex.toString().replace('
', - '
'+lList); - - /* меняем title */ - lIndex=lIndex.replace('Cloud Commander', - ''+CloudFunc.setTitle()+''); - - /* отображаем панель быстрых клавишь */ - lList=lIndex; - - /* если браузер поддерживает gzip-сжатие*/ - lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); - }catch(error){console.log(error);} + + var lIndex; + /* пробуем достать данные из кэша + * с жатием или без, взависимости + * от настроек + */ + var lFileData=CloudServer.Cache.get(CloudServer.INDEX); + /* если их нет там - вычитываем из файла*/ + if(!lFileData) { + lIndex=Fs.readFile(CloudServer.INDEX, + CloudServer.indexReaded(lList)); + }else { + var lReaded_f = CloudServer.indexReaded(lList); + lReaded_f(false, lFileData); + } }else{ /* в обычном режиме(когда js включен * высылаем json-структуру файлов @@ -583,6 +550,60 @@ CloudServer._readDir = function (pError, pFiles) } }; +CloudServer.indexReaded = function(pList){ + return function(pError, pIndex){ + if(pError){ + return console.log(pError); + } + + /* и сохраняем в кэш */ + CloudServer.Cache.set(CloudServer.INDEX, pIndex); + + /* если выбрана опция минифизировать скрпиты + * меняем в index.html обычный client.js на + * минифицированый + */ + pIndex=pIndex.toString(); + + /* if scripts shoud be minified and + * minification proceed sucessfully + * we include minified version of + * clien.js to index.html + */ + pIndex = CloudServer.Minify._allowed.css? + pIndex.replace('','') + .replace('/css/style.css',CloudServer.Minify.MinFolder + 'all.min.css') + :pIndex; + + pIndex = CloudServer.Minify._allowed.js?pIndex.replace('client.js', + CloudServer.Minify.MinFolder + + 'client.min.js') + :pIndex; + + pIndex=pIndex.toString().replace('
', + '
'+pList); + + /* меняем title */ + pIndex=pIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + + /* отображаем панель быстрых клавишь */ + pList=pIndex; + + var lHeader; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(pList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,pList,CloudServer.INDEX); + }; +}; + /* Функция генерирует функцию считывания файла * таким образом, что бы у нас было * имя считываемого файла From 754274192a17b40e209ce50648cb3c190bb2af99 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 06:59:20 -0400 Subject: [PATCH 105/170] all sync functions changed to async equivalents --- server.js | 248 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 141 insertions(+), 107 deletions(-) diff --git a/server.js b/server.js index 450ec74f..143b155c 100644 --- a/server.js +++ b/server.js @@ -433,121 +433,154 @@ CloudServer._stated = function(pError, pStat){ } }; + /* Функция читает ссылку или выводит информацию об ошибке*/ CloudServer._readDir = function (pError, pFiles) { - if(!pError) + if(pError){ + console.log(pError); + CloudServer.sendResponse('OK',pError.toString(), + DirPath); + return; + } + + /* Если мы не в корне добавляем слеш к будующим ссылкам */ + if(DirPath !== '/') { - /* данные о файлах в формате JSON*/ - var lJSON=[]; - var lJSONFile={}; - /* Если мы не в корне добавляем слеш к будующим ссылкам */ - if(DirPath!=='/') - { - DirPath+='/'; - } + DirPath += '/'; + } - pFiles=pFiles.sort(); - - lJSON[0]={path:DirPath,size:'dir'}; - var fReturnFalse=function returnFalse(){return false;}; - for(var i=0;i', + pIndex = pIndex.toString().replace('
', '
'+pList); /* меняем title */ - pIndex=pIndex.replace('Cloud Commander', + pIndex = pIndex.replace('Cloud Commander', ''+CloudFunc.setTitle()+''); /* отображаем панель быстрых клавишь */ - pList=pIndex; + pList = pIndex; var lHeader; /* если браузер поддерживает gzip-сжатие*/ - lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + lHeader = CloudServer.generateHeaders('text/html',CloudServer.Gzip); /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip){ - Zlib.gzip(pList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + if(CloudServer.Gzip) { + Zlib.gzip(pList, + CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); } /* если не поддерживаеться - отсылаем данные без сжатия*/ else From 5a46cfd62461c812d56e032396a443d8079fd784 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 06:59:47 -0400 Subject: [PATCH 106/170] all sync functions changed to async equivalents --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2c1420db..1c2da1d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,8 @@ * Added loading image when file going to be edited. +* All sync functions changed to async equivalents. + 2012.07.27, Version 0.1.4 From 331134420317c446e9b1831ad90946f745f751e8 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 07:39:50 -0400 Subject: [PATCH 107/170] on f4 on folder CodeMirror opens json data of folder --- client.js | 4 ++-- lib/client/editor.js | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/client.js b/client.js index ce3e32da..c15d6101 100644 --- a/client.js +++ b/client.js @@ -495,7 +495,7 @@ CloudClient._changeLinks = function(pPanelID) if(a[i].target !== '_blank') { /* убираем адрес хоста*/ - var link='/'+a[i].href.replace(document.location.href,''); + var link='/'+a[i].href.replace(document.location.href,''); /* убираем значения, которые говорят, * об отсутствии js */ @@ -635,7 +635,7 @@ CloudClient._ajaxLoad=function(path, pNeedRefresh) /* переводим таблицу файлов в строку, для * сохранения в localStorage */ - var lJSON_s=JSON.stringify(data); + var lJSON_s = JSON.stringify(data); console.log(lJSON_s.length); /* если размер данных не очень бошьой diff --git a/lib/client/editor.js b/lib/client/editor.js index e2c07755..75938e47 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -1,4 +1,4 @@ -var CloudCommander, CodeMirror; +var CloudCommander, CloudFunc, CodeMirror; /* object contains editors CodeMirror * and later will be Ace */ @@ -86,11 +86,32 @@ CloudCommander.Editor.CodeMirror = { var lA; if(lCurrent.length){ lCurrent = lCurrent[0]; - - lA = lCurrent.getElementsByTagName('a'); + + /* getting link */ + lA = lCurrent.getElementsByTagName('a'); + if(!lA.length) + return console.log('Error:' + + 'can not find links in current file'); + + lA = lA[0].href; + /* убираем адрес хоста*/ + lA = '/' + lA.replace(document.location.href,''); + + /* checking is this link is to directory */ + var lSize = lCurrent.getElementsByClassName('size'); + if(lSize){ + lSize = lSize[0].textContent; - if(lA.length) - lA = lA[0].href; + /* if directory - load json + * not html data + */ + if (lSize === ''){ + if (lA.indexOf(CloudFunc.NOJS) === + CloudFunc.FS.length){ + lA = lA.replace(CloudFunc.NOJS, ''); + } + } + } } /* показываем гиф загрузки возле пути папки сверху*/ @@ -116,7 +137,11 @@ CloudCommander.Editor.CodeMirror = { console.log(jqXHR.responseText); }, - success:function(data, textStatus, jqXHR){ + success:function(data, textStatus, jqXHR){ + /* if we got json - show it */ + if(typeof data === 'object') + data = JSON.stringify(data); + initCodeMirror_f(data); CloudCommander.keyBinded = false; From b478dfa014d4f32c938bc0bbb6aa1308dc7dc01a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 07:40:49 -0400 Subject: [PATCH 108/170] on f4 on folder CodeMirror opens json data of folder --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1c2da1d4..5dd7709a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,9 @@ * All sync functions changed to async equivalents. +* On f4 key pressed when current-file is folder +CodeMirror opens json data of folder. + 2012.07.27, Version 0.1.4 From 3a25369152c96464e4b96f1b6095b8c1d95edc86 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 07:45:45 -0400 Subject: [PATCH 109/170] added json easy beautifier --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 75938e47..e7da9f7d 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -140,7 +140,7 @@ CloudCommander.Editor.CodeMirror = { success:function(data, textStatus, jqXHR){ /* if we got json - show it */ if(typeof data === 'object') - data = JSON.stringify(data); + data = JSON.stringify(data, null, 4); initCodeMirror_f(data); From 9a1f87b577fc17b31980ff56c226cba034e5ab6d Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 08:33:19 -0400 Subject: [PATCH 110/170] changed mode of CodeMirror to javascript --- config.json | 2 +- lib/client/editor.js | 6 +- .../editor/codemirror/mode/javascript.js | 361 ++++++++++++++++++ .../editor/codemirror/pack/javascript.pack.js | 1 + 4 files changed, 367 insertions(+), 3 deletions(-) create mode 100644 lib/client/editor/codemirror/mode/javascript.js create mode 100644 lib/client/editor/codemirror/pack/javascript.pack.js diff --git a/config.json b/config.json index d58f0b2d..4a0dccf7 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "cache" : {"allowed" : false}, "minification" : { - "js" : false, + "js" : true, "css" : true, "html" : true, "img" : true diff --git a/lib/client/editor.js b/lib/client/editor.js index e7da9f7d..6711cdd1 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -44,13 +44,15 @@ CloudCommander.Editor.CodeMirror = { '}' }); - CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js', + CloudCommander.jsload('lib/client/editor/' + + 'codemirror/pack/javascript.pack.js', createEditorDiv); }; }; /* load CodeMirror main module */ - CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js', + CloudCommander.jsload('lib/client/editor/' + + 'codemirror/pack/codemirror.pack.js', loadAll(this)); }), diff --git a/lib/client/editor/codemirror/mode/javascript.js b/lib/client/editor/codemirror/mode/javascript.js new file mode 100644 index 00000000..2c2819af --- /dev/null +++ b/lib/client/editor/codemirror/mode/javascript.js @@ -0,0 +1,361 @@ +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var jsonMode = parserConfig.json; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + return { + "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom + }; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function nextUntilUnescaped(stream, end) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next == end && !escaped) + return false; + escaped = !escaped && next == "\\"; + } + return escaped; + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + + function jsTokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") + return chain(stream, state, jsTokenString(ch)); + else if (/[\[\]{}\(\),;\:\.]/.test(ch)) + return ret(ch); + else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } + else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } + else if (ch == "/") { + if (stream.eat("*")) { + return chain(stream, state, jsTokenComment); + } + else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } + else if (state.reAllowed) { + nextUntilUnescaped(stream, "/"); + stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla + return ret("regexp", "string-2"); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", null, stream.current()); + } + } + else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", null, stream.current()); + } + else { + stream.eatWhile(/[\w\$_]/); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.kwAllowed) ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function jsTokenString(quote) { + return function(stream, state) { + if (!nextUntilUnescaped(stream, quote)) + state.tokenize = jsTokenBase; + return ret("string", "string"); + }; + } + + function jsTokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + var state = cx.state; + if (state.context) { + cx.marked = "def"; + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return; + state.localVars = {name: varname, next: state.localVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: {name: "arguments"}}; + function pushcontext() { + if (!cx.state.context) cx.state.localVars = defaultVars; + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state; + state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + return function expecting(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(arguments.callee); + }; + } + + function statement(type) { + if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), + poplex, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator); + if (type == "function") return cont(functiondef); + if (type == "keyword c") return cont(maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator); + if (type == "operator") return cont(expression); + if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator); + if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + + function maybeoperator(type, value) { + if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator); + if (type == "operator" || type == ":") return cont(expression); + if (type == ";") return; + if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator); + if (type == ".") return cont(property, maybeoperator); + if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator); + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperator, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type) { + if (type == "variable") cx.marked = "property"; + if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression); + } + function commasep(what, end) { + function proceed(type) { + if (type == ",") return cont(what, proceed); + if (type == end) return cont(); + return cont(expect(end)); + } + return function commaSeparated(type) { + if (type == end) return cont(); + else return pass(what, proceed); + }; + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function vardef1(type, value) { + if (type == "variable"){register(value); return cont(vardef2);} + return cont(); + } + function vardef2(type, value) { + if (value == "=") return cont(expression, vardef2); + if (type == ",") return cont(vardef1); + } + function forspec1(type) { + if (type == "var") return cont(vardef1, forspec2); + if (type == ";") return pass(forspec2); + if (type == "variable") return cont(formaybein); + return pass(forspec2); + } + function formaybein(type, value) { + if (value == "in") return cont(expression); + return cont(maybeoperator, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in") return cont(expression); + return cont(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext); + } + function funarg(type, value) { + if (type == "variable") {register(value); return cont();} + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: jsTokenBase, + reAllowed: true, + kwAllowed: true, + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: 0 + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/)); + state.kwAllowed = type != '.'; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize != jsTokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + if (type == "vardef") return lexical.indented + 4; + else 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(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricChars: ":{}" + }; +}); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); \ No newline at end of file diff --git a/lib/client/editor/codemirror/pack/javascript.pack.js b/lib/client/editor/codemirror/pack/javascript.pack.js new file mode 100644 index 00000000..e413ff7a --- /dev/null +++ b/lib/client/editor/codemirror/pack/javascript.pack.js @@ -0,0 +1 @@ +CodeMirror.defineMode("javascript",function(config,parserConfig){function chain(stream,state,f){return state.tokenize=f,f(stream,state)}function nextUntilUnescaped(stream,end){var escaped=!1,next;while((next=stream.next())!=null){if(next==end&&!escaped)return!1;escaped=!escaped&&next=="\\"}return escaped}function ret(tp,style,cont){return type=tp,content=cont,style}function jsTokenBase(stream,state){var ch=stream.next();if(ch=='"'||ch=="'")return chain(stream,state,jsTokenString(ch));if(/[\[\]{}\(\),;\:\.]/.test(ch))return ret(ch);if(ch=="0"&&stream.eat(/x/i))return stream.eatWhile(/[\da-f]/i),ret("number","number");if(/\d/.test(ch)||ch=="-"&&stream.eat(/\d/))return stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),ret("number","number");if(ch=="/")return stream.eat("*")?chain(stream,state,jsTokenComment):stream.eat("/")?(stream.skipToEnd(),ret("comment","comment")):state.reAllowed?(nextUntilUnescaped(stream,"/"),stream.eatWhile(/[gimy]/),ret("regexp","string-2")):(stream.eatWhile(isOperatorChar),ret("operator",null,stream.current()));if(ch=="#")return stream.skipToEnd(),ret("error","error");if(isOperatorChar.test(ch))return stream.eatWhile(isOperatorChar),ret("operator",null,stream.current());stream.eatWhile(/[\w\$_]/);var word=stream.current(),known=keywords.propertyIsEnumerable(word)&&keywords[word];return known&&state.kwAllowed?ret(known.type,known.style,word):ret("variable","variable",word)}function jsTokenString(quote){return function(stream,state){return nextUntilUnescaped(stream,quote)||(state.tokenize=jsTokenBase),ret("string","string")}}function jsTokenComment(stream,state){var maybeEnd=!1,ch;while(ch=stream.next()){if(ch=="/"&&maybeEnd){state.tokenize=jsTokenBase;break}maybeEnd=ch=="*"}return ret("comment","comment")}function JSLexical(indented,column,type,align,prev,info){this.indented=indented,this.column=column,this.type=type,this.prev=prev,this.info=info,align!=null&&(this.align=align)}function inScope(state,varname){for(var v=state.localVars;v;v=v.next)if(v.name==varname)return!0}function parseJS(state,style,type,content,stream){var cc=state.cc;cx.state=state,cx.stream=stream,cx.marked=null,cx.cc=cc,state.lexical.hasOwnProperty("align")||(state.lexical.align=!0);for(;;){var combinator=cc.length?cc.pop():jsonMode?expression:statement;if(combinator(type,content)){while(cc.length&&cc[cc.length-1].lex)cc.pop()();return cx.marked?cx.marked:type=="variable"&&inScope(state,content)?"variable-2":style}}}function pass(){for(var i=arguments.length-1;i>=0;i--)cx.cc.push(arguments[i])}function cont(){return pass.apply(null,arguments),!0}function register(varname){var state=cx.state;if(state.context){cx.marked="def";for(var v=state.localVars;v;v=v.next)if(v.name==varname)return;state.localVars={name:varname,next:state.localVars}}}function pushcontext(){cx.state.context||(cx.state.localVars=defaultVars),cx.state.context={prev:cx.state.context,vars:cx.state.localVars}}function popcontext(){cx.state.localVars=cx.state.context.vars,cx.state.context=cx.state.context.prev}function pushlex(type,info){var result=function(){var state=cx.state;state.lexical=new JSLexical(state.indented,cx.stream.column(),type,null,state.lexical,info)};return result.lex=!0,result}function poplex(){var state=cx.state;state.lexical.prev&&(state.lexical.type==")"&&(state.indented=state.lexical.indented),state.lexical=state.lexical.prev)}function expect(wanted){return function(type){return type==wanted?cont():wanted==";"?pass():cont(arguments.callee)}}function statement(type){return type=="var"?cont(pushlex("vardef"),vardef1,expect(";"),poplex):type=="keyword a"?cont(pushlex("form"),expression,statement,poplex):type=="keyword b"?cont(pushlex("form"),statement,poplex):type=="{"?cont(pushlex("}"),block,poplex):type==";"?cont():type=="function"?cont(functiondef):type=="for"?cont(pushlex("form"),expect("("),pushlex(")"),forspec1,expect(")"),poplex,statement,poplex):type=="variable"?cont(pushlex("stat"),maybelabel):type=="switch"?cont(pushlex("form"),expression,pushlex("}","switch"),expect("{"),block,poplex,poplex):type=="case"?cont(expression,expect(":")):type=="default"?cont(expect(":")):type=="catch"?cont(pushlex("form"),pushcontext,expect("("),funarg,expect(")"),statement,poplex,popcontext):pass(pushlex("stat"),expression,expect(";"),poplex)}function expression(type){return atomicTypes.hasOwnProperty(type)?cont(maybeoperator):type=="function"?cont(functiondef):type=="keyword c"?cont(maybeexpression):type=="("?cont(pushlex(")"),maybeexpression,expect(")"),poplex,maybeoperator):type=="operator"?cont(expression):type=="["?cont(pushlex("]"),commasep(expression,"]"),poplex,maybeoperator):type=="{"?cont(pushlex("}"),commasep(objprop,"}"),poplex,maybeoperator):cont()}function maybeexpression(type){return type.match(/[;\}\)\],]/)?pass():pass(expression)}function maybeoperator(type,value){if(type=="operator"&&/\+\+|--/.test(value))return cont(maybeoperator);if(type=="operator"||type==":")return cont(expression);if(type==";")return;if(type=="(")return cont(pushlex(")"),commasep(expression,")"),poplex,maybeoperator);if(type==".")return cont(property,maybeoperator);if(type=="[")return cont(pushlex("]"),expression,expect("]"),poplex,maybeoperator)}function maybelabel(type){return type==":"?cont(poplex,statement):pass(maybeoperator,expect(";"),poplex)}function property(type){if(type=="variable")return cx.marked="property",cont()}function objprop(type){type=="variable"&&(cx.marked="property");if(atomicTypes.hasOwnProperty(type))return cont(expect(":"),expression)}function commasep(what,end){function proceed(type){return type==","?cont(what,proceed):type==end?cont():cont(expect(end))}return function(type){return type==end?cont():pass(what,proceed)}}function block(type){return type=="}"?cont():pass(statement,block)}function vardef1(type,value){return type=="variable"?(register(value),cont(vardef2)):cont()}function vardef2(type,value){if(value=="=")return cont(expression,vardef2);if(type==",")return cont(vardef1)}function forspec1(type){return type=="var"?cont(vardef1,forspec2):type==";"?pass(forspec2):type=="variable"?cont(formaybein):pass(forspec2)}function formaybein(type,value){return value=="in"?cont(expression):cont(maybeoperator,forspec2)}function forspec2(type,value){return type==";"?cont(forspec3):value=="in"?cont(expression):cont(expression,expect(";"),forspec3)}function forspec3(type){type!=")"&&cont(expression)}function functiondef(type,value){if(type=="variable")return register(value),cont(functiondef);if(type=="(")return cont(pushlex(")"),pushcontext,commasep(funarg,")"),poplex,statement,popcontext)}function funarg(type,value){if(type=="variable")return register(value),cont()}var indentUnit=config.indentUnit,jsonMode=parserConfig.json,keywords=function(){function kw(type){return{type:type,style:"keyword"}}var A=kw("keyword a"),B=kw("keyword b"),C=kw("keyword c"),operator=kw("operator"),atom={type:"atom",style:"atom"};return{"if":A,"while":A,"with":A,"else":B,"do":B,"try":B,"finally":B,"return":C,"break":C,"continue":C,"new":C,"delete":C,"throw":C,"var":kw("var"),"const":kw("var"),let:kw("var"),"function":kw("function"),"catch":kw("catch"),"for":kw("for"),"switch":kw("switch"),"case":kw("case"),"default":kw("default"),"in":operator,"typeof":operator,"instanceof":operator,"true":atom,"false":atom,"null":atom,"undefined":atom,NaN:atom,Infinity:atom}}(),isOperatorChar=/[+\-*&%=<>!?|]/,type,content,atomicTypes={atom:!0,number:!0,variable:!0,string:!0,regexp:!0},cx={state:null,column:null,marked:null,cc:null},defaultVars={name:"this",next:{name:"arguments"}};return poplex.lex=!0,{startState:function(basecolumn){return{tokenize:jsTokenBase,reAllowed:!0,kwAllowed:!0,cc:[],lexical:new JSLexical((basecolumn||0)-indentUnit,0,"block",!1),localVars:parserConfig.localVars,context:parserConfig.localVars&&{vars:parserConfig.localVars},indented:0}},token:function(stream,state){stream.sol()&&(state.lexical.hasOwnProperty("align")||(state.lexical.align=!1),state.indented=stream.indentation());if(stream.eatSpace())return null;var style=state.tokenize(stream,state);return type=="comment"?style:(state.reAllowed=type=="operator"||type=="keyword c"||!!type.match(/^[\[{}\(,;:]$/),state.kwAllowed=type!=".",parseJS(state,style,type,content,stream))},indent:function(state,textAfter){if(state.tokenize!=jsTokenBase)return 0;var firstChar=textAfter&&textAfter.charAt(0),lexical=state.lexical;lexical.type=="stat"&&firstChar=="}"&&(lexical=lexical.prev);var type=lexical.type,closing=firstChar==type;return type=="vardef"?lexical.indented+4:type=="form"&&firstChar=="{"?lexical.indented:type=="stat"||type=="form"?lexical.indented+indentUnit:lexical.info=="switch"&&!closing?lexical.indented+(/^(?:case|default)\b/.test(textAfter)?indentUnit:2*indentUnit):lexical.align?lexical.column+(closing?0:1):lexical.indented+(closing?0:indentUnit)},electricChars:":{}"}}),CodeMirror.defineMIME("text/javascript","javascript"),CodeMirror.defineMIME("application/json",{name:"javascript",json:!0}) \ No newline at end of file From 1244dae73f037700c673f224a43a2e014c56496b Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 08:35:04 -0400 Subject: [PATCH 111/170] changed mode of CodeMirror to javascript --- lib/client/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/editor.js b/lib/client/editor.js index 6711cdd1..5af07bbf 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -65,7 +65,7 @@ CloudCommander.Editor.CodeMirror = { var lParent = this; var initCodeMirror_f = function(pValue){ CodeMirror(lCloudEditor,{ - mode : 'xml', + mode : 'javascript', value : pValue, theme : 'night', lineNumbers : true, From 47b7f3682495ab507014dff12c482135eeffc0a7 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 2 Aug 2012 10:05:09 -0400 Subject: [PATCH 112/170] added terminal files --- lib/client/editor.js | 2 +- lib/client/terminal.js | 76 ++ lib/client/terminal/README-v1.md | 107 +++ lib/client/terminal/README.md | 678 ++++++++++++++ lib/client/terminal/ansi.css | 172 ++++ lib/client/terminal/jqconsole.coffee | 1279 ++++++++++++++++++++++++++ 6 files changed, 2313 insertions(+), 1 deletion(-) create mode 100644 lib/client/terminal.js create mode 100644 lib/client/terminal/README-v1.md create mode 100644 lib/client/terminal/README.md create mode 100644 lib/client/terminal/ansi.css create mode 100644 lib/client/terminal/jqconsole.coffee diff --git a/lib/client/editor.js b/lib/client/editor.js index 5af07bbf..7f3ffefc 100644 --- a/lib/client/editor.js +++ b/lib/client/editor.js @@ -3,7 +3,7 @@ var CloudCommander, CloudFunc, CodeMirror; * and later will be Ace */ CloudCommander.Editor = {}; -CloudCommander.Editor.CodeMirror = { +CloudCommander.Editor.CodeMirror = { load: (function(pParent){ /* function loads CodeMirror js and css files */ /* function shows editor */ diff --git a/lib/client/terminal.js b/lib/client/terminal.js new file mode 100644 index 00000000..b5744602 --- /dev/null +++ b/lib/client/terminal.js @@ -0,0 +1,76 @@ +var CloudCommander, jqconsole; +/* object contains terminal jqconsole + */ +CloudCommander.Terminal = {}; +CloudCommander.Terminal.jqconsole = { + load: function(pParent){ + CloudCommander.cssLoad({ + src : 'lib/client/terminal/ansi.css' + }); + + CloudCommander.jsload({ + src : 'lib/client/terminal/jqconsole-2.7.min.js', + func : function(){ + pParent.init(); + } + }); + }, + + init: function(){ + $(function() { + // Creating the console. + var header = 'Welcome to JQConsole!\n' + + 'Use jqconsole.Write() to write and ' + + 'jqconsole.Input() to read.\n'; + window.jqconsole = $('#console').jqconsole(header, 'JS> '); + + // Abort prompt on Ctrl+Z. + jqconsole.RegisterShortcut('Z', function() { + jqconsole.AbortPrompt(); + handler(); + }); + + // Move to line start Ctrl+A. + jqconsole.RegisterShortcut('A', function() { + jqconsole.MoveToStart(); + handler(); + }); + + // Move to line end Ctrl+E. + jqconsole.RegisterShortcut('E', function() { + jqconsole.MoveToEnd(); + handler(); + }); + + jqconsole.RegisterMatching('{', '}', 'brace'); + jqconsole.RegisterMatching('(', ')', 'paran'); + jqconsole.RegisterMatching('[', ']', 'bracket'); + // Handle a command. + var handler = function(command) { + if (command) { + try { + jqconsole.Write('==> ' + window.eval(command) + '\n'); + } catch (e) { + jqconsole.Write('ERROR: ' + e.message + '\n'); + } + } + jqconsole.Prompt(true, handler, function(command) { + // Continue line if can't compile the command. + try { + Function(command); + } catch (e) { + if (/[\[\{\(]$/.test(command)) { + return 1; + } else { + return 0; + } + } + return false; + }); + }; + + // Initiate the first prompt. + handler(); + }); + } +}; \ No newline at end of file diff --git a/lib/client/terminal/README-v1.md b/lib/client/terminal/README-v1.md new file mode 100644 index 00000000..e9380537 --- /dev/null +++ b/lib/client/terminal/README-v1.md @@ -0,0 +1,107 @@ +#jq-console + +A simple jQuery terminal plugin written in CoffeeScript. + +This project was spawned because of our need for a simple web terminal plugin +for the jsREPL project. It +tries to simulate a low level terminal by providing (almost) raw input/output +streams as well as input and output states. + +##Tested Browsers + +The plugin has been tested on the following browsers: + +* IE 8 +* Chrome 10 +* Firefox 3.6 +* Safari 4 +* Opera 10 + +##Getting Started + +###Instantiating + + var jqconsole = $(div).jqconsole(welcomeString); + +* `div` is the div element or selector. +* `welcomeString` is the string to be shown when the terminal is first rendered. + +###Configuration + +There isn't much initial configuration needed, because the user must supply +options and callbacks with each state change. The only config method is used to +create custom shortcuts: + +* `jqconsole.RegisterShortcut`: Registers a callback for a keyboard shortcut. + It takes two arguments: + + * `int keyCode`: The code of the key pressing which (when Ctrl is held) will + trigger this shortcut. + + * `function callback`: A function called when the shortcut is pressed; + "this" will point to the JQConsole object. + + Example: + + // Ctrl+R: resets the console. + jqconsole.RegisterShortCut(82, function() { + this.Reset(); + }); + +##Usage + +Unlike most terminal plugins, jq-console gives you complete low-level control +over the execution; you have to call the appropriate methods to start input +or output: + +* `jqconsole.Input`: Asks user for input. It takes three arguments: + + * `bool history_enabled`: Whether this input should use history. If true, + the user can select the input from history, and their input will also be + added as a new history item. + + * `function result_callback`: A function called with the user's input when + the user presses Enter and the input operation is complete. + + * `function multiline_callback`: If specified, this function is called when + the user presses Enter to check whether the input should continue to the + next line. If this function returns a falsy value, the input operation + is completed. Otherwise, input continues and the cursor moves to the next + line. + + Example: + + jqconsole.Input(true, function(input) { + alert(input); + }, function (input) { + return /\\$/.test('asdasd \\'); + }); + +* `jqconsole.Write`: Writes the given text to the console in a ``, with an + optional class. This is used for output and writing prompt labels. It takes + two arguments: + + * `string text`: The text to write. + + * `string cls`: The class to give the span containing the text. Optional. + + Examples: + + jqconsole.Write('>>>', 'prompt') + jqconsole.Write(output, 'output') + jqconsole.Write(err.message, 'error') + +* `jqconsole.SetPromptText` Sets the text currently in the input prompt. Takes + only one parameter: + + * `string text`: The text to put in the prompt. + + Examples: + + jqconsole.SetPromptText('ls') + jqconsole.SetPromptText('print [i ** 2 for i in range(10)]') + +##Contributors + +[Max Shawabkeh](http://max99x.com/) +[Amjad Masad](http://twitter.com/amjad_masad) diff --git a/lib/client/terminal/README.md b/lib/client/terminal/README.md new file mode 100644 index 00000000..cf486c85 --- /dev/null +++ b/lib/client/terminal/README.md @@ -0,0 +1,678 @@ +#jq-console + +A jQuery terminal plugin written in CoffeeScript. + +This project was spawned because of our need for a simple web terminal plugin +for the repl.it project. It tries to simulate a low level terminal by providing (almost) +raw input/output streams as well as input and output states. + +Version 2.0 adds baked-in support for rich multi-line prompting and operation +queueing. + +NOTE: This info is for jq-console v2.0. For jq-console v1.0 see README-v1.md. + + +##Tested Browsers + +The plugin has been tested on the following browsers: + +* IE 9-10 +* Chrome 10-14 +* Firefox 3.6-6 +* Opera 11 + + +##Getting Started + +###Echo example + +```css + /* The console container element */ + #console { + position: absolute; + width: 400px; + height: 500px; + background-color:black; + } + /* The inner console element. */ + .jqconsole { + padding: 10px; + } + /* The cursor. */ + .jqconsole-cursor { + background-color: gray; + } + /* The cursor color when the console looses focus. */ + .jqconsole-blurred .jqconsole-cursor { + background-color: #666; + } + /* The current prompt text color */ + .jqconsole-prompt { + color: #0d0; + } + /* The command history */ + .jqconsole-old-prompt { + color: #0b0; + font-weight: normal; + } + /* The text color when in input mode. */ + .jqconsole-input { + color: #dd0; + } + /* Previously entered input. */ + .jqconsole-old-input { + color: #bb0; + font-weight: normal; + } + /* The text color of the output. */ + .jqconsole-output { + color: white; + } +``` + +```html +
+ + + +``` + + +###Instantiating + +```javascript + $(div).jqconsole(welcomeString, promptLabel, continueLabel); +``` + +* `div` is the div element or selector. Note that this element must be + explicity sized and positioned `absolute` or `relative`. +* `welcomeString` is the string to be shown when the terminal is first rendered. +* `promptLabel` is the label to be shown before the input when using Prompt(). +* `continueLabel` is the label to be shown before the continued lines of the + input when using Prompt(). + +##Configuration + +There isn't much initial configuration needed, because the user must supply +options and callbacks with each state change. There are a few config methods +provided to create custom shortcuts and change indentation width: + +###jqconsole.RegisterShortcut +Registers a callback for a keyboard shortcut. +Takes two arguments: + + * __(int|string)__ *keyCode*: The code of the key pressing which (when Ctrl is + held) will trigger this shortcut. If a string is provided, the ASCII code + of the first character is taken. + + * __function__ *callback*: A function called when the shortcut is pressed; + "this" will point to the JQConsole object. + + + Example: + + // Ctrl+R: resets the console. + jqconsole.RegisterShortcut('R', function() { + this.Reset(); + }); + +###jqconsole.SetIndentWidth +Sets the number of spaces inserted when indenting and removed when unindenting. +Takes one argument: + + * __int__ *width*: The code of the key pressing which (when Ctrl is held) will + trigger this shortcut. + + + Example: + + // Sets the indent width to 4 spaces. + jqconsole.SetIndentWidth(4); + +###jqconsole.RegisterMatching +Registers an opening and closing characters to match and wraps each of the +opening and closing characters with a span with the specified class. +Takes one parameters: + + * __char__ *open*: The opening character of a "block". + * __char__ *close*: The closing character of a "block". + * __string__ *class*: The css class that is applied to the matched characters. + + + Example: + + jqconsole.RegisterMatching('{', '}', 'brackets'); + +##Usage + +Unlike most terminal plugins, jq-console gives you complete low-level control +over the execution; you have to call the appropriate methods to start input +or output: + +###jqconsole.Input: +Asks user for input. If another input or prompt operation is currently underway, +the new input operation is enqueued and will be called when the current +operation and all previously enqueued operations finish. Takes one argument: + + * __function__ *input_callback*: A function called with the user's input when + the user presses Enter and the input operation is complete. + + + Example: + + // Echo the input. + jqconsole.Input(function(input) { + jqconsole.Write(input); + }); + + +###jqconsole.Prompt +Asks user for input. If another input or prompt operation is currently underway +the new prompt operation is enqueued and will be called when the current +peration and all previously enqueued operations finish. Takes three arguments: + + * __bool__ *history_enabled*: Whether this input should use history. If true, + the user can select the input from history, and their input will also be + added as a new history item. + + * __function__ *result_callback*: A function called with the user's input when + the user presses Enter and the prompt operation is complete. + + * __function__ *multiline_callback*: If specified, this function is called when + the user presses Enter to check whether the input should continue to the + next line. The function must return one of the following values: + + * `false`: the input operation is completed. + + * `0`: the input continues to the next line with the current indent. + + * `N` (int): the input continues to the next line, and the current + indent is adjusted by `N`, e.g. `-2` to unindent two levels. + + + * __bool__ *async_multiline*: Whether the multiline callback function should + be treated as an asynchronous operation and be passed a continuation + function that should be called with one of the return values mentioned + above: `false`/`0`/`N`. + + + Example: + + jqconsole.Prompt(true, function(input) { + // Alert the user with the command. + alert(input); + }, function (input) { + // Continue if the last character is a backslash. + return /\\$/.test(input); + }); + +###jqconsole.AbortPrompt +Aborts the current prompt operation and returns to output mode or the next +queued input/prompt operation. Takes no arguments. + + Example: + + jqconsole.Prompt(true, function(input) { + alert(input); + }); + // Give the user 2 seconds to enter the command. + setTimeout(function() { + jqconsole.AbortPrompt(); + }, 2000); + +###jqconsole.Write +Writes the given text to the console in a ``, with an +optional class. If a prompt is currently being shown, the text is inserted +before it. Takes two arguments: + + * __string__ *text*: The text to write. + + * __string__ *cls*: The class to give the span containing the text. Optional. + + * __bool__ *escape*: Whether the text to write should be html escaped. + Optional, defaults to true. + + + Examples: + + jqconsole.Write(output, 'my-output-class') + jqconsole.Write(err.message, 'my-error-class') + + +###jqconsole.SetPromptText +Sets the text currently in the input prompt. Takes one parameter: + + * __string__ *text*: The text to put in the prompt. + + Examples: + + jqconsole.SetPromptText('ls') + jqconsole.SetPromptText('print [i ** 2 for i in range(10)]') + + +###jqconsole.ClearPromptText +Clears all the text currently in the input prompt. Takes one parameter: + + * __bool__ *clear_label*: If specified and true, also clears the main prompt + label (e.g. ">>>"). + + + Example: + + jqconsole.ClearPromptText() + + +###jqconsole.GetPromptText +Returns the contents of the prompt. Takes one parameter: + + * __bool__ *full*: If specified and true, also includes the prompt labels + (e.g. ">>>"). + + + Examples: + + var currentCommand = jqconsole.GetPromptText() + var logEntry = jqconsole.GetPromptText(true) + + +###jqconsole.Reset +Resets the console to its initial state, cancelling all current and pending +operations. Takes no parameters. + + Example: + + jqconsole.Reset() + + +###jqconsole.GetColumn +Returns the 0-based number of the column on which the cursor currently is. +Takes no parameters. + + Example: + + // Show the current line and column in a status area. + $('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn()) + + +###jqconsole.GetLine +Returns the 0-based number of the line on which the cursor currently is. +Takes no parameters. + + Example: + + // Show the current line and column in a status area. + $('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn()) + +###jqconsole.Focus +Forces the focus onto the console so events can be captured. +Takes no parameters. + + Example: + + // Redirect focus to the console whenever the user clicks anywhere. + $(window).click(function() { + jqconsole.Focus(); + }) + + +###jqconsole.GetIndentWidth +Returns the number of spaces inserted when indenting. Takes no parameters. + + Example: + + jqconsole.SetIndentWidth(4); + console.assert(jqconsole.GetIndentWidth() == 4); + + +###jqconsole.UnRegisterMatching +Deletes a certain matching settings set by `jqconsole.RegisterMatching`. +Takes two paramaters: + + * __char__ *open*: The opening character of a "block". + * __char__ *close*: The closing character of a "block". + + + Example: + + jqconsole.UnRegisterMatching('{', '}'); + + +###jqconsole.Dump +Returns the text content of the console. + +###jqconsole.GetState +Returns the current state of the console. Could be one of the following: + + * Input: `"input"` + * Output: `"output"` + * Prompt: `"prompt"` + + + Example: + + jqconsole.GetState(); //output + + +###jqconsole.MoveToStart +Moves the cursor to the start of the current line. +Takes one parameter: + + * __bool__ *all_lines*: If true moves the cursor to the beginning of the first + line in the current prompt. Defaults to false. + + + Example: + + // Move to line start Ctrl+A. + jqconsole.RegisterShortcut('A', function() { + jqconsole.MoveToStart(); + handler(); + }); + + +###jqconsole.MoveToEnd +Moves the cursor to the end of the current line. +Takes one parameter: + + * __bool__ *all_lines*: If true moves the cursor to the end of the first + line in the current prompt. Defaults to false. + + Example: + + // Move to line end Ctrl+E. + jqconsole.RegisterShortcut('E', function() { + jqconsole.MoveToEnd(); + handler(); + }); + +###jqconsole.Disable +Disables input and focus on the console. + + +###jqconsole.Enable +Enables input and focus on the console. + + +###jqconsole.IsDisabled +Returns true if the console is disabled. + + +###jqconsole.ResetHistory +Resets the console history. + + +###jqconsole.ResetMatchings +Resets the character matching configuration. + + +###jqconsole.ResetShortcuts +Resets the shortcut configuration. + + +##Default Key Config + +The console responds to the followind keys and key combinations by default: + +* `Delete`: Delete the following character. +* `Ctrl+Delete`: Delete the following word. +* `Backspace`: Delete the preceding character. +* `Ctrl+Backspace`: Delete the preceding word. +* `Ctrl+Left`: Move one word to the left. +* `Ctrl+Right`: Move one word to the right. +* `Home`: Move to the beginning of the current line. +* `Ctrl+Home`: Move to the beginnig of the first line. +* `End`: Move to the end of the current line. +* `Ctrl+End`: Move to the end of the last line. +* `Shift+Up`, `Ctrl+Up`: Move cursor to the line above the current one. +* `Shift+Down`, `Ctrl+Down`: Move cursor to the line below the current one. +* `Tab`: Indent. +* `Shift+Tab`: Unindent. +* `Up`: Previous history item. +* `Down`: Next history item. +* `Enter`: Finish input/prompt operation. See Input() and Prompt() for details. +* `Shift+Enter`: New line. +* `Page Up`: Scroll console one page up. +* `Page Down`: Scroll console one page down. + +##ANSI escape code SGR support + +jq-console implements a large subset of the ANSI escape code graphics. +Using the `.Write` method you could add style to the console using +the following syntax: + +`ASCII 27 (decimal) or 0x1b (hex)` `[` `SGR code` `m` + +Example: + + jqconsole.Write('\033[31mRed Text'); + +Note that the third parameter `escape` must be true which defaults to it. + +You'll need to include the `ansi.css` file for default effects or create your +own using the css classes from the table below. + +###SGR +[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#graphics). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeEffectClass
0Reset / Normal
1Bold`jqconsole-ansi-bold`
2Faint`jqconsole-ansi-lighter`
3Italic`jqconsole-ansi-italic`
4Line below text`jqconsole-ansi-underline`
5Blink: 1s delay`jqconsole-ansi-blink`
6Blink: 0.5s delay`jqconsole-ansi-blink-rapid`
8Hide text`jqconsole-ansi-hidden`
9Line through text`jqconsole-ansi-line-through`
10Remove all fonts
11-19Add custom font`jqconsole-ansi-fonts-{N}` where N is code - 10
20Add Fraktur font (not implemented in ansi.css)`jqconsole-ansi-fraktur`
21Remove Bold and Faint effects
22Same as 21
23Remove italic and fraktur effects
24Remove underline effect
25Remove blinking effect(s).
28Reveal text
29Remove line-through effect
30-37Set foreground color to color from the color table belowjqconsole-ansi-color-{COLOR} where {COLOR} is the color name
39Restore default foreground color
40-47Set background color to color from the color table below`jqconsole-ansi-background-color-{COLOR}` where {COLOR} is the color name
49Restore default background color
51Adds a frame around the text`jqconsole-ansi-framed`
53Line above textjqconsole-ansi-overline
54Remove frame effect
55Remove over-line effect
+ +###Colors +[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Code offsetColor
0Black
1Red
2Green
3Yellow
4Blue
5Magenta
6Cyan
7White
+ +##CSS Classes + +Several CSS classes are provided to help stylize the console: + +* `jqconsole`: The main console container. +* `jqconsole, jqconsole-blurred`: The main console container, when not in focus. +* `jqconsole-cursor`: The cursor. +* `jqconsole-header`: The welcome message at the top of the console. +* `jqconsole-input`: The prompt area during input. May have multiple lines. +* `jqconsole-old-input`: Previously-entered inputs. +* `jqconsole-prompt`: The prompt area during prompting. May have multiple lines. +* `jqconsole-old-prompt`: Previously-entered prompts. +* `jqconsole-composition`: The div encapsulating the composition of multi-byte + characters. + + +Of course, custom classes may be specified when using `jqconsole.Write()` for +further customization. + + +##Contributors + +[Max Shawabkeh](http://max99x.com/) +[Amjad Masad](http://twitter.com/amjad_masad) diff --git a/lib/client/terminal/ansi.css b/lib/client/terminal/ansi.css new file mode 100644 index 00000000..296cfc60 --- /dev/null +++ b/lib/client/terminal/ansi.css @@ -0,0 +1,172 @@ +.jqconsole-ansi-bold { + font-weight: bold!important; +} + +.jqconsole-ansi-lighter { + font-weight: lighter!important; +} + +.jqconsole-ansi-italic { + font-style: italic!important; +} + +.jqconsole-ansi-underline { + text-decoration: underline!important; +} + +@-webkit-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-moz-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-ms-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-o-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +.jqconsole-ansi-blink { + -webkit-animation-name: blinker; + -moz-animation-name: blinker; + -ms-animation-name: blinker; + -o-animation-name: blinker; + -webkit-animation-iteration-count: infinite; + -moz-animation-iteration-count: infinite; + -ms-animation-iteration-count: infinite; + -o-animation-iteration-count: infinite; + -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -o-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + -o-animation-duration: 1s; + -ms-animation-duration: 1s; +} + +.jqconsole-ansi-blink-rapid { + -webkit-animation-name: blinker; + -moz-animation-name: blinker; + -ms-animation-name: blinker; + -o-animation-name: blinker; + -webkit-animation-iteration-count: infinite; + -moz-animation-iteration-count: infinite; + -ms-animation-iteration-count: infinite; + -o-animation-iteration-count: infinite; + -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -o-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -webkit-animation-duration: 0.5s; + -moz-animation-duration: 0.5s; + -o-animation-duration: 0.5s; + -ms-animation-duration: 0.5s; +} + + +.jqconsole-ansi-hidden { + visibility:hidden!important; +} + +.jqconsole-ansi-line-through { + text-decoration: line-through; +} + +.jqconsole-ansi-fonts-1 { + +} +.jqconsole-ansi-fonts-2 { + +} +.jqconsole-ansi-fonts-3 { + +} +.jqconsole-ansi-fonts-4 { + +} +.jqconsole-ansi-fonts-5 { + +} +.jqconsole-ansi-fonts-6 { + +} +.jqconsole-ansi-fonts-7 { + +} +.jqconsole-ansi-fonts-8 { + +} +.jqconsole-ansi-fonts-9 { + +} + +.jqconsole-ansi-fraktur { + +} + +.jqconsole-ansi-color-black { + color: black!important; +} +.jqconsole-ansi-color-red { + color: red!important; +} +.jqconsole-ansi-color-green { + color: green!important; +} +.jqconsole-ansi-color-yellow { + color: yellow!important; +} +.jqconsole-ansi-color-blue { + color: blue!important; +} +.jqconsole-ansi-color-magenta { + color: magenta!important; +} +.jqconsole-ansi-color-cyan { + color: cyan!important; +} +.jqconsole-ansi-color-white { + color: white!important; +} + +.jqconsole-ansi-background-color-black { + background-color: black!important; +} +.jqconsole-ansi-background-color-red { + background-color: red!important; +} +.jqconsole-ansi-background-color-green { + background-color: green!important; +} +.jqconsole-ansi-background-color-yellow { + background-color: yellow!important; +} +.jqconsole-ansi-background-color-blue { + background-color: blue!important; +} +.jqconsole-ansi-background-color-magenta { + background-color: magenta!important; +} +.jqconsole-ansi-background-color-cyan { + background-color: cyan!important; +} +.jqconsole-ansi-background-color-white { + background-color: white!important; +} + +.jqconsole-ansi-framed { + border: 1px solid!important; +} +.jqconsole-ansi-overline { + text-decoration: overline!important; +} + diff --git a/lib/client/terminal/jqconsole.coffee b/lib/client/terminal/jqconsole.coffee new file mode 100644 index 00000000..c0a76c16 --- /dev/null +++ b/lib/client/terminal/jqconsole.coffee @@ -0,0 +1,1279 @@ +### +Copyrights 2011, the repl.it project. +Licensed under the MIT license +### + +# Shorthand for jQuery. +$ = jQuery + +# The states in which the console can be. +STATE_INPUT = 0 +STATE_OUTPUT = 1 +STATE_PROMPT = 2 + +# Key code values. +KEY_ENTER = 13 +KEY_TAB = 9 +KEY_DELETE = 46 +KEY_BACKSPACE = 8 +KEY_LEFT = 37 +KEY_RIGHT = 39 +KEY_UP = 38 +KEY_DOWN = 40 +KEY_HOME = 36 +KEY_END = 35 +KEY_PAGE_UP = 33 +KEY_PAGE_DOWN = 34 + +# CSS classes +CLASS_PREFIX = 'jqconsole-' +CLASS_CURSOR = "#{CLASS_PREFIX}cursor" +CLASS_HEADER = "#{CLASS_PREFIX}header" +CLASS_PROMPT = "#{CLASS_PREFIX}prompt" +CLASS_OLD_PROMPT = "#{CLASS_PREFIX}old-prompt" +CLASS_INPUT = "#{CLASS_PREFIX}input" +CLASS_BLURRED = "#{CLASS_PREFIX}blurred" + +# Frequently used string literals +E_KEYPRESS = 'keypress' +EMPTY_SPAN = '' +EMPTY_DIV = '
' +EMPTY_SELECTOR = ':empty' +NEWLINE = '\n' + +# Default prompt text for main and continuation prompts. +DEFAULT_PROMPT_LABEL = '>>> ' +DEFAULT_PROMPT_CONINUE_LABEL = '... ' + +# The default number of spaces inserted when indenting. +DEFAULT_INDENT_WIDTH = 2 + +CLASS_ANSI = "#{CLASS_PREFIX}ansi-" +ESCAPE_CHAR = '\033' +ESCAPE_SYNTAX = /\[(\d*)(?:;(\d*))*m/ + +class Ansi + COLORS: ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] + + constructor: -> + @klasses = []; + + _append: (klass) => + klass = "#{CLASS_ANSI}#{klass}" + if @klasses.indexOf(klass) is -1 + @klasses.push klass + + _remove: (klasses...) => + for klass in klasses + if klass in ['fonts', 'color', 'background-color'] + @klasses = (cls for cls in @klasses when cls.indexOf(klass) isnt CLASS_ANSI.length) + else + klass = "#{CLASS_ANSI}#{klass}" + @klasses = (cls for cls in @klasses when cls isnt klass) + + _color: (i) => @COLORS[i] + + _style: (code) => + code = 0 if code == '' + code = parseInt code + + return if isNaN code + + switch code + when 0 then @klasses = [] + when 1 then @_append 'bold' + when 2 then @_append 'lighter' + when 3 then @_append 'italic' + when 4 then @_append 'underline' + when 5 then @_append 'blink' + when 6 then @_append 'blink-rapid' + when 8 then @_append 'hidden' + when 9 then @_append 'line-through' + when 10 then @_remove 'fonts' + when 11,12,13,14,15,16,17,18,19 + @_append "fonts-#{code - 10}" + when 20 then @_append 'fraktur' + when 21 then @_remove 'bold', 'lighter' + when 22 then @_remove 'bold', 'lighter' + when 23 then @_remove 'italic', 'fraktur' + when 24 then @_remove 'underline' + when 25 then @_remove 'blink', 'blink-rapid' + when 28 then @_remove 'hidden' + when 29 then @_remove 'line-through' + when 30,31,32,33,34,35,36,37 + @_append 'color-' + @_color code - 30 + when 39 then @_remove 'color' + when 40,41,42,43,44,45,46,47 + @_append 'background-color-' + @_color code - 40 + when 49 then @_remove 'background-color' + when 51 then @_append 'framed' + when 53 then @_append 'overline' + when 54 then @_remove 'framed' + when 55 then @_remove 'overline' + + getClasses: => @klasses.join ' ' + + _openSpan: (text) => "#{text}" + _closeSpan: (text) => "#{text}" + + stylize: (text) => + text = @_openSpan text + + i = 0 + while (i = text.indexOf(ESCAPE_CHAR ,i)) and i isnt -1 + if d = text[i...].match ESCAPE_SYNTAX + @_style code for code in d[1...] + text = @_closeSpan(text[0...i]) + @_openSpan text[i + 1 + d[0].length...] + else i++ + + return @_closeSpan text + +# Helper functions +spanHtml = (klass, content) -> "#{content or ''}" + +class JQConsole + # Creates a console. + # @arg container: The DOM element into which the console is inserted. + # @arg header: Text to print at the top of the console on reset. Optional. + # Defaults to an empty string. + # @arg prompt_label: The label to show before the command prompt. Optional. + # Defaults to DEFAULT_PROMPT_LABEL. + # @arg prompt_continue: The label to show before continuation lines of the + # command prompt. Optional. Defaults to DEFAULT_PROMPT_CONINUE_LABEL. + constructor: (@container, header, prompt_label, prompt_continue_label) -> + # Mobile devices supported sniff. + @isMobile = !!navigator.userAgent.match /iPhone|iPad|iPod|Android/i + @isIos = !!navigator.userAgent.match /iPhone|iPad|iPod/i + @isAndroid = !!navigator.userAgent.match /Android/i + + @$window = $(window) + + # The header written when the console is reset. + @header = header or '' + + # The prompt label used by Prompt(). + @prompt_label_main = prompt_label or DEFAULT_PROMPT_LABEL + @prompt_label_continue = ' \n' + (prompt_continue_label or + DEFAULT_PROMPT_CONINUE_LABEL) + + # How many spaces are inserted when a tab character is pressed. + @indent_width = DEFAULT_INDENT_WIDTH + + # By default, the console is in the output state. + @state = STATE_OUTPUT + + # A queue of input/prompt operations waiting to be called. The items are + # bound functions ready to be called. + @input_queue = [] + + # The function to call when input is accepted. Valid only in + # input/prompt mode. + @input_callback = null + # The function to call to determine whether the input should continue to the + # next line. + @multiline_callback = null + + # A table of all "recorded" inputs given so far. + @history = [] + # The index of the currently selected history item. If this is past the end + # of @history, then the user has not selected a history item. + @history_index = 0 + # The command which the user was typing before browsing history. Keeping + # track of this allows us to restore the user's command if they browse the + # history then decide to go back to what they were typing. + @history_new = '' + # Whether the current input operation is using history. + @history_active = false + + # A table of custom shortcuts, mapping character codes to callbacks. + @shortcuts = {} + + # The main console area. Everything else happens inside this. + @$console = $('
').appendTo @container
+    @$console.css 
+      position: 'absolute'
+      top: 0
+      bottom: 0
+      right: 0
+      left: 0
+      margin: 0
+      overflow: 'auto'
+
+    # Whether the console currently has focus.
+    @$console_focused = true
+    
+    # On screen somehow invisible textbox for input.
+    # Copied from codemirror2, this works for both mobile and desktop browsers.
+    @$input_container = $(EMPTY_DIV).appendTo @container
+    @$input_container.css
+      position: 'relative'
+      width: 1
+      height: 0
+      overflow: 'hidden'
+    @$input_source = $('