Вход Регистрация
Файл: usr/plugins/highlight_code/codemirror.js
Строк: 1040
<?php
/* CodeMirror main module (http://codemirror.net/)
 *
 * Implements the CodeMirror constructor and prototype, which take care
 * of initializing the editor frame, and providing the outside interface.
 */

// The CodeMirrorConfig object is used to specify a default
// configuration. If you specify such an object before loading this
// file, the values you put into it will override the defaults given
// below. You can also assign to it after loading.
var CodeMirrorConfig = window.CodeMirrorConfig || {};

var 
CodeMirror = (function(){
  function 
setDefaults(object, defaults) {
    for (var 
option in defaults) {
      if (!
object.hasOwnProperty(option))
        
object[option] = defaults[option];
    }
  }
  function forEach(array, 
action) {
    for (var 
i = 0; i < array.length; i++)
      
action(array[i]);
  }

  
// These default options can be overridden by passing a set of
  // options to a specific CodeMirror constructor. See manual.html for
  // their meaning.
  
setDefaults(CodeMirrorConfig, {
    
stylesheet: [],
    
path: "",
    
parserfile: [],
    
basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"],
    
iframeClass: null,
    
passDelay: 200,
    
passTime: 50,
    
lineNumberDelay: 200,
    
lineNumberTime: 50,
    
continuousScanning: false,
    
saveFunction: null,
    
onChange: null,
    
undoDepth: 50,
    
undoDelay: 800,
    
disableSpellcheck: true,
    
textWrapping: true,
    
readOnly: false,
    
width: "",
    
height: "300px",
    
minHeight: 100,
    
autoMatchParens: false,
    
parserConfig: null,
    
tabMode: "indent", // or "spaces", "default", "shift"
    
enterMode: "indent", // or "keep", "flat"
    
electricChars: true,
    
reindentOnLoad: false,
    
activeTokens: null,
    
cursorActivity: null,
    
lineNumbers: false,
    
firstLineNumber: 1,
    
indentUnit: 2,
    
domain: null
  
});

  function 
addLineNumberDiv(container, firstNum) {
    var 
nums = document.createElement("DIV"),
        
scroller = document.createElement("DIV");
    
nums.style.position = "absolute";
    
nums.style.height = "100%";
    if (
nums.style.setExpression) {
      try {
nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
      catch(
e) {} // Seems to throw 'Not Implemented' on some IE8 versions
    
}
    
nums.style.top = "0px";
    
nums.style.left = "0px";
    
nums.style.overflow = "hidden";
    
container.appendChild(nums);
    
scroller.className = "CodeMirror-line-numbers";
    
nums.appendChild(scroller);
    
scroller.innerHTML = "<div>" + firstNum + "</div>";
    return 
nums;
  }

  function 
frameHTML(options) {
    if (
typeof options.parserfile == "string")
      
options.parserfile = [options.parserfile];
    if (
typeof options.basefiles == "string")
      
options.basefiles = [options.basefiles];
    if (
typeof options.stylesheet == "string")
      
options.stylesheet = [options.stylesheet];

    var 
html = ["<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head>"];
    // Hack to work around a bunch of IE8-specific problems.
    
html.push("<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>");
    forEach(
options.stylesheet, function(file) {
      
html.push("<link rel="stylesheet" type="text/css" href="" + file + ""/>");
    });
    forEach(
options.basefiles.concat(options.parserfile), function(file) {
      if (!/^
https?:/.test(file)) file = options.path + file;
      
html.push("<script type="text/javascript" src="" + file + ""><" + "/script>");
    });
    
html.push("</head><body style="border-width: 0;" class="editbox" spellcheck="" +
              (options.disableSpellcheck ? "
false" : "true") + ""></body></html>");
    return 
html.join("");
  }

  var 
internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);

  function 
CodeMirror(place, options) {
    
// Use passed options, if any, to override defaults.
    
this.options = options = options || {};
    
setDefaults(options, CodeMirrorConfig);

    
// Backward compatibility for deprecated options.
    
if (options.dumbTabs) options.tabMode = "spaces";
    else if (
options.normalTab) options.tabMode = "default";

    var 
frame = this.frame = document.createElement("IFRAME");
    if (
options.iframeClass) frame.className = options.iframeClass;
    
frame.frameBorder = 0;
    
frame.style.border = "0";
    
frame.style.width = '100%';
    
frame.style.height = '100%';
    
// display: block occasionally suppresses some Firefox bugs, so we
    // always add it, redundant as it sounds.
    
frame.style.display = "block";

    var 
div = this.wrapping = document.createElement("DIV");
    
div.style.position = "relative";
    
div.className = "CodeMirror-wrapping";
    
div.style.width = options.width;
    
div.style.height = (options.height == "dynamic") ? options.minHeight + "px" : options.height;
    
// This is used by Editor.reroutePasteEvent
    
var teHack = this.textareaHack = document.createElement("TEXTAREA");
    
div.appendChild(teHack);
    
teHack.style.position = "absolute";
    
teHack.style.left = "-10000px";
    
teHack.style.width = "10px";

    
// Link back to this object, so that the editor can fetch options
    // and add a reference to itself.
    
frame.CodeMirror = this;
    if (
options.domain && internetExplorer) {
      
this.html = frameHTML(options);
      
frame.src = "javascript:(function(){document.open();" +
        (
options.domain ? "document.domain="" + options.domain + "";" : "") +
        
"document.write(window.frameElement.CodeMirror.html);document.close();})()";
    }
    else {
      
frame.src = "javascript:;";
    }

    if (
place.appendChild) place.appendChild(div);
    else 
place(div);
    
div.appendChild(frame);
    if (
options.lineNumbers) this.lineNumbers = addLineNumberDiv(div, options.firstLineNumber);

    
this.win = frame.contentWindow;
    if (!
options.domain || !internetExplorer) {
      
this.win.document.open();
      
this.win.document.write(frameHTML(options));
      
this.win.document.close();
    }
  }

  
CodeMirror.prototype = {
    
init: function() {
      if (
this.options.initCallback) this.options.initCallback(this);
      if (
this.options.lineNumbers) this.activateLineNumbers();
      if (
this.options.reindentOnLoad) this.reindent();
      if (
this.options.height == "dynamic") this.setDynamicHeight();
    },

    
getCode: function() {return this.editor.getCode();},
    
setCode: function(code) {this.editor.importCode(code);},
    
selection: function() {this.focusIfIE(); return this.editor.selectedText();},
    
reindent: function() {this.editor.reindent();},
    
reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},

    
focusIfIE: function() {
      
// in IE, a lot of selection-related functionality only works when the frame is focused
      
if (this.win.select.ie_selection) this.focus();
    },
    
focus: function() {
      
this.win.focus();
      if (
this.editor.selectionSnapshot) // IE hack
        
this.win.select.setBookmark(this.win.document.body, this.editor.selectionSnapshot);
    },
    
replaceSelection: function(text) {
      
this.focus();
      
this.editor.replaceSelection(text);
      return 
true;
    },
    
replaceChars: function(text, start, end) {
      
this.editor.replaceChars(text, start, end);
    },
    
getSearchCursor: function(string, fromCursor, caseFold) {
      return 
this.editor.getSearchCursor(string, fromCursor, caseFold);
    },

    
undo: function() {this.editor.history.undo();},
    
redo: function() {this.editor.history.redo();},
    
historySize: function() {return this.editor.history.historySize();},
    
clearHistory: function() {this.editor.history.clear();},

    
grabKeys: function(callback, filter) {this.editor.grabKeys(callback, filter);},
    
ungrabKeys: function() {this.editor.ungrabKeys();},

    
setParser: function(name, parserConfig) {this.editor.setParser(name, parserConfig);},
    
setSpellcheck: function(on) {this.win.document.body.spellcheck = on;},
    
setStylesheet: function(names) {
      if (
typeof names === "string") names = [names];
      var 
activeStylesheets = {};
      var 
matchedNames = {};
      var 
links = this.win.document.getElementsByTagName("link");
      
// Create hashes of active stylesheets and matched names.
      // This is O(n^2) but n is expected to be very small.
      
for (var x = 0, link; link = links[x]; x++) {
        if (
link.rel.indexOf("stylesheet") !== -1) {
          for (var 
y = 0; y < names.length; y++) {
            var 
name = names[y];
            if (
link.href.substring(link.href.length - name.length) === name) {
              
activeStylesheets[link.href] = true;
              
matchedNames[name] = true;
            }
          }
        }
      }
      
// Activate the selected stylesheets and disable the rest.
      
for (var x = 0, link; link = links[x]; x++) {
        if (
link.rel.indexOf("stylesheet") !== -1) {
          
link.disabled = !(link.href in activeStylesheets);
        }
      }
      
// Create any new stylesheets.
      
for (var y = 0; y < names.length; y++) {
        var 
name = names[y];
        if (!(
name in matchedNames)) {
          var 
link = this.win.document.createElement("link");
          
link.rel = "stylesheet";
          
link.type = "text/css";
          
link.href = name;
          
this.win.document.getElementsByTagName('head')[0].appendChild(link);
        }
      }
    },
    
setTextWrapping: function(on) {
      if (
on == this.options.textWrapping) return;
      
this.win.document.body.style.whiteSpace = on ? "" : "nowrap";
      
this.options.textWrapping = on;
      if (
this.lineNumbers) {
        
this.setLineNumbers(false);
        
this.setLineNumbers(true);
      }
    },
    
setIndentUnit: function(unit) {this.win.indentUnit = unit;},
    
setUndoDepth: function(depth) {this.editor.history.maxDepth = depth;},
    
setTabMode: function(mode) {this.options.tabMode = mode;},
    
setEnterMode: function(mode) {this.options.enterMode = mode;},
    
setLineNumbers: function(on) {
      if (
on && !this.lineNumbers) {
        
this.lineNumbers = addLineNumberDiv(this.wrapping);
        
this.activateLineNumbers();
      }
      else if (!
on && this.lineNumbers) {
        
this.wrapping.removeChild(this.lineNumbers);
        
this.wrapping.style.marginLeft = "";
        
this.lineNumbers = null;
      }
    },

    
cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
    
firstLine: function() {return this.editor.firstLine();},
    
lastLine: function() {return this.editor.lastLine();},
    
nextLine: function(line) {return this.editor.nextLine(line);},
    
prevLine: function(line) {return this.editor.prevLine(line);},
    
lineContent: function(line) {return this.editor.lineContent(line);},
    
setLineContent: function(line, content) {this.editor.setLineContent(line, content);},
    
removeLine: function(line){this.editor.removeLine(line);},
    
insertIntoLine: function(line, position, content) {this.editor.insertIntoLine(line, position, content);},
    
selectLines: function(startLine, startOffset, endLine, endOffset) {
      
this.win.focus();
      
this.editor.selectLines(startLine, startOffset, endLine, endOffset);
    },
    
nthLine: function(n) {
      var 
line = this.firstLine();
      for (; 
n > 1 && line !== false; n--)
        
line = this.nextLine(line);
      return 
line;
    },
    
lineNumber: function(line) {
      var 
num = 0;
      while (
line !== false) {
        
num++;
        
line = this.prevLine(line);
      }
      return 
num;
    },
    
jumpToLine: function(line) {
      if (
typeof line == "number") line = this.nthLine(line);
      
this.selectLines(line, 0);
      
this.win.focus();
    },
    
currentLine: function() { // Deprecated, but still there for backward compatibility
      
return this.lineNumber(this.cursorLine());
    },
    
cursorLine: function() {
      return 
this.cursorPosition().line;
    },
    
cursorCoords: function(start) {return this.editor.cursorCoords(start);},

    
activateLineNumbers: function() {
      var 
frame = this.frame, win = frame.contentWindow, doc = win.document, body = doc.body,
          
nums = this.lineNumbers, scroller = nums.firstChild, self = this;
      var 
barWidth = null;

      function 
sizeBar() {
        if (
frame.offsetWidth == 0) return;
        for (var 
root = frame; root.parentNode; root = root.parentNode){}
        if (!
nums.parentNode || root != document || !win.Editor) {
          
// Clear event handlers (their nodes might already be collected, so try/catch)
          
try{clear();}catch(e){}
          
clearInterval(sizeInterval);
          return;
        }

        if (
nums.offsetWidth != barWidth) {
          
barWidth = nums.offsetWidth;
          
frame.parentNode.style.paddingLeft = barWidth + "px";
        }
      }
      function 
doScroll() {
        
nums.scrollTop = body.scrollTop || doc.documentElement.scrollTop || 0;
      }
      
// Cleanup function, registered by nonWrapping and wrapping.
      
var clear = function(){};
      
sizeBar();
      var 
sizeInterval = setInterval(sizeBar, 500);

      function 
ensureEnoughLineNumbers(fill) {
        var 
lineHeight = scroller.firstChild.offsetHeight;
        if (
lineHeight == 0) return;
        var 
targetHeight = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0)),
            
lastNumber = Math.ceil(targetHeight / lineHeight);
        for (var 
i = scroller.childNodes.length; i <= lastNumber; i++) {
          var 
div = document.createElement("DIV");
          
div.appendChild(document.createTextNode(fill ? String(i + self.options.firstLineNumber) : "u00a0"));
          
scroller.appendChild(div);
        }
      }

      function 
nonWrapping() {
        function 
update() {
          
ensureEnoughLineNumbers(true);
          
doScroll();
        }
        
self.updateNumbers = update;
        var 
onScroll = win.addEventHandler(win, "scroll", doScroll, true),
            
onResize = win.addEventHandler(win, "resize", update, true);
        
clear = function(){
          
onScroll(); onResize();
          if (
self.updateNumbers == update) self.updateNumbers = null;
        };
        
update();
      }

      function 
wrapping() {
        var 
node, lineNum, next, pos, changes = [], styleNums = self.options.styleNumbers;

        function 
setNum(n, node) {
          
// Does not typically happen (but can, if you mess with the
          // document during the numbering)
          
if (!lineNum) lineNum = scroller.appendChild(document.createElement("DIV"));
          if (
styleNums) styleNums(lineNum, node, n);
          
// Changes are accumulated, so that the document layout
          // doesn't have to be recomputed during the pass
          
changes.push(lineNum); changes.push(n);
          
pos = lineNum.offsetHeight + lineNum.offsetTop;
          
lineNum = lineNum.nextSibling;
        }
        function 
commitChanges() {
          for (var 
i = 0; i < changes.length; i += 2)
            
changes[i].innerHTML = changes[i + 1];
          
changes = [];
        }
        function 
work() {
          if (!
scroller.parentNode || scroller.parentNode != self.lineNumbers) return;

          var 
endTime = new Date().getTime() + self.options.lineNumberTime;
          while (
node) {
            
setNum(next++, node.previousSibling);
            for (; 
node && !win.isBR(node); node = node.nextSibling) {
              var 
bott = node.offsetTop + node.offsetHeight;
              while (
scroller.offsetHeight && bott - 3 > pos) setNum("&nbsp;");
            }
            if (
node) node = node.nextSibling;
            if (new 
Date().getTime() > endTime) {
              
commitChanges();
              
pending = setTimeout(work, self.options.lineNumberDelay);
              return;
            }
          }
          while (
lineNum) setNum(next++);
          
commitChanges();
          
doScroll();
        }
        function 
start(firstTime) {
          
doScroll();
          
ensureEnoughLineNumbers(firstTime);
          
node = body.firstChild;
          
lineNum = scroller.firstChild;
          
pos = 0;
          
next = self.options.firstLineNumber;
          
work();
        }

        
start(true);
        var 
pending = null;
        function 
update() {
          if (
pending) clearTimeout(pending);
          if (
self.editor.allClean()) start();
          else 
pending = setTimeout(update, 200);
        }
        
self.updateNumbers = update;
        var 
onScroll = win.addEventHandler(win, "scroll", doScroll, true),
            
onResize = win.addEventHandler(win, "resize", update, true);
        
clear = function(){
          if (
pending) clearTimeout(pending);
          if (
self.updateNumbers == update) self.updateNumbers = null;
          
onScroll();
          
onResize();
        };
      }
      (
this.options.textWrapping || this.options.styleNumbers ? wrapping : nonWrapping)();
    },

    
setDynamicHeight: function() {
      var 
self = this, activity = self.options.cursorActivity, win = self.win, body = win.document.body,
          
lineHeight = null, timeout = null, vmargin = 2 * self.frame.offsetTop;
      
body.style.overflowY = "hidden";
      
win.document.documentElement.style.overflowY = "hidden";
      
this.frame.scrolling = "no";

      function 
updateHeight() {
        var 
trailingLines = 0, node = body.lastChild, computedHeight;
        while (
node && win.isBR(node)) {
          if (!
node.hackBR) trailingLines++;
          
node = node.previousSibling;
        }
        if (
node) {
          
lineHeight = node.offsetHeight;
          
computedHeight = node.offsetTop + (1 + trailingLines) * lineHeight;
        }
        else if (
lineHeight) {
          
computedHeight = trailingLines * lineHeight;
        }
        if (
computedHeight)
          
self.wrapping.style.height = Math.max(vmargin + computedHeight, self.options.minHeight) + "px";
      }
      
setTimeout(updateHeight, 300);
      
self.options.cursorActivity = function(x) {
        if (
activity) activity(x);
        
clearTimeout(timeout);
        
timeout = setTimeout(updateHeight, 100);
      };
    }
  };

  
