12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196 |
- /*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
- * 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.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
- */
- /**
- * @param {Element} element
- * @param {?function(Event): boolean} elementDragStart
- * @param {function(Event)} elementDrag
- * @param {?function(Event)} elementDragEnd
- * @param {string} cursor
- */
- WebInspector.installDragHandle = function(element, elementDragStart, elementDrag, elementDragEnd, cursor)
- {
- element.addEventListener("mousedown", WebInspector._elementDragStart.bind(WebInspector, elementDragStart, elementDrag, elementDragEnd, cursor), false);
- }
- /**
- * @param {?function(Event)} elementDragStart
- * @param {function(Event)} elementDrag
- * @param {?function(Event)} elementDragEnd
- * @param {string} cursor
- * @param {Event} event
- */
- WebInspector._elementDragStart = function(elementDragStart, elementDrag, elementDragEnd, cursor, event)
- {
- // Only drag upon left button. Right will likely cause a context menu. So will ctrl-click on mac.
- if (event.button || (WebInspector.isMac() && event.ctrlKey))
- return;
- if (WebInspector._elementDraggingEventListener)
- return;
- if (elementDragStart && !elementDragStart(event))
- return;
- if (WebInspector._elementDraggingGlassPane) {
- WebInspector._elementDraggingGlassPane.dispose();
- delete WebInspector._elementDraggingGlassPane;
- }
- var targetDocument = event.target.ownerDocument;
- WebInspector._elementDraggingEventListener = elementDrag;
- WebInspector._elementEndDraggingEventListener = elementDragEnd;
- WebInspector._mouseOutWhileDraggingTargetDocument = targetDocument;
- targetDocument.addEventListener("mousemove", WebInspector._elementDragMove, true);
- targetDocument.addEventListener("mouseup", WebInspector._elementDragEnd, true);
- targetDocument.addEventListener("mouseout", WebInspector._mouseOutWhileDragging, true);
- targetDocument.body.style.cursor = cursor;
- event.preventDefault();
- }
- WebInspector._mouseOutWhileDragging = function()
- {
- WebInspector._unregisterMouseOutWhileDragging();
- WebInspector._elementDraggingGlassPane = new WebInspector.GlassPane();
- }
- WebInspector._unregisterMouseOutWhileDragging = function()
- {
- if (!WebInspector._mouseOutWhileDraggingTargetDocument)
- return;
- WebInspector._mouseOutWhileDraggingTargetDocument.removeEventListener("mouseout", WebInspector._mouseOutWhileDragging, true);
- delete WebInspector._mouseOutWhileDraggingTargetDocument;
- }
- WebInspector._elementDragMove = function(event)
- {
- if (WebInspector._elementDraggingEventListener(event))
- WebInspector._cancelDragEvents(event);
- }
- WebInspector._cancelDragEvents = function(event)
- {
- var targetDocument = event.target.ownerDocument;
- targetDocument.removeEventListener("mousemove", WebInspector._elementDragMove, true);
- targetDocument.removeEventListener("mouseup", WebInspector._elementDragEnd, true);
- WebInspector._unregisterMouseOutWhileDragging();
- targetDocument.body.style.removeProperty("cursor");
- if (WebInspector._elementDraggingGlassPane)
- WebInspector._elementDraggingGlassPane.dispose();
- delete WebInspector._elementDraggingGlassPane;
- delete WebInspector._elementDraggingEventListener;
- delete WebInspector._elementEndDraggingEventListener;
- }
- WebInspector._elementDragEnd = function(event)
- {
- var elementDragEnd = WebInspector._elementEndDraggingEventListener;
- WebInspector._cancelDragEvents(event);
- event.preventDefault();
- if (elementDragEnd)
- elementDragEnd(event);
- }
- /**
- * @constructor
- */
- WebInspector.GlassPane = function()
- {
- this.element = document.createElement("div");
- this.element.style.cssText = "position:absolute;top:0;bottom:0;left:0;right:0;background-color:transparent;z-index:1000;";
- this.element.id = "glass-pane";
- document.body.appendChild(this.element);
- WebInspector._glassPane = this;
- }
- WebInspector.GlassPane.prototype = {
- dispose: function()
- {
- delete WebInspector._glassPane;
- if (WebInspector.HelpScreen.isVisible())
- WebInspector.HelpScreen.focus();
- else
- WebInspector.inspectorView.focus();
- this.element.remove();
- }
- }
- WebInspector.animateStyle = function(animations, duration, callback)
- {
- var startTime = new Date().getTime();
- var hasCompleted = false;
- const animationsLength = animations.length;
- const propertyUnit = {opacity: ""};
- const defaultUnit = "px";
- // Pre-process animations.
- for (var i = 0; i < animationsLength; ++i) {
- var animation = animations[i];
- var element = null, start = null, end = null, key = null;
- for (key in animation) {
- if (key === "element")
- element = animation[key];
- else if (key === "start")
- start = animation[key];
- else if (key === "end")
- end = animation[key];
- }
- if (!element || !end)
- continue;
- if (!start) {
- var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
- start = {};
- for (key in end)
- start[key] = parseInt(computedStyle.getPropertyValue(key), 10);
- animation.start = start;
- } else
- for (key in start)
- element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
- }
- function animateLoop()
- {
- if (hasCompleted)
- return;
- var complete = new Date().getTime() - startTime;
- // Make style changes.
- for (var i = 0; i < animationsLength; ++i) {
- var animation = animations[i];
- var element = animation.element;
- var start = animation.start;
- var end = animation.end;
- if (!element || !end)
- continue;
- var style = element.style;
- for (key in end) {
- var endValue = end[key];
- if (complete < duration) {
- var startValue = start[key];
- // Linear animation.
- var newValue = startValue + (endValue - startValue) * complete / duration;
- style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
- } else
- style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
- }
- }
- // End condition.
- if (complete >= duration)
- hasCompleted = true;
- if (callback)
- callback(hasCompleted);
- if (!hasCompleted)
- window.requestAnimationFrame(animateLoop);
- }
- function forceComplete()
- {
- if (hasCompleted)
- return;
- duration = 0;
- animateLoop();
- }
- window.requestAnimationFrame(animateLoop);
- return {
- forceComplete: forceComplete
- };
- }
- WebInspector.isBeingEdited = function(element)
- {
- if (element.hasStyleClass("text-prompt") || element.nodeName === "INPUT" || element.nodeName === "TEXTAREA")
- return true;
- if (!WebInspector.__editingCount)
- return false;
- while (element) {
- if (element.__editing)
- return true;
- element = element.parentElement;
- }
- return false;
- }
- WebInspector.markBeingEdited = function(element, value)
- {
- if (value) {
- if (element.__editing)
- return false;
- element.addStyleClass("being-edited");
- element.__editing = true;
- WebInspector.__editingCount = (WebInspector.__editingCount || 0) + 1;
- } else {
- if (!element.__editing)
- return false;
- element.removeStyleClass("being-edited");
- delete element.__editing;
- --WebInspector.__editingCount;
- }
- return true;
- }
- /**
- * @constructor
- * @param {function(Element,string,string,*,string)} commitHandler
- * @param {function(Element,*)} cancelHandler
- * @param {*=} context
- */
- WebInspector.EditingConfig = function(commitHandler, cancelHandler, context)
- {
- this.commitHandler = commitHandler;
- this.cancelHandler = cancelHandler
- this.context = context;
- /**
- * Handles the "paste" event, return values are the same as those for customFinishHandler
- * @type {function(Element)|undefined}
- */
- this.pasteHandler;
- /**
- * Whether the edited element is multiline
- * @type {boolean|undefined}
- */
- this.multiline;
- /**
- * Custom finish handler for the editing session (invoked on keydown)
- * @type {function(Element,*)|undefined}
- */
- this.customFinishHandler;
- }
- WebInspector.EditingConfig.prototype = {
- setPasteHandler: function(pasteHandler)
- {
- this.pasteHandler = pasteHandler;
- },
- /**
- * @param {string} initialValue
- * @param {Object} mode
- * @param {string} theme
- * @param {boolean=} lineWrapping
- * @param {boolean=} smartIndent
- */
- setMultilineOptions: function(initialValue, mode, theme, lineWrapping, smartIndent)
- {
- this.multiline = true;
- this.initialValue = initialValue;
- this.mode = mode;
- this.theme = theme;
- this.lineWrapping = lineWrapping;
- this.smartIndent = smartIndent;
- },
- setCustomFinishHandler: function(customFinishHandler)
- {
- this.customFinishHandler = customFinishHandler;
- }
- }
- WebInspector.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/;
- WebInspector.StyleValueDelimiters = " \xA0\t\n\"':;,/()";
- /**
- * @param {Event} event
- * @return {?string}
- */
- WebInspector._valueModificationDirection = function(event)
- {
- var direction = null;
- if (event.type === "mousewheel") {
- if (event.wheelDeltaY > 0)
- direction = "Up";
- else if (event.wheelDeltaY < 0)
- direction = "Down";
- } else {
- if (event.keyIdentifier === "Up" || event.keyIdentifier === "PageUp")
- direction = "Up";
- else if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown")
- direction = "Down";
- }
- return direction;
- }
- /**
- * @param {string} hexString
- * @param {Event} event
- */
- WebInspector._modifiedHexValue = function(hexString, event)
- {
- var direction = WebInspector._valueModificationDirection(event);
- if (!direction)
- return hexString;
- var number = parseInt(hexString, 16);
- if (isNaN(number) || !isFinite(number))
- return hexString;
- var maxValue = Math.pow(16, hexString.length) - 1;
- var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel");
- var delta;
- if (arrowKeyOrMouseWheelEvent)
- delta = (direction === "Up") ? 1 : -1;
- else
- delta = (event.keyIdentifier === "PageUp") ? 16 : -16;
- if (event.shiftKey)
- delta *= 16;
- var result = number + delta;
- if (result < 0)
- result = 0; // Color hex values are never negative, so clamp to 0.
- else if (result > maxValue)
- return hexString;
- // Ensure the result length is the same as the original hex value.
- var resultString = result.toString(16).toUpperCase();
- for (var i = 0, lengthDelta = hexString.length - resultString.length; i < lengthDelta; ++i)
- resultString = "0" + resultString;
- return resultString;
- }
- /**
- * @param {number} number
- * @param {Event} event
- */
- WebInspector._modifiedFloatNumber = function(number, event)
- {
- var direction = WebInspector._valueModificationDirection(event);
- if (!direction)
- return number;
-
- var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel");
- // Jump by 10 when shift is down or jump by 0.1 when Alt/Option is down.
- // Also jump by 10 for page up and down, or by 100 if shift is held with a page key.
- var changeAmount = 1;
- if (event.shiftKey && !arrowKeyOrMouseWheelEvent)
- changeAmount = 100;
- else if (event.shiftKey || !arrowKeyOrMouseWheelEvent)
- changeAmount = 10;
- else if (event.altKey)
- changeAmount = 0.1;
- if (direction === "Down")
- changeAmount *= -1;
- // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns.
- // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
- var result = Number((number + changeAmount).toFixed(6));
- if (!String(result).match(WebInspector.CSSNumberRegex))
- return null;
- return result;
- }
- /**
- * @param {Event} event
- * @param {Element} element
- * @param {function(string,string)=} finishHandler
- * @param {function(string)=} suggestionHandler
- * @param {function(number):number=} customNumberHandler
- */
- WebInspector.handleElementValueModifications = function(event, element, finishHandler, suggestionHandler, customNumberHandler)
- {
- var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel");
- var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown");
- if (!arrowKeyOrMouseWheelEvent && !pageKeyPressed)
- return false;
- var selection = window.getSelection();
- if (!selection.rangeCount)
- return false;
- var selectionRange = selection.getRangeAt(0);
- if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element))
- return false;
- var originalValue = element.textContent;
- var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StyleValueDelimiters, element);
- var wordString = wordRange.toString();
-
- if (suggestionHandler && suggestionHandler(wordString))
- return false;
- var replacementString;
- var prefix, suffix, number;
- var matches;
- matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString);
- if (matches && matches.length) {
- prefix = matches[1];
- suffix = matches[3];
- number = WebInspector._modifiedHexValue(matches[2], event);
-
- if (customNumberHandler)
- number = customNumberHandler(number);
- replacementString = prefix + number + suffix;
- } else {
- matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
- if (matches && matches.length) {
- prefix = matches[1];
- suffix = matches[3];
- number = WebInspector._modifiedFloatNumber(parseFloat(matches[2]), event);
-
- // Need to check for null explicitly.
- if (number === null)
- return false;
-
- if (customNumberHandler)
- number = customNumberHandler(number);
- replacementString = prefix + number + suffix;
- }
- }
- if (replacementString) {
- var replacementTextNode = document.createTextNode(replacementString);
- wordRange.deleteContents();
- wordRange.insertNode(replacementTextNode);
- var finalSelectionRange = document.createRange();
- finalSelectionRange.setStart(replacementTextNode, 0);
- finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
- selection.removeAllRanges();
- selection.addRange(finalSelectionRange);
- event.handled = true;
- event.preventDefault();
-
- if (finishHandler)
- finishHandler(originalValue, replacementString);
- return true;
- }
- return false;
- }
- /**
- * @param {Element} element
- * @param {WebInspector.EditingConfig=} config
- * @return {?{cancel: function(), commit: function(), codeMirror: CodeMirror, setWidth: function(number)}}
- */
- WebInspector.startEditing = function(element, config)
- {
- if (!WebInspector.markBeingEdited(element, true))
- return null;
- config = config || new WebInspector.EditingConfig(function() {}, function() {});
- var committedCallback = config.commitHandler;
- var cancelledCallback = config.cancelHandler;
- var pasteCallback = config.pasteHandler;
- var context = config.context;
- var isMultiline = config.multiline || false;
- var oldText = isMultiline ? config.initialValue : getContent(element);
- var moveDirection = "";
- var oldTabIndex;
- var codeMirror;
- var cssLoadView;
- /**
- * @param {Event} e
- */
- function consumeCopy(e)
- {
- e.consume();
- }
- if (isMultiline) {
- loadScript("CodeMirrorTextEditor.js");
- cssLoadView = new WebInspector.CodeMirrorCSSLoadView();
- cssLoadView.show(element);
- WebInspector.setCurrentFocusElement(element);
- element.addEventListener("copy", consumeCopy, false);
- codeMirror = window.CodeMirror(element, {
- mode: config.mode,
- lineWrapping: config.lineWrapping,
- smartIndent: config.smartIndent,
- autofocus: true,
- theme: config.theme,
- value: oldText
- });
- codeMirror.getWrapperElement().addStyleClass("source-code");
- codeMirror.on("cursorActivity", function(cm) {
- cm.display.cursor.scrollIntoViewIfNeeded(false);
- });
- } else {
- element.addStyleClass("editing");
- oldTabIndex = element.getAttribute("tabIndex");
- if (typeof oldTabIndex !== "number" || oldTabIndex < 0)
- element.tabIndex = 0;
- WebInspector.setCurrentFocusElement(element);
- }
- /**
- * @param {number} width
- */
- function setWidth(width)
- {
- const padding = 30;
- codeMirror.getWrapperElement().style.width = (width - codeMirror.getWrapperElement().offsetLeft - padding) + "px";
- codeMirror.refresh();
- }
- /**
- * @param {Event=} e
- */
- function blurEventListener(e) {
- if (!isMultiline || !e || !e.relatedTarget || !e.relatedTarget.isSelfOrDescendant(element))
- editingCommitted.call(element);
- }
- function getContent(element) {
- if (isMultiline)
- return codeMirror.getValue();
- if (element.tagName === "INPUT" && element.type === "text")
- return element.value;
- return element.textContent;
- }
- /** @this {Element} */
- function cleanUpAfterEditing()
- {
- WebInspector.markBeingEdited(element, false);
- element.removeEventListener("blur", blurEventListener, isMultiline);
- element.removeEventListener("keydown", keyDownEventListener, true);
- if (pasteCallback)
- element.removeEventListener("paste", pasteEventListener, true);
- WebInspector.restoreFocusFromElement(element);
- if (isMultiline) {
- element.removeEventListener("copy", consumeCopy, false);
- cssLoadView.detach();
- return;
- }
- this.removeStyleClass("editing");
-
- if (typeof oldTabIndex !== "number")
- element.removeAttribute("tabIndex");
- else
- this.tabIndex = oldTabIndex;
- this.scrollTop = 0;
- this.scrollLeft = 0;
- }
- /** @this {Element} */
- function editingCancelled()
- {
- if (isMultiline)
- codeMirror.setValue(oldText);
- else {
- if (this.tagName === "INPUT" && this.type === "text")
- this.value = oldText;
- else
- this.textContent = oldText;
- }
- cleanUpAfterEditing.call(this);
- cancelledCallback(this, context);
- }
- /** @this {Element} */
- function editingCommitted()
- {
- cleanUpAfterEditing.call(this);
- committedCallback(this, getContent(this), oldText, context, moveDirection);
- }
- function defaultFinishHandler(event)
- {
- var isMetaOrCtrl = WebInspector.isMac() ?
- event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey :
- event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;
- if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !isMultiline || isMetaOrCtrl))
- return "commit";
- else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
- return "cancel";
- else if (!isMultiline && event.keyIdentifier === "U+0009") // Tab key
- return "move-" + (event.shiftKey ? "backward" : "forward");
- }
- function handleEditingResult(result, event)
- {
- if (result === "commit") {
- editingCommitted.call(element);
- event.consume(true);
- } else if (result === "cancel") {
- editingCancelled.call(element);
- event.consume(true);
- } else if (result && result.startsWith("move-")) {
- moveDirection = result.substring(5);
- if (event.keyIdentifier !== "U+0009")
- blurEventListener();
- }
- }
- function pasteEventListener(event)
- {
- var result = pasteCallback(event);
- handleEditingResult(result, event);
- }
- function keyDownEventListener(event)
- {
- var handler = config.customFinishHandler || defaultFinishHandler;
- var result = handler(event);
- handleEditingResult(result, event);
- }
- element.addEventListener("blur", blurEventListener, isMultiline);
- element.addEventListener("keydown", keyDownEventListener, true);
- if (pasteCallback)
- element.addEventListener("paste", pasteEventListener, true);
- return {
- cancel: editingCancelled.bind(element),
- commit: editingCommitted.bind(element),
- codeMirror: codeMirror, // For testing.
- setWidth: setWidth
- };
- }
- /**
- * @param {number} seconds
- * @param {boolean=} higherResolution
- * @return {string}
- */
- Number.secondsToString = function(seconds, higherResolution)
- {
- if (!isFinite(seconds))
- return "-";
- if (seconds === 0)
- return "0";
- var ms = seconds * 1000;
- if (higherResolution && ms < 1000)
- return WebInspector.UIString("%.3f\u2009ms", ms);
- else if (ms < 1000)
- return WebInspector.UIString("%.0f\u2009ms", ms);
- if (seconds < 60)
- return WebInspector.UIString("%.2f\u2009s", seconds);
- var minutes = seconds / 60;
- if (minutes < 60)
- return WebInspector.UIString("%.1f\u2009min", minutes);
- var hours = minutes / 60;
- if (hours < 24)
- return WebInspector.UIString("%.1f\u2009hrs", hours);
- var days = hours / 24;
- return WebInspector.UIString("%.1f\u2009days", days);
- }
- /**
- * @param {number} bytes
- * @return {string}
- */
- Number.bytesToString = function(bytes)
- {
- if (bytes < 1024)
- return WebInspector.UIString("%.0f\u2009B", bytes);
- var kilobytes = bytes / 1024;
- if (kilobytes < 100)
- return WebInspector.UIString("%.1f\u2009KB", kilobytes);
- if (kilobytes < 1024)
- return WebInspector.UIString("%.0f\u2009KB", kilobytes);
- var megabytes = kilobytes / 1024;
- if (megabytes < 100)
- return WebInspector.UIString("%.1f\u2009MB", megabytes);
- else
- return WebInspector.UIString("%.0f\u2009MB", megabytes);
- }
- Number.withThousandsSeparator = function(num)
- {
- var str = num + "";
- var re = /(\d+)(\d{3})/;
- while (str.match(re))
- str = str.replace(re, "$1\u2009$2"); // \u2009 is a thin space.
- return str;
- }
- WebInspector.useLowerCaseMenuTitles = function()
- {
- return WebInspector.platform() === "windows";
- }
- WebInspector.formatLocalized = function(format, substitutions, formatters, initialValue, append)
- {
- return String.format(WebInspector.UIString(format), substitutions, formatters, initialValue, append);
- }
- WebInspector.openLinkExternallyLabel = function()
- {
- return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open link in new tab" : "Open Link in New Tab");
- }
- WebInspector.copyLinkAddressLabel = function()
- {
- return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy link address" : "Copy Link Address");
- }
- WebInspector.platform = function()
- {
- if (!WebInspector._platform)
- WebInspector._platform = InspectorFrontendHost.platform();
- return WebInspector._platform;
- }
- WebInspector.isMac = function()
- {
- if (typeof WebInspector._isMac === "undefined")
- WebInspector._isMac = WebInspector.platform() === "mac";
- return WebInspector._isMac;
- }
- WebInspector.isWin = function()
- {
- if (typeof WebInspector._isWin === "undefined")
- WebInspector._isWin = WebInspector.platform() === "windows";
- return WebInspector._isWin;
- }
- WebInspector.PlatformFlavor = {
- WindowsVista: "windows-vista",
- MacTiger: "mac-tiger",
- MacLeopard: "mac-leopard",
- MacSnowLeopard: "mac-snowleopard",
- MacLion: "mac-lion",
- MacMountainLion: "mac-mountain-lion"
- }
- WebInspector.platformFlavor = function()
- {
- function detectFlavor()
- {
- const userAgent = navigator.userAgent;
- if (WebInspector.platform() === "windows") {
- var match = userAgent.match(/Windows NT (\d+)\.(?:\d+)/);
- if (match && match[1] >= 6)
- return WebInspector.PlatformFlavor.WindowsVista;
- return null;
- } else if (WebInspector.platform() === "mac") {
- var match = userAgent.match(/Mac OS X\s*(?:(\d+)_(\d+))?/);
- if (!match || match[1] != 10)
- return WebInspector.PlatformFlavor.MacSnowLeopard;
- switch (Number(match[2])) {
- case 4:
- return WebInspector.PlatformFlavor.MacTiger;
- case 5:
- return WebInspector.PlatformFlavor.MacLeopard;
- case 6:
- return WebInspector.PlatformFlavor.MacSnowLeopard;
- case 7:
- return WebInspector.PlatformFlavor.MacLion;
- case 8:
- return WebInspector.PlatformFlavor.MacMountainLion;
- default:
- return "";
- }
- }
- }
- if (!WebInspector._platformFlavor)
- WebInspector._platformFlavor = detectFlavor();
- return WebInspector._platformFlavor;
- }
- WebInspector.port = function()
- {
- if (!WebInspector._port)
- WebInspector._port = InspectorFrontendHost.port();
- return WebInspector._port;
- }
- WebInspector.installPortStyles = function()
- {
- var platform = WebInspector.platform();
- document.body.addStyleClass("platform-" + platform);
- var flavor = WebInspector.platformFlavor();
- if (flavor)
- document.body.addStyleClass("platform-" + flavor);
- var port = WebInspector.port();
- document.body.addStyleClass("port-" + port);
- }
- WebInspector._windowFocused = function(event)
- {
- if (event.target.document.nodeType === Node.DOCUMENT_NODE)
- document.body.removeStyleClass("inactive");
- }
- WebInspector._windowBlurred = function(event)
- {
- if (event.target.document.nodeType === Node.DOCUMENT_NODE)
- document.body.addStyleClass("inactive");
- }
- WebInspector.previousFocusElement = function()
- {
- return WebInspector._previousFocusElement;
- }
- WebInspector.currentFocusElement = function()
- {
- return WebInspector._currentFocusElement;
- }
- WebInspector._focusChanged = function(event)
- {
- WebInspector.setCurrentFocusElement(event.target);
- }
- WebInspector._textInputTypes = ["text", "search", "tel", "url", "email", "password"].keySet();
- WebInspector._isTextEditingElement = function(element)
- {
- if (element instanceof HTMLInputElement)
- return element.type in WebInspector._textInputTypes;
- if (element instanceof HTMLTextAreaElement)
- return true;
- return false;
- }
- WebInspector.setCurrentFocusElement = function(x)
- {
- if (WebInspector._glassPane && x && !WebInspector._glassPane.element.isAncestor(x))
- return;
- if (WebInspector._currentFocusElement !== x)
- WebInspector._previousFocusElement = WebInspector._currentFocusElement;
- WebInspector._currentFocusElement = x;
- if (WebInspector._currentFocusElement) {
- WebInspector._currentFocusElement.focus();
- // Make a caret selection inside the new element if there isn't a range selection and there isn't already a caret selection inside.
- // This is needed (at least) to remove caret from console when focus is moved to some element in the panel.
- // The code below should not be applied to text fields and text areas, hence _isTextEditingElement check.
- var selection = window.getSelection();
- if (!WebInspector._isTextEditingElement(WebInspector._currentFocusElement) && selection.isCollapsed && !WebInspector._currentFocusElement.isInsertionCaretInside()) {
- var selectionRange = WebInspector._currentFocusElement.ownerDocument.createRange();
- selectionRange.setStart(WebInspector._currentFocusElement, 0);
- selectionRange.setEnd(WebInspector._currentFocusElement, 0);
- selection.removeAllRanges();
- selection.addRange(selectionRange);
- }
- } else if (WebInspector._previousFocusElement)
- WebInspector._previousFocusElement.blur();
- }
- WebInspector.restoreFocusFromElement = function(element)
- {
- if (element && element.isSelfOrAncestor(WebInspector.currentFocusElement()))
- WebInspector.setCurrentFocusElement(WebInspector.previousFocusElement());
- }
- WebInspector.setToolbarColors = function(backgroundColor, color)
- {
- if (!WebInspector._themeStyleElement) {
- WebInspector._themeStyleElement = document.createElement("style");
- document.head.appendChild(WebInspector._themeStyleElement);
- }
- WebInspector._themeStyleElement.textContent =
- "#toolbar {\
- background-image: none !important;\
- background-color: " + backgroundColor + " !important;\
- }\
- \
- .toolbar-label {\
- color: " + color + " !important;\
- text-shadow: none;\
- }";
- }
- WebInspector.resetToolbarColors = function()
- {
- if (WebInspector._themeStyleElement)
- WebInspector._themeStyleElement.textContent = "";
- }
- /**
- * @param {Element} element
- * @param {number} offset
- * @param {number} length
- * @param {Array.<Object>=} domChanges
- */
- WebInspector.highlightSearchResult = function(element, offset, length, domChanges)
- {
- var result = WebInspector.highlightSearchResults(element, [{offset: offset, length: length }], domChanges);
- return result.length ? result[0] : null;
- }
- /**
- * @param {Element} element
- * @param {Array.<Object>} resultRanges
- * @param {Array.<Object>=} changes
- */
- WebInspector.highlightSearchResults = function(element, resultRanges, changes)
- {
- return WebInspector.highlightRangesWithStyleClass(element, resultRanges, "highlighted-search-result", changes);
- }
- /**
- * @param {Element} element
- * @param {Array.<Object>} resultRanges
- * @param {string} styleClass
- * @param {Array.<Object>=} changes
- */
- WebInspector.highlightRangesWithStyleClass = function(element, resultRanges, styleClass, changes)
- {
- changes = changes || [];
- var highlightNodes = [];
- var lineText = element.textContent;
- var ownerDocument = element.ownerDocument;
- var textNodeSnapshot = ownerDocument.evaluate(".//text()", element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- var snapshotLength = textNodeSnapshot.snapshotLength;
- if (snapshotLength === 0)
- return highlightNodes;
- var nodeRanges = [];
- var rangeEndOffset = 0;
- for (var i = 0; i < snapshotLength; ++i) {
- var range = {};
- range.offset = rangeEndOffset;
- range.length = textNodeSnapshot.snapshotItem(i).textContent.length;
- rangeEndOffset = range.offset + range.length;
- nodeRanges.push(range);
- }
- var startIndex = 0;
- for (var i = 0; i < resultRanges.length; ++i) {
- var startOffset = resultRanges[i].offset;
- var endOffset = startOffset + resultRanges[i].length;
- while (startIndex < snapshotLength && nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= startOffset)
- startIndex++;
- var endIndex = startIndex;
- while (endIndex < snapshotLength && nodeRanges[endIndex].offset + nodeRanges[endIndex].length < endOffset)
- endIndex++;
- if (endIndex === snapshotLength)
- break;
- var highlightNode = ownerDocument.createElement("span");
- highlightNode.className = styleClass;
- highlightNode.textContent = lineText.substring(startOffset, endOffset);
- var lastTextNode = textNodeSnapshot.snapshotItem(endIndex);
- var lastText = lastTextNode.textContent;
- lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[endIndex].offset);
- changes.push({ node: lastTextNode, type: "changed", oldText: lastText, newText: lastTextNode.textContent });
- if (startIndex === endIndex) {
- lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode);
- changes.push({ node: highlightNode, type: "added", nextSibling: lastTextNode, parent: lastTextNode.parentElement });
- highlightNodes.push(highlightNode);
- var prefixNode = ownerDocument.createTextNode(lastText.substring(0, startOffset - nodeRanges[startIndex].offset));
- lastTextNode.parentElement.insertBefore(prefixNode, highlightNode);
- changes.push({ node: prefixNode, type: "added", nextSibling: highlightNode, parent: lastTextNode.parentElement });
- } else {
- var firstTextNode = textNodeSnapshot.snapshotItem(startIndex);
- var firstText = firstTextNode.textContent;
- var anchorElement = firstTextNode.nextSibling;
- firstTextNode.parentElement.insertBefore(highlightNode, anchorElement);
- changes.push({ node: highlightNode, type: "added", nextSibling: anchorElement, parent: firstTextNode.parentElement });
- highlightNodes.push(highlightNode);
- firstTextNode.textContent = firstText.substring(0, startOffset - nodeRanges[startIndex].offset);
- changes.push({ node: firstTextNode, type: "changed", oldText: firstText, newText: firstTextNode.textContent });
- for (var j = startIndex + 1; j < endIndex; j++) {
- var textNode = textNodeSnapshot.snapshotItem(j);
- var text = textNode.textContent;
- textNode.textContent = "";
- changes.push({ node: textNode, type: "changed", oldText: text, newText: textNode.textContent });
- }
- }
- startIndex = endIndex;
- nodeRanges[startIndex].offset = endOffset;
- nodeRanges[startIndex].length = lastTextNode.textContent.length;
- }
- return highlightNodes;
- }
- WebInspector.applyDomChanges = function(domChanges)
- {
- for (var i = 0, size = domChanges.length; i < size; ++i) {
- var entry = domChanges[i];
- switch (entry.type) {
- case "added":
- entry.parent.insertBefore(entry.node, entry.nextSibling);
- break;
- case "changed":
- entry.node.textContent = entry.newText;
- break;
- }
- }
- }
- WebInspector.revertDomChanges = function(domChanges)
- {
- for (var i = domChanges.length - 1; i >= 0; --i) {
- var entry = domChanges[i];
- switch (entry.type) {
- case "added":
- entry.node.remove();
- break;
- case "changed":
- entry.node.textContent = entry.oldText;
- break;
- }
- }
- }
- WebInspector._coalescingLevel = 0;
- WebInspector.startBatchUpdate = function()
- {
- if (!WebInspector._coalescingLevel)
- WebInspector._postUpdateHandlers = new Map();
- WebInspector._coalescingLevel++;
- }
- WebInspector.endBatchUpdate = function()
- {
- if (--WebInspector._coalescingLevel)
- return;
- var handlers = WebInspector._postUpdateHandlers;
- delete WebInspector._postUpdateHandlers;
- var keys = handlers.keys();
- for (var i = 0; i < keys.length; ++i) {
- var object = keys[i];
- var methods = handlers.get(object).keys();
- for (var j = 0; j < methods.length; ++j)
- methods[j].call(object);
- }
- }
- /**
- * @param {Object} object
- * @param {function()} method
- */
- WebInspector.invokeOnceAfterBatchUpdate = function(object, method)
- {
- if (!WebInspector._coalescingLevel) {
- method.call(object);
- return;
- }
-
- var methods = WebInspector._postUpdateHandlers.get(object);
- if (!methods) {
- methods = new Map();
- WebInspector._postUpdateHandlers.put(object, methods);
- }
- methods.put(method);
- }
- /**
- * This bogus view is needed to load/unload CodeMirror-related CSS on demand.
- *
- * @constructor
- * @extends {WebInspector.View}
- */
- WebInspector.CodeMirrorCSSLoadView = function()
- {
- WebInspector.View.call(this);
- this.element.addStyleClass("hidden");
- this.registerRequiredCSS("cm/codemirror.css");
- this.registerRequiredCSS("cm/cmdevtools.css");
- }
- WebInspector.CodeMirrorCSSLoadView.prototype = {
- __proto__: WebInspector.View.prototype
- }
- ;(function() {
- function windowLoaded()
- {
- window.addEventListener("focus", WebInspector._windowFocused, false);
- window.addEventListener("blur", WebInspector._windowBlurred, false);
- document.addEventListener("focus", WebInspector._focusChanged.bind(this), true);
- window.removeEventListener("DOMContentLoaded", windowLoaded, false);
- }
- window.addEventListener("DOMContentLoaded", windowLoaded, false);
- })();
|