A multi-line widget can be fixed width. To enable fixed width, you need to set a width config option in JavaScript. To prevent a flash as the content is resized, you should set a matching width style in CSS on the containing element passed to the multi-line widget JavaScript constructor.
A multi-line widget can be fluid. When constructing the widget, do not pass in a width config option.
The widget will resize as the page is resized, too.
The EditableText
widget allows users to edit document text
in-place.
Don't forget to include the widget's CSS files!
<script type="text/javascript" src="../../build/yui/3.0.0pr2/build/yui/yui.js"></script> <script type="text/javascript" src="../../build/inlineedit/editor.js"></script> <script type="text/javascript" src="../../build/anim/anim.js"></script> <link type="text/css" rel="stylesheet" href="../../build/inlineedit/assets/skins/sam/editor.css"></link>
var LAZR_YUI_CONFIG = { filter: "min", base: "../../build/", modules: LAZR_MODULES, }; YUI(LAZR_YUI_CONFIG).use('lazr.editor', function(Y) { var editor = new Y.EditableText(...); });
The widget requires a well-structured block of elements. Various parts of the block will be discovered by the widget. Here's an example of some existing markup:
<div id="editable_text"> <span id="text">Some editable text</span> <button id="trigger">Edit</button> </div>
The editor requires three DOM elements to work correctly:
yui-editable_text-trigger
class.yui-editable_text-text
class.Here is some example JavaScript to hook up the above DOM structure:
var etext = new Y.EditableText({ contentBox: '#editable_text', text: '#text', trigger: '#trigger', }); etext.render();
Here is the resulting markup, after the editor has be rendered:
<!-- This is the final DOM structure for the editor --> <div class="yui-widget yui-editable_text"> <div id="editable_text" class="yui-editable_text"> <span id="text" class="yui-editable_text-text">Some editable text</span> <button id="trigger" class="yui-editable_text-trigger">Edit</button> <div class="yui-widget yui-ieditor yui-ieditor-hidden"/> <!-- The editor itself --> </div> </div>
The widget's DOM components, such as text
and
trigger
, can be discoverd by the editor if they have the
appropriate CSS classes attached to them. This is an alternative to
specifying the text and trigger elements in the editor's constructor.
The first child element of the contentBox marked with the
yui-editable_text-trigger
CSS class will be used as the editor
trigger.
The first child element of the contentBox marked with the
yui-editable_text-text
CSS class with become the editor's "text"
node.
The editor can be built upon using custom events, by overriding existing methods, or by injecting dependant objects.
Before extending the editor, you should understand that it is actually
two widgets, one wrapping the other. The inner widget, an instance of
Y.InlineEditor
, is responsible for handling user input. The
InlineEditor
object is wrapped by a Y.EditableText
object. EditableText
shows and hides the editor widget, and
handles updating the existing text with the user's new value.
The EditableText
widget publishes all of the same events as
the editor it wraps. The wrapped editor can be accessed using the
EditableText
instance's editor
property.
ieditor:save | Called after an input value has been successfully saved by the editor widget. |
ieditor:cancel | Called after the user hits the 'Cancel' button. |
These are the most useful methods to override on the
InlineEditor
class:
validate | Responsible for validating the user's input, and displaying a helpful error message if something's wrong. |
_saveData | Responsible for writing the verified and validated user data to the editor's "value" attribute. |
You can customize the editor by supplying the 'editor' argument to
the EditableText
constructor, passing in an
InlineEditor
instance:
var myeditor = new MyCustomEditor(); var etext = new Y.EditableText({ ... editor: myeditor });
This example plugin adds a 2-second delay to the editor's save function. It also makes use of the UI's "waiting" state.
// Add a delay between the start and end of the inline editor widget's // "save" event. var DelayedSavePlugin = function(config) { DelayedSavePlugin.superclass.constructor.apply(this, arguments); }; DelayedSavePlugin.NAME = 'delayedsave'; DelayedSavePlugin.NS = 'fx'; DelayedSavePlugin.ATTRS = { /* * Default duration of the 'saving' delay, in milliseconds. */ duration: { value: 2000 } }; Y.extend(DelayedSavePlugin, Y.Plugin, { initializer: function(config) { // Save a reference to the original _saveData() method before // we wrap it up. this.original_save = config.owner._saveData; // We want to run our delayed-save code before the original // 'save' method. Using doBefore() means that unplugging our // code will leave the original widget in a clean state. this.doBefore("_saveData", this._altSave); }, destructor: function() {}, /* * Our own _altSave() method, used to override the owner's default * behaviour. This method will only be called if the editor's input * is valid. */ _altSave: function() { var owner = this._owner, delay = this.get('duration'); Y.log("Running alternative _saveData()", 'info'); // Set the UI 'waiting' status. owner._uiSetWaiting(); // Introduce a configurable delay around the owner's _saveData() // method. Y.later(delay, this, function() { Y.log("Running original 'save' method.", 'info'); this.original_save.apply(owner, arguments[0]); // Make sure we clear the 'waiting' status. owner._uiClearWaiting(); }, arguments); // Make sure we prevent the default _devSave() method from // running. return new Y.Do.Halt(); } }); var editable_text = new Y.EditableText({ boundingBox: '#editable_text', contentBox: '#editable_text_content', text: '#text', trigger: '#edit_btn' }); editable_text.render(); // Add the 2 second delay to the underlying editor widget. editable_text.editor.plug({fn:DelayedSavePlugin});