| /* |
| * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
| * Copyright (C) 2009 Joseph Pecoraro |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WebInspector.SourceFrame = function(element, addBreakpointDelegate) |
| { |
| this.messages = []; |
| this.breakpoints = []; |
| this._shortcuts = {}; |
| |
| this.addBreakpointDelegate = addBreakpointDelegate; |
| |
| this.element = element || document.createElement("iframe"); |
| this.element.addStyleClass("source-view-frame"); |
| this.element.setAttribute("viewsource", "true"); |
| |
| this.element.addEventListener("load", this._loaded.bind(this), false); |
| } |
| |
| WebInspector.SourceFrame.prototype = { |
| get executionLine() |
| { |
| return this._executionLine; |
| }, |
| |
| set executionLine(x) |
| { |
| if (this._executionLine === x) |
| return; |
| |
| var previousLine = this._executionLine; |
| this._executionLine = x; |
| |
| this._updateExecutionLine(previousLine); |
| }, |
| |
| get autoSizesToFitContentHeight() |
| { |
| return this._autoSizesToFitContentHeight; |
| }, |
| |
| set autoSizesToFitContentHeight(x) |
| { |
| if (this._autoSizesToFitContentHeight === x) |
| return; |
| |
| this._autoSizesToFitContentHeight = x; |
| |
| if (this._autoSizesToFitContentHeight) { |
| this._windowResizeListener = this._windowResized.bind(this); |
| window.addEventListener("resize", this._windowResizeListener, false); |
| this.sizeToFitContentHeight(); |
| } else { |
| this.element.style.removeProperty("height"); |
| if (this.element.contentDocument) |
| this.element.contentDocument.body.removeStyleClass("webkit-height-sized-to-fit"); |
| window.removeEventListener("resize", this._windowResizeListener, false); |
| delete this._windowResizeListener; |
| } |
| }, |
| |
| sourceRow: function(lineNumber) |
| { |
| if (!lineNumber || !this.element.contentDocument) |
| return; |
| |
| var table = this.element.contentDocument.getElementsByTagName("table")[0]; |
| if (!table) |
| return; |
| |
| var rows = table.rows; |
| |
| // Line numbers are a 1-based index, but the rows collection is 0-based. |
| --lineNumber; |
| |
| return rows[lineNumber]; |
| }, |
| |
| lineNumberForSourceRow: function(sourceRow) |
| { |
| // Line numbers are a 1-based index, but the rows collection is 0-based. |
| var lineNumber = 0; |
| while (sourceRow) { |
| ++lineNumber; |
| sourceRow = sourceRow.previousSibling; |
| } |
| |
| return lineNumber; |
| }, |
| |
| revealLine: function(lineNumber) |
| { |
| if (!this._isContentLoaded()) { |
| this._lineNumberToReveal = lineNumber; |
| return; |
| } |
| |
| var row = this.sourceRow(lineNumber); |
| if (row) |
| row.scrollIntoViewIfNeeded(true); |
| }, |
| |
| addBreakpoint: function(breakpoint) |
| { |
| this.breakpoints.push(breakpoint); |
| breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this); |
| breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this); |
| this._addBreakpointToSource(breakpoint); |
| }, |
| |
| removeBreakpoint: function(breakpoint) |
| { |
| this.breakpoints.remove(breakpoint); |
| breakpoint.removeEventListener("enabled", null, this); |
| breakpoint.removeEventListener("disabled", null, this); |
| this._removeBreakpointFromSource(breakpoint); |
| }, |
| |
| addMessage: function(msg) |
| { |
| // Don't add the message if there is no message or valid line or if the msg isn't an error or warning. |
| if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning()) |
| return; |
| this.messages.push(msg); |
| this._addMessageToSource(msg); |
| }, |
| |
| clearMessages: function() |
| { |
| this.messages = []; |
| |
| if (!this.element.contentDocument) |
| return; |
| |
| var bubbles = this.element.contentDocument.querySelectorAll(".webkit-html-message-bubble"); |
| if (!bubbles) |
| return; |
| |
| for (var i = 0; i < bubbles.length; ++i) { |
| var bubble = bubbles[i]; |
| bubble.parentNode.removeChild(bubble); |
| } |
| }, |
| |
| sizeToFitContentHeight: function() |
| { |
| if (this.element.contentDocument) { |
| this.element.style.setProperty("height", this.element.contentDocument.body.offsetHeight + "px"); |
| this.element.contentDocument.body.addStyleClass("webkit-height-sized-to-fit"); |
| } |
| }, |
| |
| _highlightLineEnds: function(event) |
| { |
| event.target.parentNode.removeStyleClass("webkit-highlighted-line"); |
| }, |
| |
| highlightLine: function(lineNumber) |
| { |
| if (!this._isContentLoaded()) { |
| this._lineNumberToHighlight = lineNumber; |
| return; |
| } |
| |
| var sourceRow = this.sourceRow(lineNumber); |
| if (!sourceRow) |
| return; |
| var line = sourceRow.getElementsByClassName('webkit-line-content')[0]; |
| // Trick to reset the animation if the user clicks on the same link |
| // Using a timeout to avoid coalesced style updates |
| line.style.setProperty("-webkit-animation-name", "none"); |
| setTimeout(function () { |
| line.style.removeProperty("-webkit-animation-name"); |
| sourceRow.addStyleClass("webkit-highlighted-line"); |
| }, 0); |
| }, |
| |
| _loaded: function() |
| { |
| WebInspector.addMainEventListeners(this.element.contentDocument); |
| this.element.contentDocument.addEventListener("contextmenu", this._documentContextMenu.bind(this), true); |
| this.element.contentDocument.addEventListener("mousedown", this._documentMouseDown.bind(this), true); |
| this.element.contentDocument.addEventListener("keydown", this._documentKeyDown.bind(this), true); |
| this.element.contentDocument.addEventListener("keyup", WebInspector.documentKeyUp.bind(WebInspector), true); |
| this.element.contentDocument.addEventListener("webkitAnimationEnd", this._highlightLineEnds.bind(this), false); |
| |
| // Register 'eval' shortcut. |
| var isMac = InspectorController.platform().indexOf("mac-") === 0; |
| var platformSpecificModifier = isMac ? WebInspector.KeyboardShortcut.Modifiers.Meta : WebInspector.KeyboardShortcut.Modifiers.Ctrl; |
| var shortcut = WebInspector.KeyboardShortcut.makeKey(69 /* 'E' */, platformSpecificModifier | WebInspector.KeyboardShortcut.Modifiers.Shift); |
| this._shortcuts[shortcut] = this._evalSelectionInCallFrame.bind(this); |
| |
| var headElement = this.element.contentDocument.getElementsByTagName("head")[0]; |
| if (!headElement) { |
| headElement = this.element.contentDocument.createElement("head"); |
| this.element.contentDocument.documentElement.insertBefore(headElement, this.element.contentDocument.documentElement.firstChild); |
| } |
| |
| var linkElement = this.element.contentDocument.createElement("link"); |
| linkElement.type = "text/css"; |
| linkElement.rel = "stylesheet"; |
| linkElement.href = "inspectorSyntaxHighlight.css"; |
| headElement.appendChild(linkElement); |
| |
| var styleElement = this.element.contentDocument.createElement("style"); |
| headElement.appendChild(styleElement); |
| |
| // Add these style rules here since they are specific to the Inspector. They also behave oddly and not |
| // all properties apply if added to view-source.css (because it is a user agent sheet.) |
| var styleText = ".webkit-line-number { background-repeat: no-repeat; background-position: right 1px; }\n"; |
| styleText += ".webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(program-counter); }\n"; |
| |
| styleText += ".webkit-breakpoint .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint); }\n"; |
| styleText += ".webkit-breakpoint-disabled .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint-disabled); }\n"; |
| styleText += ".webkit-breakpoint.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-program-counter); }\n"; |
| styleText += ".webkit-breakpoint-disabled.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-disabled-program-counter); }\n"; |
| |
| styleText += ".webkit-breakpoint.webkit-breakpoint-conditional .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint-conditional); }\n"; |
| styleText += ".webkit-breakpoint-disabled.webkit-breakpoint-conditional .webkit-line-number { color: white; background-image: -webkit-canvas(breakpoint-disabled-conditional); }\n"; |
| styleText += ".webkit-breakpoint.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-conditional-program-counter); }\n"; |
| styleText += ".webkit-breakpoint-disabled.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number { color: transparent; background-image: -webkit-canvas(breakpoint-disabled-conditional-program-counter); }\n"; |
| |
| styleText += ".webkit-execution-line .webkit-line-content { background-color: rgb(171, 191, 254); outline: 1px solid rgb(64, 115, 244); }\n"; |
| styleText += ".webkit-height-sized-to-fit { overflow-y: hidden }\n"; |
| styleText += ".webkit-line-content { background-color: white; }\n"; |
| styleText += "@-webkit-keyframes fadeout {from {background-color: rgb(255, 255, 120);} to { background-color: white;}}\n"; |
| styleText += ".webkit-highlighted-line .webkit-line-content { background-color: rgb(255, 255, 120); -webkit-animation: 'fadeout' 2s 500ms}\n"; |
| |
| // TODO: Move these styles into inspector.css once https://bugs.webkit.org/show_bug.cgi?id=28913 is fixed and popup moved into the top frame. |
| styleText += ".popup-content { position: absolute; z-index: 10000; padding: 4px; background-color: rgb(203, 226, 255); -webkit-border-radius: 7px; border: 2px solid rgb(169, 172, 203); }"; |
| styleText += ".popup-glasspane { position: absolute; top: 0; left: 0; height: 100%; width: 100%; opacity: 0; z-index: 9900; }"; |
| styleText += ".popup-message { background-color: transparent; font-family: Lucida Grande, sans-serif; font-weight: normal; font-size: 11px; text-align: left; text-shadow: none; color: rgb(85, 85, 85); cursor: default; margin: 0 0 2px 0; }"; |
| styleText += ".popup-content.breakpoint-condition { width: 90%; }"; |
| styleText += ".popup-content input#bp-condition { font-family: monospace; margin: 0; border: 1px inset rgb(190, 190, 190) !important; width: 100%; box-shadow: none !important; outline: none !important; -webkit-user-modify: read-write; }"; |
| // This class is already in inspector.css |
| styleText += ".hidden { display: none !important; }"; |
| |
| styleElement.textContent = styleText; |
| |
| this._needsProgramCounterImage = true; |
| this._needsBreakpointImages = true; |
| |
| this.element.contentWindow.Element.prototype.addStyleClass = Element.prototype.addStyleClass; |
| this.element.contentWindow.Element.prototype.removeStyleClass = Element.prototype.removeStyleClass; |
| this.element.contentWindow.Element.prototype.positionAt = Element.prototype.positionAt; |
| this.element.contentWindow.Element.prototype.removeMatchingStyleClasses = Element.prototype.removeMatchingStyleClasses; |
| this.element.contentWindow.Element.prototype.hasStyleClass = Element.prototype.hasStyleClass; |
| this.element.contentWindow.Element.prototype.pageOffsetRelativeToWindow = Element.prototype.pageOffsetRelativeToWindow; |
| this.element.contentWindow.Element.prototype.__defineGetter__("totalOffsetLeft", Element.prototype.__lookupGetter__("totalOffsetLeft")); |
| this.element.contentWindow.Element.prototype.__defineGetter__("totalOffsetTop", Element.prototype.__lookupGetter__("totalOffsetTop")); |
| this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeName = Node.prototype.enclosingNodeOrSelfWithNodeName; |
| this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = Node.prototype.enclosingNodeOrSelfWithNodeNameInArray; |
| |
| this._addExistingMessagesToSource(); |
| this._addExistingBreakpointsToSource(); |
| this._updateExecutionLine(); |
| if (this._executionLine) |
| this.revealLine(this._executionLine); |
| |
| if (this.autoSizesToFitContentHeight) |
| this.sizeToFitContentHeight(); |
| |
| if (this._lineNumberToReveal) { |
| this.revealLine(this._lineNumberToReveal); |
| delete this._lineNumberToReveal; |
| } |
| |
| if (this._lineNumberToHighlight) { |
| this.highlightLine(this._lineNumberToHighlight); |
| delete this._lineNumberToHighlight; |
| } |
| |
| this.dispatchEventToListeners("content loaded"); |
| }, |
| |
| _isContentLoaded: function() { |
| var doc = this.element.contentDocument; |
| return doc && doc.getElementsByTagName("table")[0]; |
| }, |
| |
| _windowResized: function(event) |
| { |
| if (!this._autoSizesToFitContentHeight) |
| return; |
| this.sizeToFitContentHeight(); |
| }, |
| |
| _documentContextMenu: function(event) |
| { |
| if (!event.target.hasStyleClass("webkit-line-number")) |
| return; |
| var sourceRow = event.target.enclosingNodeOrSelfWithNodeName("tr"); |
| if (!sourceRow._breakpointObject && this.addBreakpointDelegate) |
| this.addBreakpointDelegate(this.lineNumberForSourceRow(sourceRow)); |
| |
| var breakpoint = sourceRow._breakpointObject; |
| if (!breakpoint) |
| return; |
| |
| this._editBreakpointCondition(event.target, sourceRow, breakpoint); |
| event.preventDefault(); |
| }, |
| |
| _documentMouseDown: function(event) |
| { |
| if (!event.target.hasStyleClass("webkit-line-number")) |
| return; |
| if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) |
| return; |
| var sourceRow = event.target.enclosingNodeOrSelfWithNodeName("tr"); |
| if (sourceRow._breakpointObject && sourceRow._breakpointObject.enabled) |
| sourceRow._breakpointObject.enabled = false; |
| else if (sourceRow._breakpointObject) |
| WebInspector.panels.scripts.removeBreakpoint(sourceRow._breakpointObject); |
| else if (this.addBreakpointDelegate) |
| this.addBreakpointDelegate(this.lineNumberForSourceRow(sourceRow)); |
| }, |
| |
| _editBreakpointCondition: function(eventTarget, sourceRow, breakpoint) |
| { |
| // TODO: Migrate the popup to the top-level document and remove the blur listener from conditionElement once https://bugs.webkit.org/show_bug.cgi?id=28913 is fixed. |
| var popupDocument = this.element.contentDocument; |
| this._showBreakpointConditionPopup(eventTarget, breakpoint.line, popupDocument); |
| |
| function committed(element, newText) |
| { |
| breakpoint.condition = newText; |
| if (breakpoint.condition) |
| sourceRow.addStyleClass("webkit-breakpoint-conditional"); |
| else |
| sourceRow.removeStyleClass("webkit-breakpoint-conditional"); |
| dismissed.call(this); |
| } |
| |
| function dismissed() |
| { |
| this._popup.hide(); |
| delete this._conditionEditorElement; |
| } |
| |
| var dismissedHandler = dismissed.bind(this); |
| this._conditionEditorElement.addEventListener("blur", dismissedHandler, false); |
| |
| WebInspector.startEditing(this._conditionEditorElement, committed.bind(this), dismissedHandler); |
| this._conditionEditorElement.value = breakpoint.condition; |
| this._conditionEditorElement.select(); |
| }, |
| |
| _showBreakpointConditionPopup: function(clickedElement, lineNumber, popupDocument) |
| { |
| var popupContentElement = this._createPopupElement(lineNumber, popupDocument); |
| var lineElement = clickedElement.enclosingNodeOrSelfWithNodeName("td").nextSibling; |
| if (this._popup) { |
| this._popup.hide(); |
| this._popup.element = popupContentElement; |
| } else { |
| this._popup = new WebInspector.Popup(popupContentElement); |
| this._popup.autoHide = true; |
| } |
| this._popup.anchor = lineElement; |
| this._popup.show(); |
| }, |
| |
| _createPopupElement: function(lineNumber, popupDocument) |
| { |
| var popupContentElement = popupDocument.createElement("div"); |
| popupContentElement.className = "popup-content breakpoint-condition"; |
| |
| var labelElement = document.createElement("label"); |
| labelElement.className = "popup-message"; |
| labelElement.htmlFor = "bp-condition"; |
| labelElement.appendChild(document.createTextNode(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber))); |
| popupContentElement.appendChild(labelElement); |
| |
| var editorElement = document.createElement("input"); |
| editorElement.id = "bp-condition"; |
| editorElement.type = "text" |
| popupContentElement.appendChild(editorElement); |
| this._conditionEditorElement = editorElement; |
| |
| return popupContentElement; |
| }, |
| |
| _documentKeyDown: function(event) |
| { |
| var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); |
| var handler = this._shortcuts[shortcut]; |
| if (handler) { |
| handler(event); |
| event.preventDefault(); |
| } else { |
| WebInspector.documentKeyDown(event); |
| } |
| }, |
| |
| _evalSelectionInCallFrame: function(event) |
| { |
| if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) |
| return; |
| |
| var selection = this.element.contentWindow.getSelection(); |
| if (!selection.rangeCount) |
| return; |
| |
| var expression = selection.getRangeAt(0).toString().trimWhitespace(); |
| WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, "console", function(result, exception) { |
| WebInspector.showConsole(); |
| var commandMessage = new WebInspector.ConsoleCommand(expression); |
| WebInspector.console.addMessage(commandMessage); |
| WebInspector.console.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); |
| }); |
| }, |
| |
| _breakpointEnableChanged: function(event) |
| { |
| var breakpoint = event.target; |
| var sourceRow = this.sourceRow(breakpoint.line); |
| if (!sourceRow) |
| return; |
| |
| sourceRow.addStyleClass("webkit-breakpoint"); |
| |
| if (breakpoint.enabled) |
| sourceRow.removeStyleClass("webkit-breakpoint-disabled"); |
| else |
| sourceRow.addStyleClass("webkit-breakpoint-disabled"); |
| }, |
| |
| _updateExecutionLine: function(previousLine) |
| { |
| if (previousLine) { |
| var sourceRow = this.sourceRow(previousLine); |
| if (sourceRow) |
| sourceRow.removeStyleClass("webkit-execution-line"); |
| } |
| |
| if (!this._executionLine) |
| return; |
| |
| this._drawProgramCounterImageIfNeeded(); |
| |
| var sourceRow = this.sourceRow(this._executionLine); |
| if (sourceRow) |
| sourceRow.addStyleClass("webkit-execution-line"); |
| }, |
| |
| _addExistingBreakpointsToSource: function() |
| { |
| var length = this.breakpoints.length; |
| for (var i = 0; i < length; ++i) |
| this._addBreakpointToSource(this.breakpoints[i]); |
| }, |
| |
| _addBreakpointToSource: function(breakpoint) |
| { |
| var sourceRow = this.sourceRow(breakpoint.line); |
| if (!sourceRow) |
| return; |
| |
| breakpoint.sourceText = sourceRow.getElementsByClassName('webkit-line-content')[0].textContent; |
| |
| this._drawBreakpointImagesIfNeeded(); |
| |
| sourceRow._breakpointObject = breakpoint; |
| |
| sourceRow.addStyleClass("webkit-breakpoint"); |
| if (!breakpoint.enabled) |
| sourceRow.addStyleClass("webkit-breakpoint-disabled"); |
| if (breakpoint.condition) |
| sourceRow.addStyleClass("webkit-breakpoint-conditional"); |
| }, |
| |
| _removeBreakpointFromSource: function(breakpoint) |
| { |
| var sourceRow = this.sourceRow(breakpoint.line); |
| if (!sourceRow) |
| return; |
| |
| delete sourceRow._breakpointObject; |
| |
| sourceRow.removeStyleClass("webkit-breakpoint"); |
| sourceRow.removeStyleClass("webkit-breakpoint-disabled"); |
| sourceRow.removeStyleClass("webkit-breakpoint-conditional"); |
| }, |
| |
| _incrementMessageRepeatCount: function(msg, repeatDelta) |
| { |
| if (!msg._resourceMessageLineElement) |
| return; |
| |
| if (!msg._resourceMessageRepeatCountElement) { |
| var repeatedElement = document.createElement("span"); |
| msg._resourceMessageLineElement.appendChild(repeatedElement); |
| msg._resourceMessageRepeatCountElement = repeatedElement; |
| } |
| |
| msg.repeatCount += repeatDelta; |
| msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount); |
| }, |
| |
| _addExistingMessagesToSource: function() |
| { |
| var length = this.messages.length; |
| for (var i = 0; i < length; ++i) |
| this._addMessageToSource(this.messages[i]); |
| }, |
| |
| _addMessageToSource: function(msg) |
| { |
| var row = this.sourceRow(msg.line); |
| if (!row) |
| return; |
| |
| var cell = row.cells[1]; |
| if (!cell) |
| return; |
| |
| var messageBubbleElement = cell.lastChild; |
| if (!messageBubbleElement || messageBubbleElement.nodeType !== Node.ELEMENT_NODE || !messageBubbleElement.hasStyleClass("webkit-html-message-bubble")) { |
| messageBubbleElement = this.element.contentDocument.createElement("div"); |
| messageBubbleElement.className = "webkit-html-message-bubble"; |
| cell.appendChild(messageBubbleElement); |
| } |
| |
| if (!row.messages) |
| row.messages = []; |
| |
| for (var i = 0; i < row.messages.length; ++i) { |
| if (row.messages[i].isEqual(msg, true)) { |
| this._incrementMessageRepeatCount(row.messages[i], msg.repeatDelta); |
| return; |
| } |
| } |
| |
| row.messages.push(msg); |
| |
| var imageURL; |
| switch (msg.level) { |
| case WebInspector.ConsoleMessage.MessageLevel.Error: |
| messageBubbleElement.addStyleClass("webkit-html-error-message"); |
| imageURL = "Images/errorIcon.png"; |
| break; |
| case WebInspector.ConsoleMessage.MessageLevel.Warning: |
| messageBubbleElement.addStyleClass("webkit-html-warning-message"); |
| imageURL = "Images/warningIcon.png"; |
| break; |
| } |
| |
| var messageLineElement = this.element.contentDocument.createElement("div"); |
| messageLineElement.className = "webkit-html-message-line"; |
| messageBubbleElement.appendChild(messageLineElement); |
| |
| // Create the image element in the Inspector's document so we can use relative image URLs. |
| var image = document.createElement("img"); |
| image.src = imageURL; |
| image.className = "webkit-html-message-icon"; |
| |
| // Adopt the image element since it wasn't created in element's contentDocument. |
| image = this.element.contentDocument.adoptNode(image); |
| messageLineElement.appendChild(image); |
| messageLineElement.appendChild(this.element.contentDocument.createTextNode(msg.message)); |
| |
| msg._resourceMessageLineElement = messageLineElement; |
| }, |
| |
| _drawProgramCounterInContext: function(ctx, glow) |
| { |
| if (glow) |
| ctx.save(); |
| |
| ctx.beginPath(); |
| ctx.moveTo(17, 2); |
| ctx.lineTo(19, 2); |
| ctx.lineTo(19, 0); |
| ctx.lineTo(21, 0); |
| ctx.lineTo(26, 5.5); |
| ctx.lineTo(21, 11); |
| ctx.lineTo(19, 11); |
| ctx.lineTo(19, 9); |
| ctx.lineTo(17, 9); |
| ctx.closePath(); |
| ctx.fillStyle = "rgb(142, 5, 4)"; |
| |
| if (glow) { |
| ctx.shadowBlur = 4; |
| ctx.shadowColor = "rgb(255, 255, 255)"; |
| ctx.shadowOffsetX = -1; |
| ctx.shadowOffsetY = 0; |
| } |
| |
| ctx.fill(); |
| ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels. |
| |
| if (glow) |
| ctx.restore(); |
| }, |
| |
| _drawProgramCounterImageIfNeeded: function() |
| { |
| if (!this._needsProgramCounterImage || !this.element.contentDocument) |
| return; |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "program-counter", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| this._drawProgramCounterInContext(ctx, true); |
| |
| delete this._needsProgramCounterImage; |
| }, |
| |
| _drawBreakpointImagesIfNeeded: function(conditional) |
| { |
| if (!this._needsBreakpointImages || !this.element.contentDocument) |
| return; |
| |
| function drawBreakpoint(ctx, disabled, conditional) |
| { |
| ctx.beginPath(); |
| ctx.moveTo(0, 2); |
| ctx.lineTo(2, 0); |
| ctx.lineTo(21, 0); |
| ctx.lineTo(26, 5.5); |
| ctx.lineTo(21, 11); |
| ctx.lineTo(2, 11); |
| ctx.lineTo(0, 9); |
| ctx.closePath(); |
| ctx.fillStyle = conditional ? "rgb(217, 142, 1)" : "rgb(1, 142, 217)"; |
| ctx.strokeStyle = conditional ? "rgb(205, 103, 0)" : "rgb(0, 103, 205)"; |
| ctx.lineWidth = 3; |
| ctx.fill(); |
| ctx.save(); |
| ctx.clip(); |
| ctx.stroke(); |
| ctx.restore(); |
| |
| if (!disabled) |
| return; |
| |
| ctx.save(); |
| ctx.globalCompositeOperation = "destination-out"; |
| ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; |
| ctx.fillRect(0, 0, 26, 11); |
| ctx.restore(); |
| } |
| |
| |
| // Unconditional breakpoints. |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-program-counter", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx); |
| ctx.clearRect(20, 0, 6, 11); |
| this._drawProgramCounterInContext(ctx, true); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, true); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled-program-counter", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, true); |
| ctx.clearRect(20, 0, 6, 11); |
| this._drawProgramCounterInContext(ctx, true); |
| |
| |
| // Conditional breakpoints. |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-conditional", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, false, true); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-conditional-program-counter", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, false, true); |
| ctx.clearRect(20, 0, 6, 11); |
| this._drawProgramCounterInContext(ctx, true); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled-conditional", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, true, true); |
| |
| var ctx = this.element.contentDocument.getCSSCanvasContext("2d", "breakpoint-disabled-conditional-program-counter", 26, 11); |
| ctx.clearRect(0, 0, 26, 11); |
| drawBreakpoint(ctx, true, true); |
| ctx.clearRect(20, 0, 6, 11); |
| this._drawProgramCounterInContext(ctx, true); |
| |
| delete this._needsBreakpointImages; |
| }, |
| |
| syntaxHighlightJavascript: function() |
| { |
| var table = this.element.contentDocument.getElementsByTagName("table")[0]; |
| if (!table) |
| return; |
| |
| var jsSyntaxHighlighter = new WebInspector.JavaScriptSourceSyntaxHighlighter(table, this); |
| jsSyntaxHighlighter.process(); |
| }, |
| |
| syntaxHighlightCSS: function() |
| { |
| var table = this.element.contentDocument.getElementsByTagName("table")[0]; |
| if (!table) |
| return; |
| |
| var cssSyntaxHighlighter = new WebInspector.CSSSourceSyntaxHighligher(table, this); |
| cssSyntaxHighlighter.process(); |
| } |
| } |
| |
| WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype; |
| |
| WebInspector.SourceSyntaxHighligher = function(table, sourceFrame) |
| { |
| this.table = table; |
| this.sourceFrame = sourceFrame; |
| } |
| |
| WebInspector.SourceSyntaxHighligher.prototype = { |
| createSpan: function(content, className) |
| { |
| var span = document.createElement("span"); |
| span.className = className; |
| span.appendChild(document.createTextNode(content)); |
| return span; |
| }, |
| |
| generateFinder: function(regex, matchNumber, className) |
| { |
| return function(str) { |
| var match = regex.exec(str); |
| if (!match) |
| return null; |
| this.previousMatchLength = match[matchNumber].length; |
| return this.createSpan(match[matchNumber], className); |
| }; |
| }, |
| |
| process: function() |
| { |
| // Split up the work into chunks so we don't block the |
| // UI thread while processing. |
| |
| var i = 0; |
| var rows = this.table.rows; |
| var rowsLength = rows.length; |
| var previousCell = null; |
| const linesPerChunk = 10; |
| |
| function processChunk() |
| { |
| for (var end = Math.min(i + linesPerChunk, rowsLength); i < end; ++i) { |
| var row = rows[i]; |
| if (!row) |
| continue; |
| var cell = row.cells[1]; |
| if (!cell) |
| continue; |
| this.syntaxHighlightLine(cell, previousCell); |
| if (i < (end - 1)) |
| this.deleteContinueFlags(previousCell); |
| previousCell = cell; |
| } |
| |
| if (i >= rowsLength && processChunkInterval) { |
| this.deleteContinueFlags(previousCell); |
| delete this.previousMatchLength; |
| clearInterval(processChunkInterval); |
| |
| this.sourceFrame.dispatchEventToListeners("syntax highlighting complete"); |
| } |
| } |
| |
| var boundProcessChunk = processChunk.bind(this); |
| var processChunkInterval = setInterval(boundProcessChunk, 25); |
| boundProcessChunk(); |
| } |
| } |
| |
| WebInspector.CSSSourceSyntaxHighligher = function(table, sourceFrame) { |
| WebInspector.SourceSyntaxHighligher.call(this, table, sourceFrame); |
| |
| this.findNumber = this.generateFinder(/^((-?(\d+|\d*\.\d+))|^(#[a-fA-F0-9]{3,6}))(?:\D|$)/, 1, "webkit-css-number"); |
| this.findUnits = this.generateFinder(/^(px|em|pt|in|cm|mm|pc|ex)(?:\W|$)/, 1, "webkit-css-unit"); |
| this.findKeyword = this.generateFinder(/^(rgba?|hsla?|var)(?:\W|$)/, 1, "webkit-css-keyword"); |
| this.findSingleLineString = this.generateFinder(/^"(?:[^"\\]|\\.)*"|^'([^'\\]|\\.)*'/, 0, "webkit-css-string"); // " this quote keeps Xcode happy |
| this.findSingleLineComment = this.generateFinder(/^\/\*.*?\*\//, 0, "webkit-css-comment"); |
| this.findMultilineCommentStart = this.generateFinder(/^\/\*.*$/, 0, "webkit-css-comment"); |
| this.findMultilineCommentEnd = this.generateFinder(/^.*?\*\//, 0, "webkit-css-comment"); |
| this.findSelector = this.generateFinder(/^([#\.]?[_a-zA-Z].*?)(?:\W|$)/, 1, "webkit-css-selector"); |
| this.findProperty = this.generateFinder(/^(-?[_a-z0-9][_a-z0-9-]*\s*)(?:\:)/, 1, "webkit-css-property"); |
| this.findGenericIdent = this.generateFinder(/^([@-]?[_a-z0-9][_a-z0-9-]*)(?:\W|$)/, 1, "webkit-css-string"); |
| } |
| |
| WebInspector.CSSSourceSyntaxHighligher.prototype = { |
| deleteContinueFlags: function(cell) |
| { |
| if (!cell) |
| return; |
| delete cell._commentContinues; |
| delete cell._inSelector; |
| }, |
| |
| findPseudoClass: function(str) |
| { |
| var match = /^(::?)([_a-z0-9][_a-z0-9-]*)/.exec(str); |
| if (!match) |
| return null; |
| this.previousMatchLength = match[0].length; |
| var span = document.createElement("span"); |
| span.appendChild(document.createTextNode(match[1])); |
| span.appendChild(this.createSpan(match[2], "webkit-css-pseudo-class")); |
| return span; |
| }, |
| |
| findURL: function(str) |
| { |
| var match = /^(?:local|url)\(([^\)]*?)\)/.exec(str); |
| if (!match) |
| return null; |
| this.previousMatchLength = match[0].length; |
| var innerUrlSpan = this.createSpan(match[1], "webkit-css-url"); |
| var outerSpan = document.createElement("span"); |
| outerSpan.appendChild(this.createSpan("url", "webkit-css-keyword")); |
| outerSpan.appendChild(document.createTextNode("(")); |
| outerSpan.appendChild(innerUrlSpan); |
| outerSpan.appendChild(document.createTextNode(")")); |
| return outerSpan; |
| }, |
| |
| findAtRule: function(str) |
| { |
| var match = /^@[_a-z0-9][_a-z0-9-]*(?:\W|$)/.exec(str); |
| if (!match) |
| return null; |
| this.previousMatchLength = match[0].length; |
| return this.createSpan(match[0], "webkit-css-at-rule"); |
| }, |
| |
| syntaxHighlightLine: function(line, prevLine) |
| { |
| var code = line.textContent; |
| while (line.firstChild) |
| line.removeChild(line.firstChild); |
| |
| var token; |
| var tmp = 0; |
| var i = 0; |
| this.previousMatchLength = 0; |
| |
| if (prevLine) { |
| if (prevLine._commentContinues) { |
| if (!(token = this.findMultilineCommentEnd(code))) { |
| token = this.createSpan(code, "webkit-javascript-comment"); |
| line._commentContinues = true; |
| } |
| } |
| if (token) { |
| i += this.previousMatchLength ? this.previousMatchLength : code.length; |
| tmp = i; |
| line.appendChild(token); |
| } |
| } |
| |
| var inSelector = (prevLine && prevLine._inSelector); // inside a selector, we can now parse properties and values |
| var inAtRuleBlock = (prevLine && prevLine._inAtRuleBlock); // inside an @rule block, but not necessarily inside a selector yet |
| var atRuleStarted = (prevLine && prevLine._atRuleStarted); // we received an @rule, we may stop the @rule at a semicolon or open a block and become inAtRuleBlock |
| var atRuleIsSelector = (prevLine && prevLine._atRuleIsSelector); // when this @rule opens a block it immediately goes into parsing properties and values instead of selectors |
| |
| for ( ; i < code.length; ++i) { |
| var codeFragment = code.substr(i); |
| var prevChar = code[i - 1]; |
| var currChar = codeFragment[0]; |
| token = this.findSingleLineComment(codeFragment); |
| if (!token) { |
| if ((token = this.findMultilineCommentStart(codeFragment))) |
| line._commentContinues = true; |
| else if (currChar === ";" && !inAtRuleBlock) |
| atRuleStarted = false; |
| else if (currChar === "}") { |
| if (inSelector && inAtRuleBlock && atRuleIsSelector) { |
| inSelector = false; |
| inAtRuleBlock = false; |
| atRuleStarted = false; |
| } else if (inSelector) { |
| inSelector = false; |
| } else if (inAtRuleBlock) { |
| inAtRuleBlock = false; |
| atRuleStarted = false; |
| } |
| } else if (currChar === "{") { |
| if (!atRuleStarted || inAtRuleBlock) { |
| inSelector = true; |
| } else if (!inAtRuleBlock && atRuleIsSelector) { |
| inAtRuleBlock = true; |
| inSelector = true; |
| } else if (!inAtRuleBlock) { |
| inAtRuleBlock = true; |
| inSelector = false; |
| } |
| } else if (inSelector) { |
| if (!prevChar || /^\d/.test(prevChar)) { |
| token = this.findUnits(codeFragment); |
| } else if (!prevChar || /^\W/.test(prevChar)) { |
| token = this.findNumber(codeFragment) || |
| this.findKeyword(codeFragment) || |
| this.findURL(codeFragment) || |
| this.findProperty(codeFragment) || |
| this.findAtRule(codeFragment) || |
| this.findGenericIdent(codeFragment) || |
| this.findSingleLineString(codeFragment); |
| } |
| } else if (!inSelector) { |
| if (atRuleStarted && !inAtRuleBlock) |
| token = this.findURL(codeFragment); // for @import |
| if (!token) { |
| token = this.findSelector(codeFragment) || |
| this.findPseudoClass(codeFragment) || |
| this.findAtRule(codeFragment); |
| } |
| } |
| } |
| |
| if (token) { |
| if (currChar === "@") { |
| atRuleStarted = true; |
| |
| // The @font-face, @page, and @variables at-rules do not contain selectors like other at-rules |
| // instead it acts as a selector and contains properties and values. |
| var text = token.textContent; |
| atRuleIsSelector = /font-face/.test(text) || /page/.test(text) || /variables/.test(text); |
| } |
| |
| if (tmp !== i) |
| line.appendChild(document.createTextNode(code.substring(tmp, i))); |
| line.appendChild(token); |
| i += this.previousMatchLength - 1; |
| tmp = i + 1; |
| } |
| } |
| |
| line._inSelector = inSelector; |
| line._inAtRuleBlock = inAtRuleBlock; |
| line._atRuleStarted = atRuleStarted; |
| line._atRuleIsSelector = atRuleIsSelector; |
| |
| if (tmp < code.length) |
| line.appendChild(document.createTextNode(code.substring(tmp, i))); |
| } |
| } |
| |
| WebInspector.CSSSourceSyntaxHighligher.prototype.__proto__ = WebInspector.SourceSyntaxHighligher.prototype; |
| |
| WebInspector.JavaScriptSourceSyntaxHighlighter = function(table, sourceFrame) { |
| WebInspector.SourceSyntaxHighligher.call(this, table, sourceFrame); |
| |
| this.LexState = { |
| Initial: 1, |
| DivisionAllowed: 2, |
| }; |
| this.ContinueState = { |
| None: 0, |
| Comment: 1, |
| SingleQuoteString: 2, |
| DoubleQuoteString: 3, |
| RegExp: 4 |
| }; |
| |
| this.nonToken = ""; |
| this.cursor = 0; |
| this.lineIndex = -1; |
| this.lineCode = ""; |
| this.lineFragment = null; |
| this.lexState = this.LexState.Initial; |
| this.continueState = this.ContinueState.None; |
| |
| this.rules = [{ |
| pattern: /^(?:\/\/.*)/, |
| action: singleLineCommentAction |
| }, { |
| pattern: /^(?:\/\*(?:[^\*]|\*[^\/])*\*+\/)/, |
| action: multiLineSingleLineCommentAction |
| }, { |
| pattern: /^(?:\/\*(?:[^\*]|\*[^\/])*)/, |
| action: multiLineCommentStartAction |
| }, { |
| pattern: /^(?:(?:[^\*]|\*[^\/])*\*+\/)/, |
| action: multiLineCommentEndAction, |
| continueStateCondition: this.ContinueState.Comment |
| }, { |
| pattern: /^.*/, |
| action: multiLineCommentMiddleAction, |
| continueStateCondition: this.ContinueState.Comment |
| }, { |
| pattern: /^(?:(?:0|[1-9]\d*)\.\d+?(?:[eE](?:\d+|\+\d+|-\d+))?|\.\d+(?:[eE](?:\d+|\+\d+|-\d+))?|(?:0|[1-9]\d*)(?:[eE](?:\d+|\+\d+|-\d+))?|0x[0-9a-fA-F]+|0X[0-9a-fA-F]+)/, |
| action: numericLiteralAction |
| }, { |
| pattern: /^(?:"(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*"|'(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*')/, |
| action: stringLiteralAction |
| }, { |
| pattern: /^(?:'(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/, |
| action: singleQuoteStringStartAction |
| }, { |
| pattern: /^(?:(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*')/, |
| action: singleQuoteStringEndAction, |
| continueStateCondition: this.ContinueState.SingleQuoteString |
| }, { |
| pattern: /^(?:(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/, |
| action: singleQuoteStringMiddleAction, |
| continueStateCondition: this.ContinueState.SingleQuoteString |
| }, { |
| pattern: /^(?:"(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/, |
| action: doubleQuoteStringStartAction |
| }, { |
| pattern: /^(?:(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*")/, |
| action: doubleQuoteStringEndAction, |
| continueStateCondition: this.ContinueState.DoubleQuoteString |
| }, { |
| pattern: /^(?:(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/, |
| action: doubleQuoteStringMiddleAction, |
| continueStateCondition: this.ContinueState.DoubleQuoteString |
| }, { |
| pattern: /^(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/, |
| action: identOrKeywordAction, |
| dontAppendNonToken: true |
| }, { |
| pattern: /^\)/, |
| action: rightParenAction, |
| dontAppendNonToken: true |
| }, { |
| pattern: /^(?:<=|>=|===|==|!=|!==|\+\+|\-\-|<<|>>|>>>|&&|\|\||\+=|\-=|\*=|%=|<<=|>>=|>>>=|&=|\|=|^=|[{}\(\[\]\.;,<>\+\-\*%&\|\^!~\?:=])/, |
| action: punctuatorAction, |
| dontAppendNonToken: true |
| }, { |
| pattern: /^(?:\/=?)/, |
| action: divPunctuatorAction, |
| stateCondition: this.LexState.DivisionAllowed, |
| dontAppendNonToken: true |
| }, { |
| pattern: /^(?:\/(?:(?:\\.)|[^\\*\/])(?:(?:\\.)|[^\\/])*\/(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/, |
| action: regExpLiteralAction |
| }, { |
| pattern: /^(?:\/(?:(?:\\.)|[^\\*\/])(?:(?:\\.)|[^\\/])*)\\$/, |
| action: regExpStartAction |
| }, { |
| pattern: /^(?:(?:(?:\\.)|[^\\/])*\/(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/, |
| action: regExpEndAction, |
| continueStateCondition: this.ContinueState.RegExp |
| }, { |
| pattern: /^(?:(?:(?:\\.)|[^\\/])*)\\$/, |
| action: regExpMiddleAction, |
| continueStateCondition: this.ContinueState.RegExp |
| }]; |
| |
| function singleLineCommentAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-comment")); |
| } |
| |
| function multiLineSingleLineCommentAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-comment")); |
| } |
| |
| function multiLineCommentStartAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-comment")); |
| this.continueState = this.ContinueState.Comment; |
| } |
| |
| function multiLineCommentEndAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-comment")); |
| this.continueState = this.ContinueState.None; |
| } |
| |
| function multiLineCommentMiddleAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-comment")); |
| } |
| |
| function numericLiteralAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-number")); |
| this.lexState = this.LexState.DivisionAllowed; |
| } |
| |
| function stringLiteralAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| this.lexState = this.LexState.Initial; |
| } |
| |
| function singleQuoteStringStartAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| this.continueState = this.ContinueState.SingleQuoteString; |
| } |
| |
| function singleQuoteStringEndAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| this.continueState = this.ContinueState.None; |
| } |
| |
| function singleQuoteStringMiddleAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| } |
| |
| function doubleQuoteStringStartAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| this.continueState = this.ContinueState.DoubleQuoteString; |
| } |
| |
| function doubleQuoteStringEndAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| this.continueState = this.ContinueState.None; |
| } |
| |
| function doubleQuoteStringMiddleAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-string")); |
| } |
| |
| function regExpLiteralAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-regexp")); |
| this.lexState = this.LexState.Initial; |
| } |
| |
| function regExpStartAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-regexp")); |
| this.continueState = this.ContinueState.RegExp; |
| } |
| |
| function regExpEndAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-regexp")); |
| this.continueState = this.ContinueState.None; |
| } |
| |
| function regExpMiddleAction(token) |
| { |
| this.cursor += token.length; |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-regexp")); |
| } |
| |
| function identOrKeywordAction(token) |
| { |
| const keywords = ["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"]; |
| this.cursor += token.length; |
| if (keywords.indexOf(token) === -1) { |
| this.nonToken += token; |
| this.lexState = this.LexState.DivisionAllowed; |
| } else { |
| this.appendNonToken(); |
| this.lineFragment.appendChild(this.createSpan(token, "webkit-javascript-keyword")); |
| this.lexState = this.LexState.Initial; |
| } |
| } |
| |
| function divPunctuatorAction(token) |
| { |
| this.cursor += token.length; |
| this.nonToken += token; |
| this.lexState = this.LexState.Initial; |
| } |
| |
| function rightParenAction(token) |
| { |
| this.cursor += token.length; |
| this.nonToken += token; |
| this.lexState = this.LexState.DivisionAllowed; |
| } |
| |
| function punctuatorAction(token) |
| { |
| this.cursor += token.length; |
| this.nonToken += token; |
| this.lexState = this.LexState.Initial; |
| } |
| } |
| |
| WebInspector.JavaScriptSourceSyntaxHighlighter.prototype = { |
| process: function() |
| { |
| // Split up the work into chunks so we don't block the |
| // UI thread while processing. |
| |
| var rows = this.table.rows; |
| var rowsLength = rows.length; |
| const tokensPerChunk = 100; |
| const lineLengthLimit = 20000; |
| |
| var boundProcessChunk = processChunk.bind(this); |
| var processChunkInterval = setInterval(boundProcessChunk, 25); |
| boundProcessChunk(); |
| |
| function processChunk() |
| { |
| for (var i = 0; i < tokensPerChunk; i++) { |
| if (this.cursor >= this.lineCode.length) |
| moveToNextLine.call(this); |
| if (this.lineIndex >= rowsLength) { |
| this.sourceFrame.dispatchEventToListeners("syntax highlighting complete"); |
| return; |
| } |
| if (this.cursor > lineLengthLimit) { |
| var codeFragment = this.lineCode.substring(this.cursor); |
| this.nonToken += codeFragment; |
| this.cursor += codeFragment.length; |
| } |
| |
| this.lex(); |
| } |
| } |
| |
| function moveToNextLine() |
| { |
| this.appendNonToken(); |
| |
| var row = rows[this.lineIndex]; |
| var line = row ? row.cells[1] : null; |
| if (line && this.lineFragment) { |
| var messageBubble = null; |
| if (line.lastChild && line.lastChild.nodeType === Node.ELEMENT_NODE && line.lastChild.hasStyleClass("webkit-html-message-bubble")) { |
| messageBubble = line.lastChild; |
| line.removeChild(messageBubble); |
| } |
| |
| Element.prototype.removeChildren.call(line); |
| |
| line.appendChild(this.lineFragment); |
| if (messageBubble) |
| line.appendChild(messageBubble); |
| this.lineFragment = null; |
| } |
| this.lineIndex++; |
| if (this.lineIndex >= rowsLength && processChunkInterval) { |
| clearInterval(processChunkInterval); |
| this.sourceFrame.dispatchEventToListeners("syntax highlighting complete"); |
| return; |
| } |
| row = rows[this.lineIndex]; |
| line = row ? row.cells[1] : null; |
| this.lineCode = line.textContent; |
| this.lineFragment = document.createDocumentFragment(); |
| this.cursor = 0; |
| if (!line) |
| moveToNextLine(); |
| } |
| }, |
| |
| lex: function() |
| { |
| var token = null; |
| var codeFragment = this.lineCode.substring(this.cursor); |
| |
| for (var i = 0; i < this.rules.length; i++) { |
| var rule = this.rules[i]; |
| var ruleContinueStateCondition = typeof rule.continueStateCondition === "undefined" ? this.ContinueState.None : rule.continueStateCondition; |
| if (this.continueState === ruleContinueStateCondition) { |
| if (typeof rule.stateCondition !== "undefined" && this.lexState !== rule.stateCondition) |
| continue; |
| var match = rule.pattern.exec(codeFragment); |
| if (match) { |
| token = match[0]; |
| if (token) { |
| if (!rule.dontAppendNonToken) |
| this.appendNonToken(); |
| return rule.action.call(this, token); |
| } |
| } |
| } |
| } |
| this.nonToken += codeFragment[0]; |
| this.cursor++; |
| }, |
| |
| appendNonToken: function () |
| { |
| if (this.nonToken.length > 0) { |
| this.lineFragment.appendChild(document.createTextNode(this.nonToken)); |
| this.nonToken = ""; |
| } |
| }, |
| |
| syntaxHighlightNode: function(node) |
| { |
| this.lineCode = node.textContent; |
| this.lineFragment = document.createDocumentFragment(); |
| this.cursor = 0; |
| while (true) { |
| if (this.cursor >= this.lineCode.length) { |
| var codeFragment = this.lineCode.substring(this.cursor); |
| this.nonToken += codeFragment; |
| this.cursor += codeFragment.length; |
| this.appendNonToken(); |
| while (node.firstChild) |
| node.removeChild(node.firstChild); |
| node.appendChild(this.lineFragment); |
| this.lineFragment =null; |
| return; |
| } |
| |
| this.lex(); |
| } |
| } |
| } |
| |
| WebInspector.JavaScriptSourceSyntaxHighlighter.prototype.__proto__ = WebInspector.SourceSyntaxHighligher.prototype; |