CodeMirror.InvalidLineHandle = {toString: function(){return "CodeMirror.InvalidLineHandle";}};

  
CodeMirror.replace = function(element) {
    if (
typeof element == "string")
      
element = document.getElementById(element);
    return function(
newElement) {
      
element.parentNode.replaceChild(newElement, element);
    };
  };

  
CodeMirror.fromTextArea = function(area, options) {
    if (
typeof area == "string")
      
area = document.getElementById(area);

    
options = options || {};
    if (
area.style.width && options.width == null)
      
options.width = area.style.width;
    if (
area.style.height && options.height == null)
      
options.height = area.style.height;
    if (
options.content == null) options.content = area.value;

    if (
area.form) {
      function 
updateField() {
        
area.value = mirror.getCode();
      }
      if (
typeof area.form.addEventListener == "function")
        
area.form.addEventListener("submit", updateField, false);
      else
        
area.form.attachEvent("onsubmit", updateField);
      var 
realSubmit = area.form.submit;
      function 
wrapSubmit() {
        
updateField();
        
// Can't use realSubmit.apply because IE6 is too stupid
        
area.form.submit = realSubmit;
        
area.form.submit();
        
area.form.submit = wrapSubmit;
      }
      
area.form.submit = wrapSubmit;
    }

    function 
insert(frame) {
      if (
area.nextSibling)
        
area.parentNode.insertBefore(frame, area.nextSibling);
      else
        
area.parentNode.appendChild(frame);
    }

    
area.style.display = "none";
    var 
mirror = new CodeMirror(insert, options);
    
mirror.toTextArea = function() {
      
area.parentNode.removeChild(mirror.wrapping);
      
area.style.display = "";
      if (
area.form) {
        
area.form.submit = realSubmit;
        if (
typeof area.form.removeEventListener == "function")
          
area.form.removeEventListener("submit", updateField, false);
        else
          
area.form.detachEvent("onsubmit", updateField);
      }
    };

    return 
mirror;
  };

  
CodeMirror.isProbablySupported = function() {
    
// This is rather awful, but can be useful.
    
var match;
    if (
window.opera)
      return 
Number(window.opera.version()) >= 9.52;
    else if (/
Apple Computers, Inc/.test(navigator.vendor) && (match = navigator.userAgent.match(/Version/(d+(?:.d+)?)./)))
      return 
Number(match[1]) >= 3;
    else if (
document.selection && window.ActiveXObject && (match = navigator.userAgent.match(/MSIE (d+(?:.d*)?)b/)))
      return 
Number(match[1]) >= 6;
    else if (
match = navigator.userAgent.match(/gecko/(d{8})/i))
      return 
Number(match[1]) >= 20050901;
    else if (
match = navigator.userAgent.match(/AppleWebKit/(d+)/))
      return 
Number(match[1]) >= 525;
    else
      return 
null;
  };

  return 
CodeMirror;
})();
?>
Онлайн: 2
Реклама