home *** CD-ROM | disk | FTP | other *** search
/ Computer Active 2010 July / CA07.iso / Multimedija / QuickTimeInstaller.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_SourceFrame.js < prev    next >
Encoding:
JavaScript  |  2010-03-15  |  27.7 KB  |  731 lines

  1. /*
  2.  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
  17.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24.  */
  25.  
  26. WebInspector.SourceFrame = function(element, addBreakpointDelegate)
  27. {
  28.     this.messages = [];
  29.     this.breakpoints = [];
  30.  
  31.     this.addBreakpointDelegate = addBreakpointDelegate;
  32.  
  33.     this.element = element || document.createElement("iframe");
  34.     this.element.addStyleClass("source-view-frame");
  35.     this.element.setAttribute("viewsource", "true");
  36.  
  37.     this.element.addEventListener("load", this._loaded.bind(this), false);
  38. }
  39.  
  40. WebInspector.SourceFrame.prototype = {
  41.     get executionLine()
  42.     {
  43.         return this._executionLine;
  44.     },
  45.  
  46.     set executionLine(x)
  47.     {
  48.         if (this._executionLine === x)
  49.             return;
  50.  
  51.         var previousLine = this._executionLine;
  52.         this._executionLine = x;
  53.  
  54.         this._updateExecutionLine(previousLine);
  55.     },
  56.  
  57.     get autoSizesToFitContentHeight()
  58.     {
  59.         return this._autoSizesToFitContentHeight;
  60.     },
  61.  
  62.     set autoSizesToFitContentHeight(x)
  63.     {
  64.         if (this._autoSizesToFitContentHeight === x)
  65.             return;
  66.  
  67.         this._autoSizesToFitContentHeight = x;
  68.  
  69.         if (this._autoSizesToFitContentHeight) {
  70.             this._windowResizeListener = this._windowResized.bind(this);
  71.             window.addEventListener("resize", this._windowResizeListener, false);
  72.             this.sizeToFitContentHeight();
  73.         } else {
  74.             this.element.style.removeProperty("height");
  75.             if (this.element.contentDocument)
  76.                 this.element.contentDocument.body.removeStyleClass("webkit-height-sized-to-fit");
  77.             window.removeEventListener("resize", this._windowResizeListener, false);
  78.             delete this._windowResizeListener;
  79.         }
  80.     },
  81.  
  82.     sourceRow: function(lineNumber)
  83.     {
  84.         if (!lineNumber || !this.element.contentDocument)
  85.             return;
  86.  
  87.         var table = this.element.contentDocument.getElementsByTagName("table")[0];
  88.         if (!table)
  89.             return;
  90.  
  91.         var rows = table.rows;
  92.  
  93.         // Line numbers are a 1-based index, but the rows collection is 0-based.
  94.         --lineNumber;
  95.  
  96.         return rows[lineNumber];
  97.     },
  98.  
  99.     lineNumberForSourceRow: function(sourceRow)
  100.     {
  101.         // Line numbers are a 1-based index, but the rows collection is 0-based.
  102.         var lineNumber = 0;
  103.         while (sourceRow) {
  104.             ++lineNumber;
  105.             sourceRow = sourceRow.previousSibling;
  106.         }
  107.  
  108.         return lineNumber;
  109.     },
  110.  
  111.     revealLine: function(lineNumber)
  112.     {
  113.         if (!this._isContentLoaded()) {
  114.             this._lineNumberToReveal = lineNumber;
  115.             return;
  116.         }
  117.     
  118.         var row = this.sourceRow(lineNumber);
  119.         if (row)
  120.             row.scrollIntoViewIfNeeded(true);
  121.     },
  122.  
  123.     addBreakpoint: function(breakpoint)
  124.     {
  125.         this.breakpoints.push(breakpoint);
  126.         breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this);
  127.         breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this);
  128.         this._addBreakpointToSource(breakpoint);
  129.     },
  130.  
  131.     removeBreakpoint: function(breakpoint)
  132.     {
  133.         this.breakpoints.remove(breakpoint);
  134.         breakpoint.removeEventListener("enabled", null, this);
  135.         breakpoint.removeEventListener("disabled", null, this);
  136.         this._removeBreakpointFromSource(breakpoint);
  137.     },
  138.  
  139.     addMessage: function(msg)
  140.     {
  141.         // Don't add the message if there is no message or valid line or if the msg isn't an error or warning.
  142.         if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning())
  143.             return;
  144.         this.messages.push(msg);
  145.         this._addMessageToSource(msg);
  146.     },
  147.  
  148.     clearMessages: function()
  149.     {
  150.         this.messages = [];
  151.  
  152.         if (!this.element.contentDocument)
  153.             return;
  154.  
  155.         var bubbles = this.element.contentDocument.querySelectorAll(".webkit-html-message-bubble");
  156.         if (!bubbles)
  157.             return;
  158.  
  159.         for (var i = 0; i < bubbles.length; ++i) {
  160.             var bubble = bubbles[i];
  161.             bubble.parentNode.removeChild(bubble);
  162.         }
  163.     },
  164.  
  165.     sizeToFitContentHeight: function()
  166.     {
  167.         if (this.element.contentDocument) {
  168.             this.element.style.setProperty("height", this.element.contentDocument.body.offsetHeight + "px");
  169.             this.element.contentDocument.body.addStyleClass("webkit-height-sized-to-fit");
  170.         }
  171.     },
  172.  
  173.     _highlightLineEnds: function(event)
  174.     {
  175.         event.target.parentNode.removeStyleClass("webkit-highlighted-line");
  176.     },
  177.  
  178.     highlightLine: function(lineNumber)
  179.     {
  180.         if (!this._isContentLoaded()) {
  181.             this._lineNumberToHighlight = lineNumber;
  182.             return;
  183.         }
  184.  
  185.         var sourceRow = this.sourceRow(lineNumber);
  186.         if (!sourceRow)
  187.             return;
  188.         var line = sourceRow.getElementsByClassName('webkit-line-content')[0];
  189.         // Trick to reset the animation if the user clicks on the same link
  190.         // Using a timeout to avoid coalesced style updates
  191.         line.style.setProperty("-webkit-animation-name", "none");
  192.         setTimeout(function () {
  193.             line.style.removeProperty("-webkit-animation-name");
  194.             sourceRow.addStyleClass("webkit-highlighted-line");
  195.         }, 0);
  196.     },
  197.  
  198.     _loaded: function()
  199.     {
  200.         WebInspector.addMainEventListeners(this.element.contentDocument);
  201.         this.element.contentDocument.addEventListener("mousedown", this._documentMouseDown.bind(this), true);
  202.         this.element.contentDocument.addEventListener("webkitAnimationEnd", this._highlightLineEnds.bind(this), false);
  203.  
  204.         var headElement = this.element.contentDocument.getElementsByTagName("head")[0];
  205.         if (!headElement) {
  206.             headElement = this.element.contentDocument.createElement("head");
  207.             this.element.contentDocument.documentElement.insertBefore(headElement, this.element.contentDocument.documentElement.firstChild);
  208.         }
  209.  
  210.         var styleElement = this.element.contentDocument.createElement("style");
  211.         headElement.appendChild(styleElement);
  212.  
  213.         // Add these style rules here since they are specific to the Inspector. They also behave oddly and not
  214.         // all properties apply if added to view-source.css (becuase it is a user agent sheet.)
  215.         var styleText = ".webkit-line-number { background-repeat: no-repeat; background-position: right 1px; }\n";
  216.         styleText += ".webkit-breakpoint .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint); }\n";
  217.         styleText += ".webkit-breakpoint-disabled .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint-disabled); }\n";
  218.         styleText += ".webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(program-counter); }\n";
  219.         styleText += ".webkit-breakpoint.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-program-counter); }\n";
  220.         styleText += ".webkit-breakpoint-disabled.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-disabled-program-counter); }\n";
  221.         styleText += ".webkit-execution-line .webkit-line-content { background-color: rgb(171, 191, 254); outline: 1px solid rgb(64, 115, 244); }\n";
  222.         styleText += ".webkit-height-sized-to-fit { overflow-y: hidden }\n";
  223.         styleText += ".webkit-line-content { background-color: white; }\n";
  224.         styleText += "@-webkit-keyframes fadeout {from {background-color: rgb(255, 255, 120);} to { background-color: white;}}\n";
  225.         styleText += ".webkit-highlighted-line .webkit-line-content { background-color: rgb(255, 255, 120); -webkit-animation: 'fadeout' 2s 500ms}\n";
  226.         styleText += ".webkit-javascript-comment { color: rgb(0, 116, 0); }\n";
  227.         styleText += ".webkit-javascript-keyword { color: rgb(170, 13, 145); }\n";
  228.         styleText += ".webkit-javascript-number { color: rgb(28, 0, 207); }\n";
  229.         styleText += ".webkit-javascript-string, .webkit-javascript-regexp { color: rgb(196, 26, 22); }\n";
  230.  
  231.         styleElement.textContent = styleText;
  232.  
  233.         this._needsProgramCounterImage = true;
  234.         this._needsBreakpointImages = true;
  235.  
  236.         this.element.contentWindow.Element.prototype.addStyleClass = Element.prototype.addStyleClass;
  237.         this.element.contentWindow.Element.prototype.removeStyleClass = Element.prototype.removeStyleClass;
  238.         this.element.contentWindow.Element.prototype.removeMatchingStyleClasses = Element.prototype.removeMatchingStyleClasses;
  239.         this.element.contentWindow.Element.prototype.hasStyleClass = Element.prototype.hasStyleClass;
  240.         this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeName = Node.prototype.enclosingNodeOrSelfWithNodeName;
  241.         this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = Node.prototype.enclosingNodeOrSelfWithNodeNameInArray;
  242.  
  243.         this._addExistingMessagesToSource();
  244.         this._addExistingBreakpointsToSource();
  245.         this._updateExecutionLine();
  246.         if (this._executionLine)
  247.             this.revealLine(this._executionLine);
  248.  
  249.         if (this.autoSizesToFitContentHeight)
  250.             this.sizeToFitContentHeight();
  251.             
  252.         if (this._lineNumberToReveal) {
  253.             this.revealLine(this._lineNumberToReveal);
  254.             delete this._lineNumberToReveal;
  255.         }
  256.     
  257.         if (this._lineNumberToHighlight) {
  258.             this.highlightLine(this._lineNumberToHighlight);
  259.             delete this._lineNumberToHighlight;
  260.         }
  261.         
  262.         this.dispatchEventToListeners("content loaded");
  263.     },
  264.     
  265.     _isContentLoaded: function() {
  266.         var doc = this.element.contentDocument;
  267.         return doc && doc.getElementsByTagName("table")[0];
  268.     },
  269.  
  270.     _windowResized: function(event)
  271.     {
  272.         if (!this._autoSizesToFitContentHeight)
  273.             return;
  274.         this.sizeToFitContentHeight();
  275.     },
  276.  
  277.     _documentMouseDown: function(event)
  278.     {
  279.         if (!event.target.hasStyleClass("webkit-line-number"))
  280.             return;
  281.  
  282.         var sourceRow = event.target.enclosingNodeOrSelfWithNodeName("tr");
  283.         if (sourceRow._breakpointObject)
  284.             sourceRow._breakpointObject.enabled = !sourceRow._breakpointObject.enabled;
  285.         else if (this.addBreakpointDelegate)
  286.             this.addBreakpointDelegate(this.lineNumberForSourceRow(sourceRow));
  287.     },
  288.  
  289.     _breakpointEnableChanged: function(event)
  290.     {
  291.         var breakpoint = event.target;
  292.         var sourceRow = this.sourceRow(breakpoint.line);
  293.         if (!sourceRow)
  294.             return;
  295.  
  296.         sourceRow.addStyleClass("webkit-breakpoint");
  297.  
  298.         if (breakpoint.enabled)
  299.             sourceRow.removeStyleClass("webkit-breakpoint-disabled");
  300.         else
  301.             sourceRow.addStyleClass("webkit-breakpoint-disabled");
  302.     },
  303.  
  304.     _updateExecutionLine: function(previousLine)
  305.     {
  306.         if (previousLine) {
  307.             var sourceRow = this.sourceRow(previousLine);
  308.             if (sourceRow)
  309.                 sourceRow.removeStyleClass("webkit-execution-line");
  310.         }
  311.  
  312.         if (!this._executionLine)
  313.             return;
  314.  
  315.         this._drawProgramCounterImageIfNeeded();
  316.  
  317.         var sourceRow = this.sourceRow(this._executionLine);
  318.         if (sourceRow)
  319.             sourceRow.addStyleClass("webkit-execution-line");
  320.     },
  321.  
  322.     _addExistingBreakpointsToSource: function()
  323.     {
  324.         var length = this.breakpoints.length;
  325.         for (var i = 0; i < length; ++i)
  326.             this._addBreakpointToSource(this.breakpoints[i]);
  327.     },
  328.  
  329.     _addBreakpointToSource: function(breakpoint)
  330.     {
  331.         var sourceRow = this.sourceRow(breakpoint.line);
  332.         if (!sourceRow)
  333.             return;
  334.  
  335.         this._drawBreakpointImagesIfNeeded();
  336.  
  337.         sourceRow._breakpointObject = breakpoint;
  338.  
  339.         sourceRow.addStyleClass("webkit-breakpoint");
  340.         if (!breakpoint.enabled)
  341.             sourceRow.addStyleClass("webkit-breakpoint-disabled");
  342.     },
  343.  
  344.     _removeBreakpointFromSource: function(breakpoint)
  345.     {
  346.         var sourceRow = this.sourceRow(breakpoint.line);
  347.         if (!sourceRow)
  348.             return;
  349.  
  350.         delete sourceRow._breakpointObject;
  351.  
  352.         sourceRow.removeStyleClass("webkit-breakpoint");
  353.         sourceRow.removeStyleClass("webkit-breakpoint-disabled");
  354.     },
  355.     
  356.     _incrementMessageRepeatCount: function(msg, repeatDelta)
  357.     {
  358.         if (!msg._resourceMessageLineElement)
  359.             return;
  360.  
  361.         if (!msg._resourceMessageRepeatCountElement) {
  362.             var repeatedElement = document.createElement("span");
  363.             msg._resourceMessageLineElement.appendChild(repeatedElement);
  364.             msg._resourceMessageRepeatCountElement = repeatedElement;
  365.         }
  366.  
  367.         msg.repeatCount += repeatDelta;
  368.         msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount);
  369.     },
  370.  
  371.     _addExistingMessagesToSource: function()
  372.     {
  373.         var length = this.messages.length;
  374.         for (var i = 0; i < length; ++i)
  375.             this._addMessageToSource(this.messages[i]);
  376.     },
  377.  
  378.     _addMessageToSource: function(msg)
  379.     {
  380.         var row = this.sourceRow(msg.line);
  381.         if (!row)
  382.             return;
  383.  
  384.         var cell = row.cells[1];
  385.         if (!cell)
  386.             return;
  387.  
  388.         var messageBubbleElement = cell.lastChild;
  389.         if (!messageBubbleElement || messageBubbleElement.nodeType !== Node.ELEMENT_NODE || !messageBubbleElement.hasStyleClass("webkit-html-message-bubble")) {
  390.             messageBubbleElement = this.element.contentDocument.createElement("div");
  391.             messageBubbleElement.className = "webkit-html-message-bubble";
  392.             cell.appendChild(messageBubbleElement);
  393.         }
  394.  
  395.         if (!row.messages)
  396.             row.messages = [];
  397.  
  398.         for (var i = 0; i < row.messages.length; ++i) {
  399.             if (row.messages[i].isEqual(msg, true)) {
  400.                 this._incrementMessageRepeatCount(row.messages[i], msg.repeatDelta);
  401.                 return;
  402.             }
  403.         }
  404.  
  405.         row.messages.push(msg);
  406.  
  407.         var imageURL;
  408.         switch (msg.level) {
  409.             case WebInspector.ConsoleMessage.MessageLevel.Error:
  410.                 messageBubbleElement.addStyleClass("webkit-html-error-message");
  411.                 imageURL = "Images/errorIcon.png";
  412.                 break;
  413.             case WebInspector.ConsoleMessage.MessageLevel.Warning:
  414.                 messageBubbleElement.addStyleClass("webkit-html-warning-message");
  415.                 imageURL = "Images/warningIcon.png";
  416.                 break;
  417.         }
  418.  
  419.         var messageLineElement = this.element.contentDocument.createElement("div");
  420.         messageLineElement.className = "webkit-html-message-line";
  421.         messageBubbleElement.appendChild(messageLineElement);
  422.  
  423.         // Create the image element in the Inspector's document so we can use relative image URLs.
  424.         var image = document.createElement("img");
  425.         image.src = imageURL;
  426.         image.className = "webkit-html-message-icon";
  427.  
  428.         // Adopt the image element since it wasn't created in element's contentDocument.
  429.         image = this.element.contentDocument.adoptNode(image);
  430.         messageLineElement.appendChild(image);
  431.         messageLineElement.appendChild(this.element.contentDocument.createTextNode(msg.message));
  432.  
  433.         msg._resourceMessageLineElement = messageLineElement;
  434.     },
  435.  
  436.     _drawProgramCounterInContext: function(ctx, glow)
  437.     {
  438.         if (glow)
  439.             ctx.save();
  440.  
  441.         ctx.beginPath();
  442.         ctx.moveTo(17, 2);
  443.         ctx.lineTo(19, 2);
  444.         ctx.lineTo(19, 0);
  445.         ctx.lineTo(21, 0);
  446.         ctx.lineTo(26, 5.5);
  447.         ctx.lineTo(21, 11);
  448.         ctx.lineTo(19, 11);
  449.         ctx.lineTo(19, 9);
  450.         ctx.lineTo(17, 9);
  451.         ctx.closePath();
  452.         ctx.fillStyle = "rgb(142, 5, 4)";
  453.  
  454.         if (glow) {
  455.             ctx.shadowBlur = 4;
  456.             ctx.shadowColor = "rgb(255, 255, 255)";
  457.             ctx.shadowOffsetX = -1;
  458.             ctx.shadowOffsetY = 0;
  459.         }
  460.  
  461.         ctx.fill();
  462.         ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels.
  463.  
  464.         if (glow)
  465.             ctx.restore();
  466.     },
  467.  
  468.     _drawProgramCounterImageIfNeeded: function()
  469.     {
  470.         if (!this._needsProgramCounterImage || !this.element.contentDocument)
  471.             return;
  472.  
  473.         var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "program-counter", 26, 11);
  474.         ctx.clearRect(0, 0, 26, 11);
  475.         this._drawProgramCounterInContext(ctx, true);
  476.  
  477.         delete this._needsProgramCounterImage;
  478.     },
  479.  
  480.     _drawBreakpointImagesIfNeeded: function()
  481.     {
  482.         if (!this._needsBreakpointImages || !this.element.contentDocument)
  483.             return;
  484.  
  485.         function drawBreakpoint(ctx, disabled)
  486.         {
  487.             ctx.beginPath();
  488.             ctx.moveTo(0, 2);
  489.             ctx.lineTo(2, 0);
  490.             ctx.lineTo(21, 0);
  491.             ctx.lineTo(26, 5.5);
  492.             ctx.lineTo(21, 11);
  493.             ctx.lineTo(2, 11);
  494.             ctx.lineTo(0, 9);
  495.             ctx.closePath();
  496.             ctx.fillStyle = "rgb(1, 142, 217)";
  497.             ctx.strokeStyle = "rgb(0, 103, 205)";
  498.             ctx.lineWidth = 3;
  499.             ctx.fill();
  500.             ctx.save();
  501.             ctx.clip();
  502.             ctx.stroke();
  503.             ctx.restore();
  504.  
  505.             if (!disabled)
  506.                 return;
  507.  
  508.             ctx.save();
  509.             ctx.globalCompositeOperation = "destination-out";
  510.             ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
  511.             ctx.fillRect(0, 0, 26, 11);
  512.             ctx.restore();
  513.         }
  514.  
  515.         var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint", 26, 11);
  516.         ctx.clearRect(0, 0, 26, 11);
  517.         drawBreakpoint(ctx);
  518.  
  519.         var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-program-counter", 26, 11);
  520.         ctx.clearRect(0, 0, 26, 11);
  521.         drawBreakpoint(ctx);
  522.         ctx.clearRect(20, 0, 6, 11);
  523.         this._drawProgramCounterInContext(ctx, true);
  524.  
  525.         var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled", 26, 11);
  526.         ctx.clearRect(0, 0, 26, 11);
  527.         drawBreakpoint(ctx, true);
  528.  
  529.         var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled-program-counter", 26, 11);
  530.         ctx.clearRect(0, 0, 26, 11);
  531.         drawBreakpoint(ctx, true);
  532.         ctx.clearRect(20, 0, 6, 11);
  533.         this._drawProgramCounterInContext(ctx, true);
  534.  
  535.         delete this._needsBreakpointImages;
  536.     },
  537.  
  538.     syntaxHighlightJavascript: function()
  539.     {
  540.         var table = this.element.contentDocument.getElementsByTagName("table")[0];
  541.         if (!table)
  542.             return;
  543.  
  544.         function deleteContinueFlags(cell)
  545.         {
  546.             if (!cell)
  547.                 return;
  548.             delete cell._commentContinues;
  549.             delete cell._singleQuoteStringContinues;
  550.             delete cell._doubleQuoteStringContinues;
  551.             delete cell._regexpContinues;
  552.         }
  553.  
  554.         function createSpan(content, className)
  555.         {
  556.             var span = document.createElement("span");
  557.             span.className = className;
  558.             span.appendChild(document.createTextNode(content));
  559.             return span;
  560.         }
  561.  
  562.         function generateFinder(regex, matchNumber, className)
  563.         {
  564.             return function(str) {
  565.                 var match = regex.exec(str);
  566.                 if (!match)
  567.                     return null;
  568.                 previousMatchLength = match[matchNumber].length;
  569.                 return createSpan(match[matchNumber], className);
  570.             };
  571.         }
  572.  
  573.         var findNumber = generateFinder(/^(-?(\d+\.?\d*([eE][+-]\d+)?|0[xX]\h+|Infinity)|NaN)(?:\W|$)/, 1, "webkit-javascript-number");
  574.         var findKeyword = generateFinder(/^(null|true|false|break|case|catch|const|default|finally|for|instanceof|new|var|continue|function|return|void|delete|if|this|do|while|else|in|switch|throw|try|typeof|with|debugger|class|enum|export|extends|import|super|get|set)(?:\W|$)/, 1, "webkit-javascript-keyword");
  575.         var findSingleLineString = generateFinder(/^"(?:[^"\\]|\\.)*"|^'([^'\\]|\\.)*'/, 0, "webkit-javascript-string"); // " this quote keeps Xcode happy
  576.         var findMultilineCommentStart = generateFinder(/^\/\*.*$/, 0, "webkit-javascript-comment");
  577.         var findMultilineCommentEnd = generateFinder(/^.*?\*\//, 0, "webkit-javascript-comment");
  578.         var findMultilineSingleQuoteStringStart = generateFinder(/^'(?:[^'\\]|\\.)*\\$/, 0, "webkit-javascript-string");
  579.         var findMultilineSingleQuoteStringEnd = generateFinder(/^(?:[^'\\]|\\.)*?'/, 0, "webkit-javascript-string");
  580.         var findMultilineDoubleQuoteStringStart = generateFinder(/^"(?:[^"\\]|\\.)*\\$/, 0, "webkit-javascript-string");
  581.         var findMultilineDoubleQuoteStringEnd = generateFinder(/^(?:[^"\\]|\\.)*?"/, 0, "webkit-javascript-string");
  582.         var findMultilineRegExpEnd = generateFinder(/^(?:[^\/\\]|\\.)*?\/([gim]{0,3})/, 0, "webkit-javascript-regexp");
  583.         var findSingleLineComment = generateFinder(/^\/\/.*|^\/\*.*?\*\//, 0, "webkit-javascript-comment");
  584.  
  585.         function findMultilineRegExpStart(str)
  586.         {
  587.             var match = /^\/(?:[^\/\\]|\\.)*\\$/.exec(str);
  588.             if (!match || !/\\|\$|\.[\?\*\+]|[^\|]\|[^\|]/.test(match[0]))
  589.                 return null;
  590.             var node = createSpan(match[0], "webkit-javascript-regexp");
  591.             previousMatchLength = match[0].length;
  592.             return node;
  593.         }
  594.  
  595.         function findSingleLineRegExp(str)
  596.         {
  597.             var match = /^(\/(?:[^\/\\]|\\.)*\/([gim]{0,3}))(.?)/.exec(str);
  598.             if (!match || !(match[2].length > 0 || /\\|\$|\.[\?\*\+]|[^\|]\|[^\|]/.test(match[1]) || /\.|;|,/.test(match[3])))
  599.                 return null;
  600.             var node = createSpan(match[1], "webkit-javascript-regexp");
  601.             previousMatchLength = match[1].length;
  602.             return node;
  603.         }
  604.  
  605.         function syntaxHighlightJavascriptLine(line, prevLine)
  606.         {
  607.             var messageBubble = line.lastChild;
  608.             if (messageBubble && messageBubble.nodeType === Node.ELEMENT_NODE && messageBubble.hasStyleClass("webkit-html-message-bubble"))
  609.                 line.removeChild(messageBubble);
  610.             else
  611.                 messageBubble = null;
  612.  
  613.             var code = line.textContent;
  614.  
  615.             while (line.firstChild)
  616.                 line.removeChild(line.firstChild);
  617.  
  618.             var token;
  619.             var tmp = 0;
  620.             var i = 0;
  621.             previousMatchLength = 0;
  622.  
  623.             if (prevLine) {
  624.                 if (prevLine._commentContinues) {
  625.                     if (!(token = findMultilineCommentEnd(code))) {
  626.                         token = createSpan(code, "webkit-javascript-comment");
  627.                         line._commentContinues = true;
  628.                     }
  629.                 } else if (prevLine._singleQuoteStringContinues) {
  630.                     if (!(token = findMultilineSingleQuoteStringEnd(code))) {
  631.                         token = createSpan(code, "webkit-javascript-string");
  632.                         line._singleQuoteStringContinues = true;
  633.                     }
  634.                 } else if (prevLine._doubleQuoteStringContinues) {
  635.                     if (!(token = findMultilineDoubleQuoteStringEnd(code))) {
  636.                         token = createSpan(code, "webkit-javascript-string");
  637.                         line._doubleQuoteStringContinues = true;
  638.                     }
  639.                 } else if (prevLine._regexpContinues) {
  640.                     if (!(token = findMultilineRegExpEnd(code))) {
  641.                         token = createSpan(code, "webkit-javascript-regexp");
  642.                         line._regexpContinues = true;
  643.                     }
  644.                 }
  645.                 if (token) {
  646.                     i += previousMatchLength ? previousMatchLength : code.length;
  647.                     tmp = i;
  648.                     line.appendChild(token);
  649.                 }
  650.             }
  651.  
  652.             for ( ; i < code.length; ++i) {
  653.                 var codeFragment = code.substr(i);
  654.                 var prevChar = code[i - 1];
  655.                 token = findSingleLineComment(codeFragment);
  656.                 if (!token) {
  657.                     if ((token = findMultilineCommentStart(codeFragment)))
  658.                         line._commentContinues = true;
  659.                     else if (!prevChar || /^\W/.test(prevChar)) {
  660.                         token = findNumber(codeFragment, code[i - 1]) ||
  661.                                 findKeyword(codeFragment, code[i - 1]) ||
  662.                                 findSingleLineString(codeFragment) ||
  663.                                 findSingleLineRegExp(codeFragment);
  664.                         if (!token) {
  665.                             if (token = findMultilineSingleQuoteStringStart(codeFragment))
  666.                                 line._singleQuoteStringContinues = true;
  667.                             else if (token = findMultilineDoubleQuoteStringStart(codeFragment))
  668.                                 line._doubleQuoteStringContinues = true;
  669.                             else if (token = findMultilineRegExpStart(codeFragment))
  670.                                 line._regexpContinues = true;
  671.                         }
  672.                     }
  673.                 }
  674.  
  675.                 if (token) {
  676.                     if (tmp !== i)
  677.                         line.appendChild(document.createTextNode(code.substring(tmp, i)));
  678.                     line.appendChild(token);
  679.                     i += previousMatchLength - 1;
  680.                     tmp = i + 1;
  681.                 }
  682.             }
  683.  
  684.             if (tmp < code.length)
  685.                 line.appendChild(document.createTextNode(code.substring(tmp, i)));
  686.  
  687.             if (messageBubble)
  688.                 line.appendChild(messageBubble);
  689.         }
  690.  
  691.         var i = 0;
  692.         var rows = table.rows;
  693.         var rowsLength = rows.length;
  694.         var previousCell = null;
  695.         var previousMatchLength = 0;
  696.         var sourceFrame = this;
  697.  
  698.         // Split up the work into chunks so we don't block the
  699.         // UI thread while processing.
  700.  
  701.         function processChunk()
  702.         {
  703.             for (var end = Math.min(i + 10, rowsLength); i < end; ++i) {
  704.                 var row = rows[i];
  705.                 if (!row)
  706.                     continue;
  707.                 var cell = row.cells[1];
  708.                 if (!cell)
  709.                     continue;
  710.                 syntaxHighlightJavascriptLine(cell, previousCell);
  711.                 if (i < (end - 1))
  712.                     deleteContinueFlags(previousCell);
  713.                 previousCell = cell;
  714.             }
  715.  
  716.             if (i >= rowsLength && processChunkInterval) {
  717.                 deleteContinueFlags(previousCell);
  718.                 clearInterval(processChunkInterval);
  719.  
  720.                 sourceFrame.dispatchEventToListeners("syntax highlighting complete");
  721.             }
  722.         }
  723.  
  724.         processChunk();
  725.  
  726.         var processChunkInterval = setInterval(processChunk, 25);
  727.     }
  728. }
  729.  
  730. WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;
  731.