(function() {
var lang = YAHOO.lang, Event = YAHOO.util.Event, Dom = YAHOO.util.Dom, CSS_PREFIX = 'inputEx-InPlaceEdit-';
/**
* Meta field providing in place editing (the editor appears when you click on the formatted value).
* @class inputEx.InPlaceEdit
* @extends inputEx.Field
* @constructor
* @param {Object} options Added options:
* <ul>
* <li>visu</li>
* <li>editorField</li>
* <li>animColors</li>
* </ul>
*/
inputEx.InPlaceEdit = function(options) {
inputEx.InPlaceEdit.superclass.constructor.call(this, options);
};
lang.extend(inputEx.InPlaceEdit, inputEx.Field, {
/**
* Set the default values of the options
* @param {Object} options Options object as passed to the constructor
*/
setOptions: function(options) {
inputEx.InPlaceEdit.superclass.setOptions.call(this, options);
this.options.visu = options.visu;
this.options.editorField = options.editorField;
this.options.buttonTypes = options.buttonTypes || {ok:"submit",cancel:"link"};
this.options.animColors = options.animColors || null;
},
/**
* Override renderComponent to create 2 divs: the visualization one, and the edit in place form
*/
renderComponent: function() {
this.renderVisuDiv();
this.renderEditor();
},
/**
* Render the editor
*/
renderEditor: function() {
this.editorContainer = inputEx.cn('div', {className: CSS_PREFIX+'editor'}, {display: 'none'});
// Render the editor field
this.editorField = inputEx(this.options.editorField,this);
var editorFieldEl = this.editorField.getEl();
this.editorContainer.appendChild( editorFieldEl );
Dom.addClass( editorFieldEl , CSS_PREFIX+'editorDiv');
this.okButton = new inputEx.widget.Button({
type: this.options.buttonTypes.ok,
parentEl: this.editorContainer,
value: inputEx.messages.okEditor,
className: "inputEx-Button "+CSS_PREFIX+'OkButton',
onClick: {fn: this.onOkEditor, scope:this}
});
this.cancelLink = new inputEx.widget.Button({
type: this.options.buttonTypes.cancel,
parentEl: this.editorContainer,
value: inputEx.messages.cancelEditor,
className: "inputEx-Button "+CSS_PREFIX+'CancelLink',
onClick: {fn: this.onCancelEditor, scope:this}
});
// Line breaker ()
this.editorContainer.appendChild( inputEx.cn('div',null, {clear: 'both'}) );
this.fieldContainer.appendChild(this.editorContainer);
},
/**
* Set the color when hovering the field
* @param {Event} e The original mouseover event
*/
onVisuMouseOver: function(e) {
if(this.colorAnim) {
this.colorAnim.stop(true);
}
inputEx.sn(this.formattedContainer, null, {backgroundColor: this.options.animColors.from });
},
/**
* Start the color animation when hovering the field
* @param {Event} e The original mouseout event
*/
onVisuMouseOut: function(e) {
// Start animation
if(this.colorAnim) {
this.colorAnim.stop(true);
}
this.colorAnim = new YAHOO.util.ColorAnim(this.formattedContainer, {backgroundColor: this.options.animColors}, 1);
this.colorAnim.onComplete.subscribe(function() { Dom.setStyle(this.formattedContainer, 'background-color', ''); }, this, true);
this.colorAnim.animate();
},
/**
* Create the div that will contain the visualization of the value
*/
renderVisuDiv: function() {
this.formattedContainer = inputEx.cn('div', {className: 'inputEx-InPlaceEdit-visu'});
if( lang.isFunction(this.options.formatDom) ) {
this.formattedContainer.appendChild( this.options.formatDom(this.options.value) );
}
else if( lang.isFunction(this.options.formatValue) ) {
this.formattedContainer.innerHTML = this.options.formatValue(this.options.value);
}
else {
this.formattedContainer.innerHTML = lang.isUndefined(this.options.value) ? inputEx.messages.emptyInPlaceEdit: this.options.value;
}
this.fieldContainer.appendChild(this.formattedContainer);
},
/**
* Adds the events for the editor and color animations
*/
initEvents: function() {
Event.addListener(this.formattedContainer, "click", this.openEditor, this, true);
// For color animation (if specified)
if (this.options.animColors) {
Event.addListener(this.formattedContainer, 'mouseover', this.onVisuMouseOver, this, true);
Event.addListener(this.formattedContainer, 'mouseout', this.onVisuMouseOut, this, true);
}
if(this.editorField.el) {
// Register some listeners
Event.addListener(this.editorField.el, "keyup", this.onKeyUp, this, true);
Event.addListener(this.editorField.el, "keydown", this.onKeyDown, this, true);
}
},
/**
* Handle some keys events to close the editor
* @param {Event} e The original keyup event
*/
onKeyUp: function(e) {
// Enter
if( e.keyCode == 13) {
this.onOkEditor(e);
}
// Escape
if( e.keyCode == 27) {
this.onCancelEditor(e);
}
},
/**
* Handle the tabulation key to close the editor
* @param {Event} e The original keydown event
*/
onKeyDown: function(e) {
// Tab
if(e.keyCode == 9) {
this.onOkEditor(e);
}
},
/**
* Validate the editor (ok button, enter key or tabulation key)
*/
onOkEditor: function(e) {
Event.stopEvent(e);
var newValue = this.editorField.getValue();
this.setValue(newValue);
this.editorContainer.style.display = 'none';
this.formattedContainer.style.display = '';
var that = this;
setTimeout(function() {that.updatedEvt.fire(newValue);}, 50);
},
/**
* Close the editor on cancel (cancel button, blur event or escape key)
* @param {Event} e The original event (click, blur or keydown)
*/
onCancelEditor: function(e) {
Event.stopEvent(e);
this.editorContainer.style.display = 'none';
this.formattedContainer.style.display = '';
},
/**
* Display the editor
*/
openEditor: function() {
var value = this.getValue();
this.editorContainer.style.display = '';
this.formattedContainer.style.display = 'none';
if(!lang.isUndefined(value)) {
this.editorField.setValue(value);
}
// Set focus in the element !
this.editorField.focus();
// Select the content
if(this.editorField.el && lang.isFunction(this.editorField.el.setSelectionRange) && (!!value && !!value.length)) {
this.editorField.el.setSelectionRange(0,value.length);
}
},
/**
* Returned the previously stored value
* @return {Any} The value of the subfield
*/
getValue: function() {
var editorOpened = (this.editorContainer.style.display == '');
return editorOpened ? this.editorField.getValue() : this.value;
},
/**
* Set the value and update the display
* @param {Any} value The value to set
* @param {boolean} [sendUpdatedEvt] (optional) Wether this setValue should fire the updatedEvt or not (default is true, pass false to NOT send the event)
*/
setValue: function(value, sendUpdatedEvt) {
// Store the value
this.value = value;
if(lang.isUndefined(value) || value == "") {
inputEx.renderVisu(this.options.visu, inputEx.messages.emptyInPlaceEdit, this.formattedContainer);
}
else {
inputEx.renderVisu(this.options.visu, this.value, this.formattedContainer);
}
// If the editor is opened, update it
if(this.editorContainer.style.display == '') {
this.editorField.setValue(value);
}
inputEx.InPlaceEdit.superclass.setValue.call(this, value, sendUpdatedEvt);
},
/**
* Close the editor when calling the close function on this field
*/
close: function() {
this.editorContainer.style.display = 'none';
this.formattedContainer.style.display = '';
}
});
inputEx.messages.emptyInPlaceEdit = "(click to edit)";
inputEx.messages.cancelEditor = "cancel";
inputEx.messages.okEditor = "Ok";
// Register this class as "inplaceedit" type
inputEx.registerType("inplaceedit", inputEx.InPlaceEdit, [
{ type:'type', label: 'Editor', name: 'editorField'}
]);
})();