/* Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ if(!dojo._hasResource["dijit.InlineEditBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dijit.InlineEditBox"] = true; dojo.provide("dijit.InlineEditBox"); dojo.require("dojo.i18n"); dojo.require("dijit._Widget"); dojo.require("dijit._Container"); dojo.require("dijit.form.Button"); dojo.require("dijit.form.TextBox"); dojo.requireLocalization("dijit", "common", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); dojo.declare("dijit.InlineEditBox", dijit._Widget, { // summary: // An element with in-line edit capabilites // // description: // Behavior for an existing node (`

`, `

`, ``, etc.) so that // when you click it, an editor shows up in place of the original // text. Optionally, Save and Cancel button are displayed below the edit widget. // When Save is clicked, the text is pulled from the edit // widget and redisplayed and the edit widget is again hidden. // By default a plain Textarea widget is used as the editor (or for // inline values a TextBox), but you can specify an editor such as // dijit.Editor (for editing HTML) or a Slider (for adjusting a number). // An edit widget must support the following API to be used: // - displayedValue or value as initialization parameter, // and available through set('displayedValue') / set('value') // - void focus() // - DOM-node focusNode = node containing editable text // editing: [readonly] Boolean // Is the node currently in edit mode? editing: false, // autoSave: Boolean // Changing the value automatically saves it; don't have to push save button // (and save button isn't even displayed) autoSave: true, // buttonSave: String // Save button label buttonSave: "", // buttonCancel: String // Cancel button label buttonCancel: "", // renderAsHtml: Boolean // Set this to true if the specified Editor's value should be interpreted as HTML // rather than plain text (ex: `dijit.Editor`) renderAsHtml: false, // editor: String|Function // Class name (or reference to the Class) for Editor widget editor: "dijit.form.TextBox", // editorWrapper: String|Function // Class name (or reference to the Class) for widget that wraps the editor widget, displaying save/cancel // buttons. editorWrapper: "dijit._InlineEditor", // editorParams: Object // Set of parameters for editor, like {required: true} editorParams: {}, // disabled: Boolean // If true, clicking the InlineEditBox to edit it will have no effect. disabled: false, onChange: function(value){ // summary: // Set this handler to be notified of changes to value. // tags: // callback }, onCancel: function(){ // summary: // Set this handler to be notified when editing is cancelled. // tags: // callback }, // width: String // Width of editor. By default it's width=100% (ie, block mode). width: "100%", // value: String // The display value of the widget in read-only mode value: "", // noValueIndicator: [const] String // The text that gets displayed when there is no value (so that the user has a place to click to edit) noValueIndicator: dojo.isIE <= 6 ? // font-family needed on IE6 but it messes up IE8 "    ✍    " : "    ✍    ", constructor: function(){ // summary: // Sets up private arrays etc. // tags: // private this.editorParams = {}; }, postMixInProperties: function(){ this.inherited(arguments); // save pointer to original source node, since Widget nulls-out srcNodeRef this.displayNode = this.srcNodeRef; // connect handlers to the display node var events = { ondijitclick: "_onClick", onmouseover: "_onMouseOver", onmouseout: "_onMouseOut", onfocus: "_onMouseOver", onblur: "_onMouseOut" }; for(var name in events){ this.connect(this.displayNode, name, events[name]); } dijit.setWaiRole(this.displayNode, "button"); if(!this.displayNode.getAttribute("tabIndex")){ this.displayNode.setAttribute("tabIndex", 0); } if(!this.value && !("value" in this.params)){ // "" is a good value if specified directly so check params){ this.value = dojo.trim(this.renderAsHtml ? this.displayNode.innerHTML : (this.displayNode.innerText||this.displayNode.textContent||"")); } if(!this.value){ this.displayNode.innerHTML = this.noValueIndicator; } dojo.addClass(this.displayNode, 'dijitInlineEditBoxDisplayMode'); }, setDisabled: function(/*Boolean*/ disabled){ // summary: // Deprecated. Use set('disabled', ...) instead. // tags: // deprecated dojo.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0"); this.set('disabled', disabled); }, _setDisabledAttr: function(/*Boolean*/ disabled){ // summary: // Hook to make set("disabled", ...) work. // Set disabled state of widget. dijit.setWaiState(this.domNode, "disabled", disabled); if(disabled){ this.displayNode.removeAttribute("tabIndex"); }else{ this.displayNode.setAttribute("tabIndex", 0); } dojo.toggleClass(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled); this._set("disabled", disabled); }, _onMouseOver: function(){ // summary: // Handler for onmouseover and onfocus event. // tags: // private if(!this.disabled){ dojo.addClass(this.displayNode, "dijitInlineEditBoxDisplayModeHover"); } }, _onMouseOut: function(){ // summary: // Handler for onmouseout and onblur event. // tags: // private dojo.removeClass(this.displayNode, "dijitInlineEditBoxDisplayModeHover"); }, _onClick: function(/*Event*/ e){ // summary: // Handler for onclick event. // tags: // private if(this.disabled){ return; } if(e){ dojo.stopEvent(e); } this._onMouseOut(); // Since FF gets upset if you move a node while in an event handler for that node... setTimeout(dojo.hitch(this, "edit"), 0); }, edit: function(){ // summary: // Display the editor widget in place of the original (read only) markup. // tags: // private if(this.disabled || this.editing){ return; } this.editing = true; // save some display node values that can be restored later this._savedPosition = dojo.style(this.displayNode, "position") || "static"; this._savedOpacity = dojo.style(this.displayNode, "opacity") || "1"; this._savedTabIndex = dojo.attr(this.displayNode, "tabIndex") || "0"; if(this.wrapperWidget){ var ew = this.wrapperWidget.editWidget; ew.set("displayedValue" in ew ? "displayedValue" : "value", this.value); }else{ // Placeholder for edit widget // Put place holder (and eventually editWidget) before the display node so that it's positioned correctly // when Calendar dropdown appears, which happens automatically on focus. var placeholder = dojo.create("span", null, this.domNode, "before"); // Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons) var ewc = typeof this.editorWrapper == "string" ? dojo.getObject(this.editorWrapper) : this.editorWrapper; this.wrapperWidget = new ewc({ value: this.value, buttonSave: this.buttonSave, buttonCancel: this.buttonCancel, dir: this.dir, lang: this.lang, tabIndex: this._savedTabIndex, editor: this.editor, inlineEditBox: this, sourceStyle: dojo.getComputedStyle(this.displayNode), save: dojo.hitch(this, "save"), cancel: dojo.hitch(this, "cancel") }, placeholder); if(!this._started){ this.startup(); } } var ww = this.wrapperWidget; if(dojo.isIE){ dijit.focus(dijit.getFocus()); // IE (at least 8) needs help with tab order changes } // to avoid screen jitter, we first create the editor with position:absolute, visibility:hidden, // and then when it's finished rendering, we switch from display mode to editor // position:absolute releases screen space allocated to the display node // opacity:0 is the same as visibility:hidden but is still focusable // visiblity:hidden removes focus outline dojo.style(this.displayNode, { position: "absolute", opacity: "0", display: "none" }); // makes display node invisible, display style used for focus-ability dojo.style(ww.domNode, { position: this._savedPosition, visibility: "visible", opacity: "1" }); dojo.attr(this.displayNode, "tabIndex", "-1"); // needed by WebKit for TAB from editor to skip displayNode // Replace the display widget with edit widget, leaving them both displayed for a brief time so that // focus can be shifted without incident. (browser may needs some time to render the editor.) setTimeout(dojo.hitch(this, function(){ ww.focus(); // both nodes are showing, so we can switch focus safely ww._resetValue = ww.getValue(); }), 0); }, _onBlur: function(){ // summary: // Called when focus moves outside the InlineEditBox. // Performs garbage collection. // tags: // private this.inherited(arguments); if(!this.editing){ /* causes IE focus problems, see TooltipDialog_a11y.html... setTimeout(dojo.hitch(this, function(){ if(this.wrapperWidget){ this.wrapperWidget.destroy(); delete this.wrapperWidget; } }), 0); */ } }, destroy: function(){ if(this.wrapperWidget && !this.wrapperWidget._destroyed){ this.wrapperWidget.destroy(); delete this.wrapperWidget; } this.inherited(arguments); }, _showText: function(/*Boolean*/ focus){ // summary: // Revert to display mode, and optionally focus on display node // tags: // private var ww = this.wrapperWidget; dojo.style(ww.domNode, { position: "absolute", visibility: "hidden", opacity: "0" }); // hide the editor from mouse/keyboard events dojo.style(this.displayNode, { position: this._savedPosition, opacity: this._savedOpacity, display: "" }); // make the original text visible dojo.attr(this.displayNode, "tabIndex", this._savedTabIndex); if(focus){ dijit.focus(this.displayNode); } }, save: function(/*Boolean*/ focus){ // summary: // Save the contents of the editor and revert to display mode. // focus: Boolean // Focus on the display mode text // tags: // private if(this.disabled || !this.editing){ return; } this.editing = false; var ww = this.wrapperWidget; var value = ww.getValue(); this.set('value', value); // display changed, formatted value this._showText(focus); // set focus as needed }, setValue: function(/*String*/ val){ // summary: // Deprecated. Use set('value', ...) instead. // tags: // deprecated dojo.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.", "", "2.0"); return this.set("value", val); }, _setValueAttr: function(/*String*/ val){ // summary: // Hook to make set("value", ...) work. // Inserts specified HTML value into this node, or an "input needed" character if node is blank. val = dojo.trim(val); var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&").replace(//gm, ">").replace(/"/gm, """).replace(/\n/g, "
"); this.displayNode.innerHTML = renderVal || this.noValueIndicator; this._set("value", val); if(this._started){ // tell the world that we have changed setTimeout(dojo.hitch(this, "onChange", val), 0); // setTimeout prevents browser freeze for long-running event handlers } }, getValue: function(){ // summary: // Deprecated. Use get('value') instead. // tags: // deprecated dojo.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.", "", "2.0"); return this.get("value"); }, cancel: function(/*Boolean*/ focus){ // summary: // Revert to display mode, discarding any changes made in the editor // tags: // private if(this.disabled || !this.editing){ return; } this.editing = false; // tell the world that we have no changes setTimeout(dojo.hitch(this, "onCancel"), 0); // setTimeout prevents browser freeze for long-running event handlers this._showText(focus); } }); dojo.declare( "dijit._InlineEditor", [dijit._Widget, dijit._Templated], { // summary: // Internal widget used by InlineEditBox, displayed when in editing mode // to display the editor and maybe save/cancel buttons. Calling code should // connect to save/cancel methods to detect when editing is finished // // Has mainly the same parameters as InlineEditBox, plus these values: // // style: Object // Set of CSS attributes of display node, to replicate in editor // // value: String // Value as an HTML string or plain text string, depending on renderAsHTML flag templateString: dojo.cache("dijit", "templates/InlineEditBox.html", "