123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- 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 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 (ie, dijit.Editor)
- renderAsHtml : false,
- // editor: String
- // Class name for Editor widget
- editor : "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 mode
- value : "",
- // 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
- // 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) {
- 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) markup
- this.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 editor
- var 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 widget
- var _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 text
- this.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 changed
- this.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 blank
- this.displayNode.innerHTML = val || this.noValueIndicator;
- },
- cancel : function(/* Boolean */focus) {
- // summary:
- // Revert to display mode, discarding any changes made in the editor
- this.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 flag
- templateString : "<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 template
- var 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
- // ones
- var 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 mode
- ew.domNode.style.width = "100%"; // because display: block
- // doesn't work for table
- // widgets
- this.domNode.style.display = "block";
- } else {
- // inline-block mode
- ew.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 editor
- if (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 anything
- return;
- }
- 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 conditions
- return 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 value
- if (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-edit
- return;
- }
- 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 conditions
- return 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"]) { // IE
- if (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();
- };
- }
|