Joomla! PHP Cross Reference Web Portals

Source: /media/editors/codemirror/js/codemirror-uncompressed.js - 590 lines - 22612 bytes - Summary - Text - Print

   1  /* CodeMirror main module (http://codemirror.net/)
   2   *
   3   * Implements the CodeMirror constructor and prototype, which take care
   4   * of initializing the editor frame, and providing the outside interface.
   5   */
   6  
   7  // The CodeMirrorConfig object is used to specify a default
   8  // configuration. If you specify such an object before loading this
   9  // file, the values you put into it will override the defaults given
  10  // below. You can also assign to it after loading.
  11  var CodeMirrorConfig = window.CodeMirrorConfig || {};
  12  
  13  var CodeMirror = (function(){
  14    function setDefaults(object, defaults) {
  15      for (var option in defaults) {
  16        if (!object.hasOwnProperty(option))
  17          object[option] = defaults[option];
  18      }
  19    }
  20    function forEach(array, action) {
  21      for (var i = 0; i < array.length; i++)
  22        action(array[i]);
  23    }
  24    function createHTMLElement(el) {
  25      if (document.createElementNS && document.documentElement.namespaceURI !== null)
  26        return document.createElementNS("http://www.w3.org/1999/xhtml", el)
  27      else
  28        return document.createElement(el)
  29    }
  30  
  31    // These default options can be overridden by passing a set of
  32    // options to a specific CodeMirror constructor. See manual.html for
  33    // their meaning.
  34    setDefaults(CodeMirrorConfig, {
  35      stylesheet: [],
  36      path: "",
  37      parserfile: [],
  38      basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"],
  39      iframeClass: null,
  40      passDelay: 200,
  41      passTime: 50,
  42      lineNumberDelay: 200,
  43      lineNumberTime: 50,
  44      continuousScanning: false,
  45      saveFunction: null,
  46      onLoad: null,
  47      onChange: null,
  48      undoDepth: 50,
  49      undoDelay: 800,
  50      disableSpellcheck: true,
  51      textWrapping: true,
  52      readOnly: false,
  53      width: "",
  54      height: "300px",
  55      minHeight: 100,
  56      onDynamicHeightChange: null,
  57      autoMatchParens: false,
  58      markParen: null,
  59      unmarkParen: null,
  60      parserConfig: null,
  61      tabMode: "indent", // or "spaces", "default", "shift"
  62      enterMode: "indent", // or "keep", "flat"
  63      electricChars: true,
  64      reindentOnLoad: false,
  65      activeTokens: null,
  66      onCursorActivity: null,
  67      lineNumbers: false,
  68      firstLineNumber: 1,
  69      onLineNumberClick: null,
  70      indentUnit: 2,
  71      domain: null,
  72      noScriptCaching: false,
  73      incrementalLoading: false
  74    });
  75  
  76    function addLineNumberDiv(container, firstNum) {
  77      var nums = createHTMLElement("div"),
  78          scroller = createHTMLElement("div");
  79      nums.style.position = "absolute";
  80      nums.style.height = "100%";
  81      if (nums.style.setExpression) {
  82        try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
  83        catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions
  84      }
  85      nums.style.top = "0px";
  86      nums.style.left = "0px";
  87      nums.style.overflow = "hidden";
  88      container.appendChild(nums);
  89      scroller.className = "CodeMirror-line-numbers";
  90      nums.appendChild(scroller);
  91      scroller.innerHTML = "<div>" + firstNum + "</div>";
  92      return nums;
  93    }
  94  
  95    function frameHTML(options) {
  96      if (typeof options.parserfile == "string")
  97        options.parserfile = [options.parserfile];
  98      if (typeof options.basefiles == "string")
  99        options.basefiles = [options.basefiles];
 100      if (typeof options.stylesheet == "string")
 101        options.stylesheet = [options.stylesheet];
 102  
 103      var sp = " spellcheck=\"" + (options.disableSpellcheck ? "false" : "true") + "\"";
 104      var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html" + sp + "><head>"];
 105      // Hack to work around a bunch of IE8-specific problems.
 106      html.push("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE7\"/>");
 107      var queryStr = options.noScriptCaching ? "?nocache=" + new Date().getTime().toString(16) : "";
 108      forEach(options.stylesheet, function(file) {
 109        html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + queryStr + "\"/>");
 110      });
 111      forEach(options.basefiles.concat(options.parserfile), function(file) {
 112        if (!/^https?:/.test(file)) file = options.path + file;
 113        html.push("<script type=\"text/javascript\" src=\"" + file + queryStr + "\"><" + "/script>");
 114      });
 115      html.push("</head><body style=\"border-width: 0;\" class=\"editbox\"" + sp + "></body></html>");
 116      return html.join("");
 117    }
 118  
 119    var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
 120  
 121    function CodeMirror(place, options) {
 122      // Use passed options, if any, to override defaults.
 123      this.options = options = options || {};
 124      setDefaults(options, CodeMirrorConfig);
 125  
 126      // Backward compatibility for deprecated options.
 127      if (options.dumbTabs) options.tabMode = "spaces";
 128      else if (options.normalTab) options.tabMode = "default";
 129      if (options.cursorActivity) options.onCursorActivity = options.cursorActivity;
 130  
 131      var frame = this.frame = createHTMLElement("iframe");
 132      if (options.iframeClass) frame.className = options.iframeClass;
 133      frame.frameBorder = 0;
 134      frame.style.border = "0";
 135      frame.style.width = '100%';
 136      frame.style.height = '100%';
 137      // display: block occasionally suppresses some Firefox bugs, so we
 138      // always add it, redundant as it sounds.
 139      frame.style.display = "block";
 140  
 141      var div = this.wrapping = createHTMLElement("div");
 142      div.style.position = "relative";
 143      div.className = "CodeMirror-wrapping";
 144      div.style.width = options.width;
 145      div.style.height = (options.height == "dynamic") ? options.minHeight + "px" : options.height;
 146      // This is used by Editor.reroutePasteEvent
 147      var teHack = this.textareaHack = createHTMLElement("textarea");
 148      div.appendChild(teHack);
 149      teHack.style.position = "absolute";
 150      teHack.style.left = "-10000px";
 151      teHack.style.width = "10px";
 152      teHack.tabIndex = 100000;
 153  
 154      // Link back to this object, so that the editor can fetch options
 155      // and add a reference to itself.
 156      frame.CodeMirror = this;
 157      if (options.domain && internetExplorer) {
 158        this.html = frameHTML(options);
 159        frame.src = "javascript:(function(){document.open();" +
 160          (options.domain ? "document.domain=\"" + options.domain + "\";" : "") +
 161          "document.write(window.frameElement.CodeMirror.html);document.close();})()";
 162      }
 163      else {
 164        frame.src = "javascript:;";
 165      }
 166  
 167      if (place.appendChild) place.appendChild(div);
 168      else place(div);
 169      div.appendChild(frame);
 170      if (options.lineNumbers) this.lineNumbers = addLineNumberDiv(div, options.firstLineNumber);
 171  
 172      this.win = frame.contentWindow;
 173      if (!options.domain || !internetExplorer) {
 174        this.win.document.open();
 175        this.win.document.write(frameHTML(options));
 176        this.win.document.close();
 177      }
 178    }
 179  
 180    CodeMirror.prototype = {
 181      init: function() {
 182        // Deprecated, but still supported.
 183        if (this.options.initCallback) this.options.initCallback(this);
 184        if (this.options.onLoad) this.options.onLoad(this);
 185        if (this.options.lineNumbers) this.activateLineNumbers();
 186        if (this.options.reindentOnLoad) this.reindent();
 187        if (this.options.height == "dynamic") this.setDynamicHeight();
 188      },
 189  
 190      getCode: function() {return this.editor.getCode();},
 191      setCode: function(code) {this.editor.importCode(code);},
 192      selection: function() {this.focusIfIE(); return this.editor.selectedText();},
 193      reindent: function() {this.editor.reindent();},
 194      reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},
 195  
 196      focusIfIE: function() {
 197        // in IE, a lot of selection-related functionality only works when the frame is focused
 198        if (this.win.select.ie_selection && document.activeElement != this.frame)
 199          this.focus();
 200      },
 201      focus: function() {
 202        this.win.focus();
 203        if (this.editor.selectionSnapshot) // IE hack
 204          this.win.select.setBookmark(this.win.document.body, this.editor.selectionSnapshot);
 205      },
 206      replaceSelection: function(text) {
 207        this.focus();
 208        this.editor.replaceSelection(text);
 209        return true;
 210      },
 211      replaceChars: function(text, start, end) {
 212        this.editor.replaceChars(text, start, end);
 213      },
 214      getSearchCursor: function(string, fromCursor, caseFold) {
 215        return this.editor.getSearchCursor(string, fromCursor, caseFold);
 216      },
 217  
 218      undo: function() {this.editor.history.undo();},
 219      redo: function() {this.editor.history.redo();},
 220      historySize: function() {return this.editor.history.historySize();},
 221      clearHistory: function() {this.editor.history.clear();},
 222  
 223      grabKeys: function(callback, filter) {this.editor.grabKeys(callback, filter);},
 224      ungrabKeys: function() {this.editor.ungrabKeys();},
 225  
 226      setParser: function(name, parserConfig) {this.editor.setParser(name, parserConfig);},
 227      setSpellcheck: function(on) {this.win.document.body.spellcheck = on;},
 228      setStylesheet: function(names) {
 229        if (typeof names === "string") names = [names];
 230        var activeStylesheets = {};
 231        var matchedNames = {};
 232        var links = this.win.document.getElementsByTagName("link");
 233        // Create hashes of active stylesheets and matched names.
 234        // This is O(n^2) but n is expected to be very small.
 235        for (var x = 0, link; link = links[x]; x++) {
 236          if (link.rel.indexOf("stylesheet") !== -1) {
 237            for (var y = 0; y < names.length; y++) {
 238              var name = names[y];
 239              if (link.href.substring(link.href.length - name.length) === name) {
 240                activeStylesheets[link.href] = true;
 241                matchedNames[name] = true;
 242              }
 243            }
 244          }
 245        }
 246        // Activate the selected stylesheets and disable the rest.
 247        for (var x = 0, link; link = links[x]; x++) {
 248          if (link.rel.indexOf("stylesheet") !== -1) {
 249            link.disabled = !(link.href in activeStylesheets);
 250          }
 251        }
 252        // Create any new stylesheets.
 253        for (var y = 0; y < names.length; y++) {
 254          var name = names[y];
 255          if (!(name in matchedNames)) {
 256            var link = this.win.document.createElement("link");
 257            link.rel = "stylesheet";
 258            link.type = "text/css";
 259            link.href = name;
 260            this.win.document.getElementsByTagName('head')[0].appendChild(link);
 261          }
 262        }
 263      },
 264      setTextWrapping: function(on) {
 265        if (on == this.options.textWrapping) return;
 266        this.win.document.body.style.whiteSpace = on ? "" : "nowrap";
 267        this.options.textWrapping = on;
 268        if (this.lineNumbers) {
 269          this.setLineNumbers(false);
 270          this.setLineNumbers(true);
 271        }
 272      },
 273      setIndentUnit: function(unit) {this.win.indentUnit = unit;},
 274      setUndoDepth: function(depth) {this.editor.history.maxDepth = depth;},
 275      setTabMode: function(mode) {this.options.tabMode = mode;},
 276      setEnterMode: function(mode) {this.options.enterMode = mode;},
 277      setLineNumbers: function(on) {
 278        if (on && !this.lineNumbers) {
 279          this.lineNumbers = addLineNumberDiv(this.wrapping,this.options.firstLineNumber);
 280          this.activateLineNumbers();
 281        }
 282        else if (!on && this.lineNumbers) {
 283          this.wrapping.removeChild(this.lineNumbers);
 284          this.wrapping.style.paddingLeft = "";
 285          this.lineNumbers = null;
 286        }
 287      },
 288  
 289      cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
 290      firstLine: function() {return this.editor.firstLine();},
 291      lastLine: function() {return this.editor.lastLine();},
 292      nextLine: function(line) {return this.editor.nextLine(line);},
 293      prevLine: function(line) {return this.editor.prevLine(line);},
 294      lineContent: function(line) {return this.editor.lineContent(line);},
 295      setLineContent: function(line, content) {this.editor.setLineContent(line, content);},
 296      removeLine: function(line){this.editor.removeLine(line);},
 297      insertIntoLine: function(line, position, content) {this.editor.insertIntoLine(line, position, content);},
 298      selectLines: function(startLine, startOffset, endLine, endOffset) {
 299        this.win.focus();
 300        this.editor.selectLines(startLine, startOffset, endLine, endOffset);
 301      },
 302      nthLine: function(n) {
 303        var line = this.firstLine();
 304        for (; n > 1 && line !== false; n--)
 305          line = this.nextLine(line);
 306        return line;
 307      },
 308      lineNumber: function(line) {
 309        var num = 0;
 310        while (line !== false) {
 311          num++;
 312          line = this.prevLine(line);
 313        }
 314        return num;
 315      },
 316      jumpToLine: function(line) {
 317        if (typeof line == "number") line = this.nthLine(line);
 318        this.selectLines(line, 0);
 319        this.win.focus();
 320      },
 321      currentLine: function() { // Deprecated, but still there for backward compatibility
 322        return this.lineNumber(this.cursorLine());
 323      },
 324      cursorLine: function() {
 325        return this.cursorPosition().line;
 326      },
 327      cursorCoords: function(start) {return this.editor.cursorCoords(start);},
 328  
 329      activateLineNumbers: function() {
 330        var frame = this.frame, win = frame.contentWindow, doc = win.document, body = doc.body,
 331            nums = this.lineNumbers, scroller = nums.firstChild, self = this;
 332        var barWidth = null;
 333  
 334        nums.onclick = function(e) {
 335          var handler = self.options.onLineNumberClick;
 336          if (handler) {
 337            var div = (e || window.event).target || (e || window.event).srcElement;
 338            var num = div == nums ? NaN : Number(div.innerHTML);
 339            if (!isNaN(num)) handler(num, div);
 340          }
 341        };
 342  
 343        function sizeBar() {
 344          if (frame.offsetWidth == 0) return;
 345          for (var root = frame; root.parentNode; root = root.parentNode){}
 346          if (!nums.parentNode || root != document || !win.Editor) {
 347            // Clear event handlers (their nodes might already be collected, so try/catch)
 348            try{clear();}catch(e){}
 349            clearInterval(sizeInterval);
 350            return;
 351          }
 352  
 353          if (nums.offsetWidth != barWidth) {
 354            barWidth = nums.offsetWidth;
 355            frame.parentNode.style.paddingLeft = barWidth + "px";
 356          }
 357        }
 358        function doScroll() {
 359          nums.scrollTop = body.scrollTop || doc.documentElement.scrollTop || 0;
 360        }
 361        // Cleanup function, registered by nonWrapping and wrapping.
 362        var clear = function(){};
 363        sizeBar();
 364        var sizeInterval = setInterval(sizeBar, 500);
 365  
 366        function ensureEnoughLineNumbers(fill) {
 367          var lineHeight = scroller.firstChild.offsetHeight;
 368          if (lineHeight == 0) return;
 369          var targetHeight = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0)),
 370              lastNumber = Math.ceil(targetHeight / lineHeight);
 371          for (var i = scroller.childNodes.length; i <= lastNumber; i++) {
 372            var div = createHTMLElement("div");
 373            div.appendChild(document.createTextNode(fill ? String(i + self.options.firstLineNumber) : "\u00a0"));
 374            scroller.appendChild(div);
 375          }
 376        }
 377  
 378        function nonWrapping() {
 379          function update() {
 380            ensureEnoughLineNumbers(true);
 381            doScroll();
 382          }
 383          self.updateNumbers = update;
 384          var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
 385              onResize = win.addEventHandler(win, "resize", update, true);
 386          clear = function(){
 387            onScroll(); onResize();
 388            if (self.updateNumbers == update) self.updateNumbers = null;
 389          };
 390          update();
 391        }
 392  
 393        function wrapping() {
 394          var node, lineNum, next, pos, changes = [], styleNums = self.options.styleNumbers;
 395  
 396          function setNum(n, node) {
 397            // Does not typically happen (but can, if you mess with the
 398            // document during the numbering)
 399            if (!lineNum) lineNum = scroller.appendChild(createHTMLElement("div"));
 400            if (styleNums) styleNums(lineNum, node, n);
 401            // Changes are accumulated, so that the document layout
 402            // doesn't have to be recomputed during the pass
 403            changes.push(lineNum); changes.push(n);
 404            pos = lineNum.offsetHeight + lineNum.offsetTop;
 405            lineNum = lineNum.nextSibling;
 406          }
 407          function commitChanges() {
 408            for (var i = 0; i < changes.length; i += 2)
 409              changes[i].innerHTML = changes[i + 1];
 410            changes = [];
 411          }
 412          function work() {
 413            if (!scroller.parentNode || scroller.parentNode != self.lineNumbers) return;
 414  
 415            var endTime = new Date().getTime() + self.options.lineNumberTime;
 416            while (node) {
 417              setNum(next++, node.previousSibling);
 418              for (; node && !win.isBR(node); node = node.nextSibling) {
 419                var bott = node.offsetTop + node.offsetHeight;
 420                while (scroller.offsetHeight && bott - 3 > pos) {
 421                  var oldPos = pos;
 422                  setNum("&nbsp;");
 423                  if (pos <= oldPos) break;
 424                }
 425              }
 426              if (node) node = node.nextSibling;
 427              if (new Date().getTime() > endTime) {
 428                commitChanges();
 429                pending = setTimeout(work, self.options.lineNumberDelay);
 430                return;
 431              }
 432            }
 433            while (lineNum) setNum(next++);
 434            commitChanges();
 435            doScroll();
 436          }
 437          function start(firstTime) {
 438            doScroll();
 439            ensureEnoughLineNumbers(firstTime);
 440            node = body.firstChild;
 441            lineNum = scroller.firstChild;
 442            pos = 0;
 443            next = self.options.firstLineNumber;
 444            work();
 445          }
 446  
 447          start(true);
 448          var pending = null;
 449          function update() {
 450            if (pending) clearTimeout(pending);
 451            if (self.editor.allClean()) start();
 452            else pending = setTimeout(update, 200);
 453          }
 454          self.updateNumbers = update;
 455          var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
 456              onResize = win.addEventHandler(win, "resize", update, true);
 457          clear = function(){
 458            if (pending) clearTimeout(pending);
 459            if (self.updateNumbers == update) self.updateNumbers = null;
 460            onScroll();
 461            onResize();
 462          };
 463        }
 464        (this.options.textWrapping || this.options.styleNumbers ? wrapping : nonWrapping)();
 465      },
 466  
 467      setDynamicHeight: function() {
 468        var self = this, activity = self.options.onCursorActivity, win = self.win, body = win.document.body,
 469            lineHeight = null, timeout = null, vmargin = 2 * self.frame.offsetTop;
 470        body.style.overflowY = "hidden";
 471        win.document.documentElement.style.overflowY = "hidden";
 472        this.frame.scrolling = "no";
 473  
 474        function updateHeight() {
 475          var trailingLines = 0, node = body.lastChild, computedHeight;
 476          while (node && win.isBR(node)) {
 477            if (!node.hackBR) trailingLines++;
 478            node = node.previousSibling;
 479          }
 480          if (node) {
 481            lineHeight = node.offsetHeight;
 482            computedHeight = node.offsetTop + (1 + trailingLines) * lineHeight;
 483          }
 484          else if (lineHeight) {
 485            computedHeight = trailingLines * lineHeight;
 486          }
 487          if (computedHeight) {
 488            if (self.options.onDynamicHeightChange)
 489              computedHeight = self.options.onDynamicHeightChange(computedHeight);
 490            if (computedHeight)
 491              self.wrapping.style.height = Math.max(vmargin + computedHeight, self.options.minHeight) + "px";
 492          }
 493        }
 494        setTimeout(updateHeight, 300);
 495        self.options.onCursorActivity = function(x) {
 496          if (activity) activity(x);
 497          clearTimeout(timeout);
 498          timeout = setTimeout(updateHeight, 100);
 499        };
 500      }
 501    };
 502  
 503    CodeMirror.InvalidLineHandle = {toString: function(){return "CodeMirror.InvalidLineHandle";}};
 504  
 505    CodeMirror.replace = function(element) {
 506      if (typeof element == "string")
 507        element = document.getElementById(element);
 508      return function(newElement) {
 509        element.parentNode.replaceChild(newElement, element);
 510      };
 511    };
 512  
 513    CodeMirror.fromTextArea = function(area, options) {
 514      if (typeof area == "string")
 515        area = document.getElementById(area);
 516  
 517      options = options || {};
 518      if (area.style.width && options.width == null)
 519        options.width = area.style.width;
 520      if (area.style.height && options.height == null)
 521        options.height = area.style.height;
 522      if (options.content == null) options.content = area.value;
 523  
 524      function updateField() {
 525        area.value = mirror.getCode();
 526      }
 527      if (area.form) {
 528        if (typeof area.form.addEventListener == "function")
 529          area.form.addEventListener("submit", updateField, false);
 530        else
 531          area.form.attachEvent("onsubmit", updateField);
 532        if (typeof area.form.submit == "function") {
 533          var realSubmit = area.form.submit;
 534          function wrapSubmit() {
 535            updateField();
 536            // Can't use realSubmit.apply because IE6 is too stupid
 537            area.form.submit = realSubmit;
 538            area.form.submit();
 539            area.form.submit = wrapSubmit;
 540          }
 541          area.form.submit = wrapSubmit;
 542        }
 543      }
 544  
 545      function insert(frame) {
 546        if (area.nextSibling)
 547          area.parentNode.insertBefore(frame, area.nextSibling);
 548        else
 549          area.parentNode.appendChild(frame);
 550      }
 551  
 552      area.style.display = "none";
 553      var mirror = new CodeMirror(insert, options);
 554      mirror.save = updateField;
 555      mirror.toTextArea = function() {
 556        updateField();
 557        area.parentNode.removeChild(mirror.wrapping);
 558        area.style.display = "";
 559        if (area.form) {
 560          if (typeof area.form.submit == "function")
 561            area.form.submit = realSubmit;
 562          if (typeof area.form.removeEventListener == "function")
 563            area.form.removeEventListener("submit", updateField, false);
 564          else
 565            area.form.detachEvent("onsubmit", updateField);
 566        }
 567      };
 568  
 569      return mirror;
 570    };
 571  
 572    CodeMirror.isProbablySupported = function() {
 573      // This is rather awful, but can be useful.
 574      var match;
 575      if (window.opera)
 576        return Number(window.opera.version()) >= 9.52;
 577      else if (/Apple Computer, Inc/.test(navigator.vendor) && (match = navigator.userAgent.match(/Version\/(\d+(?:\.\d+)?)\./)))
 578        return Number(match[1]) >= 3;
 579      else if (document.selection && window.ActiveXObject && (match = navigator.userAgent.match(/MSIE (\d+(?:\.\d*)?)\b/)))
 580        return Number(match[1]) >= 6;
 581      else if (match = navigator.userAgent.match(/gecko\/(\d{8})/i))
 582        return Number(match[1]) >= 20050901;
 583      else if (match = navigator.userAgent.match(/AppleWebKit\/(\d+)/))
 584        return Number(match[1]) >= 525;
 585      else
 586        return null;
 587    };
 588  
 589    return CodeMirror;
 590  })();

title

Description

title

Description

title

Description

title

title

Body