1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 WebInspector.InplaceEditor = function()
13 * @param {!Element} element
14 * @param {!WebInspector.InplaceEditor.Config=} config
15 * @return {?{cancel: function(), commit: function(), setWidth: function(number)}}
17 WebInspector.InplaceEditor.startEditing = function(element, config)
20 return self.runtime.instance(WebInspector.InplaceEditor).startEditing(element, config);
22 if (!WebInspector.InplaceEditor._defaultInstance)
23 WebInspector.InplaceEditor._defaultInstance = new WebInspector.InplaceEditor();
24 return WebInspector.InplaceEditor._defaultInstance.startEditing(element, config);
27 WebInspector.InplaceEditor.prototype = {
31 editorContent: function(editingContext) {
32 var element = editingContext.element;
33 if (element.tagName === "INPUT" && element.type === "text")
36 return element.textContent;
39 setUpEditor: function(editingContext)
41 var element = editingContext.element;
42 element.classList.add("editing");
44 var oldTabIndex = element.getAttribute("tabIndex");
45 if (typeof oldTabIndex !== "number" || oldTabIndex < 0)
47 WebInspector.setCurrentFocusElement(element);
48 editingContext.oldTabIndex = oldTabIndex;
51 closeEditor: function(editingContext)
53 var element = editingContext.element;
54 element.classList.remove("editing");
56 if (typeof editingContext.oldTabIndex !== "number")
57 element.removeAttribute("tabIndex");
59 element.tabIndex = editingContext.oldTabIndex;
60 element.scrollTop = 0;
61 element.scrollLeft = 0;
64 cancelEditing: function(editingContext)
66 var element = editingContext.element;
67 if (element.tagName === "INPUT" && element.type === "text")
68 element.value = editingContext.oldText;
70 element.textContent = editingContext.oldText;
73 augmentEditingHandle: function(editingContext, handle)
78 * @param {!Element} element
79 * @param {!WebInspector.InplaceEditor.Config=} config
80 * @return {?{cancel: function(), commit: function()}}
82 startEditing: function(element, config)
84 if (!WebInspector.markBeingEdited(element, true))
87 config = config || new WebInspector.InplaceEditor.Config(function() {}, function() {});
88 var editingContext = { element: element, config: config };
89 var committedCallback = config.commitHandler;
90 var cancelledCallback = config.cancelHandler;
91 var pasteCallback = config.pasteHandler;
92 var context = config.context;
93 var isMultiline = config.multiline || false;
94 var moveDirection = "";
100 function consumeCopy(e)
105 this.setUpEditor(editingContext);
107 editingContext.oldText = isMultiline ? config.initialValue : this.editorContent(editingContext);
112 function blurEventListener(e) {
113 if (config.blurHandler && !config.blurHandler(element, e))
115 if (!isMultiline || !e || !e.relatedTarget || !e.relatedTarget.isSelfOrDescendant(element))
116 editingCommitted.call(element);
119 function cleanUpAfterEditing()
121 WebInspector.markBeingEdited(element, false);
123 element.removeEventListener("blur", blurEventListener, isMultiline);
124 element.removeEventListener("keydown", keyDownEventListener, true);
126 element.removeEventListener("paste", pasteEventListener, true);
128 WebInspector.restoreFocusFromElement(element);
129 self.closeEditor(editingContext);
132 /** @this {Element} */
133 function editingCancelled()
135 self.cancelEditing(editingContext);
136 cleanUpAfterEditing();
137 cancelledCallback(this, context);
140 /** @this {Element} */
141 function editingCommitted()
143 cleanUpAfterEditing();
145 committedCallback(this, self.editorContent(editingContext), editingContext.oldText, context, moveDirection);
148 function defaultFinishHandler(event)
150 var isMetaOrCtrl = WebInspector.isMac() ?
151 event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey :
152 event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;
153 if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !isMultiline || isMetaOrCtrl))
155 else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
157 else if (!isMultiline && event.keyIdentifier === "U+0009") // Tab key
158 return "move-" + (event.shiftKey ? "backward" : "forward");
161 function handleEditingResult(result, event)
163 if (result === "commit") {
164 editingCommitted.call(element);
166 } else if (result === "cancel") {
167 editingCancelled.call(element);
169 } else if (result && result.startsWith("move-")) {
170 moveDirection = result.substring(5);
171 if (event.keyIdentifier !== "U+0009")
176 function pasteEventListener(event)
178 var result = pasteCallback(event);
179 handleEditingResult(result, event);
182 function keyDownEventListener(event)
184 var handler = config.customFinishHandler || defaultFinishHandler;
185 var result = handler(event);
186 handleEditingResult(result, event);
189 element.addEventListener("blur", blurEventListener, isMultiline);
190 element.addEventListener("keydown", keyDownEventListener, true);
192 element.addEventListener("paste", pasteEventListener, true);
195 cancel: editingCancelled.bind(element),
196 commit: editingCommitted.bind(element)
198 this.augmentEditingHandle(editingContext, handle);
205 * @param {function(!Element,string,string,T,string)} commitHandler
206 * @param {function(!Element,T)} cancelHandler
207 * @param {T=} context
208 * @param {function(!Element,!Event):boolean=} blurHandler
211 WebInspector.InplaceEditor.Config = function(commitHandler, cancelHandler, context, blurHandler)
213 this.commitHandler = commitHandler;
214 this.cancelHandler = cancelHandler
215 this.context = context;
216 this.blurHandler = blurHandler;
219 * Handles the "paste" event, return values are the same as those for customFinishHandler
220 * @type {function(!Element)|undefined}
225 * Whether the edited element is multiline
226 * @type {boolean|undefined}
231 * Custom finish handler for the editing session (invoked on keydown)
232 * @type {function(!Element,*)|undefined}
234 this.customFinishHandler;
237 WebInspector.InplaceEditor.Config.prototype = {
238 setPasteHandler: function(pasteHandler)
240 this.pasteHandler = pasteHandler;
244 * @param {string} initialValue
245 * @param {!Object} mode
246 * @param {string} theme
247 * @param {boolean=} lineWrapping
248 * @param {boolean=} smartIndent
250 setMultilineOptions: function(initialValue, mode, theme, lineWrapping, smartIndent)
252 this.multiline = true;
253 this.initialValue = initialValue;
256 this.lineWrapping = lineWrapping;
257 this.smartIndent = smartIndent;
260 setCustomFinishHandler: function(customFinishHandler)
262 this.customFinishHandler = customFinishHandler;