Blame | Last modification | View Log | RSS feed
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, "ko,zh,ja,zh-tw,ru,it,hu,fr,pt,ROOT,pl,es,de,cs");dojo.declare("dijit.InlineEditBox",dijit._Widget,{// summary: An element with in-line edit capabilitites//// description:// Behavior for an existing node (<p>, <div>, <span>, 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:// String getDisplayedValue() OR String getValue()// void setDisplayedValue(String) OR void setValue(String)// void focus()//// editing: 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 labelbuttonSave: "",// buttonCancel: String// Cancel button labelbuttonCancel: "",// renderAsHtml: Boolean// Set this to true if the specified Editor's value should be interpreted as HTML// rather than plain text (ie, dijit.Editor)renderAsHtml: false,// editor: String// Class name for Editor widgeteditor: "dijit.form.TextBox",// editorParams: Object// Set of parameters for editor, like {required: true}editorParams: {},onChange: function(value){// summary: User should set this handler to be notified of changes to value},// 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 modevalue: "",// noValueIndicator: String// The text that gets displayed when there is no value (so that the user has a place to click to edit)noValueIndicator: "<span style='font-family: wingdings; text-decoration: underline;'> ✍ </span>",postMixInProperties: function(){this.inherited('postMixInProperties', arguments);// save pointer to original source node, since Widget nulls-out srcNodeRefthis.displayNode = this.srcNodeRef;// connect handlers to the display nodevar 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){this.value = this.displayNode.innerHTML;}this._setDisplayValue(this.value); // if blank, change to icon for "input needed"},_onMouseOver: function(){dojo.addClass(this.displayNode, this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion");},_onMouseOut: function(){dojo.removeClass(this.displayNode, this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion");},_onClick: function(/*Event*/ e){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) markupthis.editing = true;var editValue =(this.renderAsHtml ?this.value :this.value.replace(/\s*\r?\n\s*/g,"").replace(/<br\/?>/gi, "\n").replace(/>/g,">").replace(/</g,"<").replace(/&/g,"&"));// 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 = document.createElement("span");dojo.place(placeholder, this.domNode, "before");var ew = this.editWidget = new dijit._InlineEditor({value: dojo.trim(editValue),autoSave: this.autoSave,buttonSave: this.buttonSave,buttonCancel: this.buttonCancel,renderAsHtml: this.renderAsHtml,editor: this.editor,editorParams: this.editorParams,style: dojo.getComputedStyle(this.displayNode),save: dojo.hitch(this, "save"),cancel: dojo.hitch(this, "cancel"),width: this.width}, placeholder);// 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 editorvar ews = ew.domNode.style;this.displayNode.style.display="none";ews.position = "static";ews.visibility = "visible";// 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.)this.domNode = ew.domNode;setTimeout(function(){ew.focus();}, 100);},_showText: function(/*Boolean*/ focus){// summary: revert to display mode, and optionally focus on display node// display the read-only text and then quickly hide the editor (to avoid screen jitter)this.displayNode.style.display="";var ews = this.editWidget.domNode.style;ews.position="absolute";ews.visibility="hidden";this.domNode = this.displayNode;// give the browser some time to render the display node and then shift focus to it// and hide the edit widgetvar _this = this;setTimeout(function(){if(focus){dijit.focus(_this.displayNode);}_this.editWidget.destroy();delete _this.editWidget;}, 100);},save: function(/*Boolean*/ focus){// summary:// Save the contents of the editor and revert to display mode.// focus: Boolean// Focus on the display mode textthis.editing = false;this.value = this.editWidget.getValue() + "";if(this.renderAsHtml){this.value = this.value.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """).replace("\n", "<br>");}this._setDisplayValue(this.value);// tell the world that we have changedthis.onChange(this.value);this._showText(focus);},_setDisplayValue: function(/*String*/ val){// summary: inserts specified HTML value into this node, or an "input needed" character if node is blankthis.displayNode.innerHTML = val || this.noValueIndicator;},cancel: function(/*Boolean*/ focus){// summary:// Revert to display mode, discarding any changes made in the editorthis.editing = false;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 flagtemplateString:"<fieldset dojoAttachPoint=\"editNode\" waiRole=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdojoAttachEvent=\"onkeypress: _onKeyPress\" \n\t><input dojoAttachPoint=\"editorPlaceholder\"\n\t/><span dojoAttachPoint=\"buttonContainer\"\n\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\">${buttonSave}</button\n\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\">${buttonCancel}</button\n\t></span\n></fieldset>\n",widgetsInTemplate: true,postMixInProperties: function(){this.inherited('postMixInProperties', arguments);this.messages = dojo.i18n.getLocalization("dijit", "common", this.lang);dojo.forEach(["buttonSave", "buttonCancel"], function(prop){if(!this[prop]){ this[prop] = this.messages[prop]; }}, this);},postCreate: function(){// Create edit widget in place in the templatevar cls = dojo.getObject(this.editor);var ew = this.editWidget = new cls(this.editorParams, this.editorPlaceholder);// Copy the style from the source// Don't copy ALL properties though, just the necessary/applicable onesvar srcStyle = this.style;dojo.forEach(["fontWeight","fontFamily","fontSize","fontStyle"], function(prop){ew.focusNode.style[prop]=srcStyle[prop];}, this);dojo.forEach(["marginTop","marginBottom","marginLeft", "marginRight"], function(prop){this.domNode.style[prop]=srcStyle[prop];}, this);if(this.width=="100%"){// block modeew.domNode.style.width = "100%"; // because display: block doesn't work for table widgetsthis.domNode.style.display="block";}else{// inline-block modeew.domNode.style.width = this.width + (Number(this.width)==this.width ? "px" : "");}this.connect(this.editWidget, "onChange", "_onChange");// setting the value of the edit widget will cause a possibly asynchronous onChange() call.// we need to ignore it, since we are only interested in when the user changes the value.this._ignoreNextOnChange = true;(this.editWidget.setDisplayedValue||this.editWidget.setValue).call(this.editWidget, this.value);this._initialText = this.getValue();if(this.autoSave){this.buttonContainer.style.display="none";}},destroy: function(){this.editWidget.destroy();this.inherited(arguments);},getValue: function(){var ew = this.editWidget;return ew.getDisplayedValue ? ew.getDisplayedValue() : ew.getValue();},_onKeyPress: function(e){// summary: Callback when keypress in the edit box (see template).// description:// For autoSave widgets, if Esc/Enter, call cancel/save.// For non-autoSave widgets, enable save button if the text value is// different than the original value.if(this._exitInProgress){return;}if(this.autoSave){// If Enter/Esc pressed, treat as save/cancel.if(e.keyCode == dojo.keys.ESCAPE){dojo.stopEvent(e);this._exitInProgress = true;this.cancel(true);}else if(e.keyCode == dojo.keys.ENTER){dojo.stopEvent(e);this._exitInProgress = true;this.save(true);}}else{var _this = this;// Delay before calling getValue().// The delay gives the browser a chance to update the Textarea.setTimeout(function(){_this.saveButton.setDisabled(_this.getValue() == _this._initialText);}, 100);}},_onBlur: function(){// summary:// Called when focus moves outside the editorif(this._exitInProgress){// when user clicks the "save" button, focus is shifted back to display text, causing this// function to be called, but in that case don't do anythingreturn;}if(this.autoSave){this._exitInProgress = true;if(this.getValue() == this._initialText){this.cancel(false);}else{this.save(false);}}},enableSave: function(){// summary: User replacable function returning a Boolean to indicate// if the Save button should be enabled or not - usually due to invalid conditionsreturn this.editWidget.isValid ? this.editWidget.isValid() : true; // Boolean},_onChange: function(){// summary:// Called when the underlying widget fires an onChange event,// which means that the user has finished entering the valueif(this._ignoreNextOnChange){delete this._ignoreNextOnChange;return;}if(this._exitInProgress){// TODO: the onChange event might happen after the return key for an async widget// like FilteringSelect. Shouldn't be deleting the edit widget on end-of-editreturn;}if(this.autoSave){this._exitInProgress = true;this.save(true);}else{// in case the keypress event didn't get through (old problem with Textarea that has been fixed// in theory) or if the keypress event comes too quickly and the value inside the Textarea hasn't// been updated yet)this.saveButton.setDisabled((this.getValue() == this._initialText) || !this.enableSave());}},enableSave: function(){// summary: User replacable function returning a Boolean to indicate// if the Save button should be enabled or not - usually due to invalid conditionsreturn this.editWidget.isValid ? this.editWidget.isValid() : true;},focus: function(){this.editWidget.focus();dijit.selectInputText(this.editWidget.focusNode);}});dijit.selectInputText = function(/*DomNode*/element){// summary: select all the text in an input element// TODO: use functions in _editor/selection.js?var _window = dojo.global;var _document = dojo.doc;element = dojo.byId(element);if(_document["selection"] && dojo.body()["createTextRange"]){ // IEif(element.createTextRange){var range = element.createTextRange();range.moveStart("character", 0);range.moveEnd("character", element.value.length);range.select();}}else if(_window["getSelection"]){var selection = _window.getSelection();// FIXME: does this work on Safari?if(element.setSelectionRange){element.setSelectionRange(0, element.value.length);}}element.focus();};}