forked from extern/egroupware
Add editableWidget to make HTML widget editable on double click
This commit is contained in:
parent
33759f0cd9
commit
8ea0be0abf
@ -426,7 +426,8 @@ var et2_readonlysArrayMgr = (function(){ "use strict"; return et2_arrayMgr.exten
|
||||
// If the attribute is set, return that
|
||||
if (typeof _attr != "undefined" && _attr !== null)
|
||||
{
|
||||
return et2_evalBool(_attr);
|
||||
// Accept 'editable', but otherwise boolean
|
||||
return this.expandName(_attr) === 'editable' ? 'editable' : et2_evalBool(_attr);
|
||||
}
|
||||
|
||||
// Otherwise take into accounf whether the parent is readonly
|
||||
|
158
api/js/etemplate/et2_core_editableWidget.js
Normal file
158
api/js/etemplate/et2_core_editableWidget.js
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* EGroupware eTemplate2 - JS Widget base class
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package etemplate
|
||||
* @subpackage api
|
||||
* @link http://www.egroupware.org
|
||||
* @author Andreas Stöckel
|
||||
* @copyright Stylite 2011
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/*egw:uses
|
||||
et2_core_inputWidget;
|
||||
*/
|
||||
|
||||
/**
|
||||
* et2_editableWidget derives from et2_inputWidget and adds the ability to start
|
||||
* readonly, then turn editable on double-click. If we decide to do this with
|
||||
* more widgets, it should just be merged with et2_inputWidget.
|
||||
*
|
||||
* @augments et2_inputWidget
|
||||
*/
|
||||
var et2_editableWidget = (function(){ "use strict"; return et2_inputWidget.extend(
|
||||
{
|
||||
attributes: {
|
||||
readonly: {
|
||||
name: "readonly",
|
||||
type: "string", // | boolean
|
||||
default: false,
|
||||
description: "If set to 'editable' will start readonly, double clicking will make it editable and clicking out will save"
|
||||
},
|
||||
save_callback: {
|
||||
name: "save_callback",
|
||||
type: "string",
|
||||
default: et2_no_init,
|
||||
description: "Ajax callback to save changed value when readonly is 'editable'. If not provided, a regular submit is done."
|
||||
},
|
||||
save_callback_params: {
|
||||
name: "readonly",
|
||||
type: "string",
|
||||
default: et2_no_init,
|
||||
description: "Additional parameters passed to save_callback"
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @memberOf et2_inputWidget
|
||||
*/
|
||||
init: function(_parent, _attrs) {
|
||||
// 'Editable' really should be boolean for everything else to work
|
||||
if(_attrs.readonly && typeof _attrs.readonly === 'string')
|
||||
{
|
||||
_attrs.readonly = true;
|
||||
this._toggle_readonly = true;
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
var node = this.getInputNode();
|
||||
if (node)
|
||||
{
|
||||
jQuery(node).off('.et2_editableWidget');
|
||||
}
|
||||
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the validation errors from the server
|
||||
*
|
||||
* @param {object} _attrs
|
||||
*/
|
||||
transformAttributes: function(_attrs) {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
},
|
||||
|
||||
attachToDOM: function() {
|
||||
this._super.apply(this,arguments);
|
||||
var node = this.getDOMNode();
|
||||
if (node && this._toggle_readonly)
|
||||
{
|
||||
jQuery(node)
|
||||
.off('.et2_editableWidget')
|
||||
.on("dblclick.et2_editableWidget", this, function(e) {
|
||||
e.data.dblclick.call(e.data, this);
|
||||
})
|
||||
.addClass('et2_clickable et2_editable');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
detatchFromDOM: function() {
|
||||
this._super.apply(this,arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle double click
|
||||
*
|
||||
* Turn widget editable
|
||||
*
|
||||
* @param {DOMNode} _node
|
||||
*/
|
||||
dblclick: function (_node) {
|
||||
// Turn off readonly
|
||||
this.set_readonly(false);
|
||||
|
||||
jQuery('body').on("click.et2_editableWidget", this, function(e) {
|
||||
// Make sure click comes from body, not a popup
|
||||
if(jQuery.contains(this, e.target))
|
||||
{
|
||||
jQuery(this).off("click.et2_editableWidget");
|
||||
e.data.focusout.call(e.data, this);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* User clicked somewhere else, save and turn back to readonly
|
||||
*
|
||||
* @param {DOMNode} _node Body node
|
||||
* @returns {et2_core_editableWidgetet2_editableWidget.et2_core_editableWidgetAnonym$0@call;getInstanceManager@call;submit}
|
||||
*/
|
||||
focusout: function (_node)
|
||||
{
|
||||
var value = this.get_value();
|
||||
var oldValue = this._oldValue;
|
||||
|
||||
// Change back to readonly
|
||||
this.set_readonly(true);
|
||||
|
||||
// No change, do nothing
|
||||
if(value == oldValue) return;
|
||||
|
||||
// Submit
|
||||
if(this.options.save_callback)
|
||||
{
|
||||
var params = [value];
|
||||
if(this.options.save_callback_params)
|
||||
{
|
||||
params = params.concat(this.options.save_callback_params.split(','));
|
||||
}
|
||||
|
||||
egw.json(this.options.save_callback, params, function() {
|
||||
}, this, true, this).sendRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.getInstanceManager().submit();
|
||||
}
|
||||
}
|
||||
|
||||
});}).call(this);
|
||||
|
@ -718,7 +718,7 @@ var et2_widget = (function(){ "use strict"; return ClassWithAttributes.extend(
|
||||
// constructor if it is available
|
||||
var constructor = typeof et2_registry[_nodeName] == "undefined" ?
|
||||
et2_placeholder : et2_registry[_nodeName];
|
||||
if (readonly && typeof et2_registry[_nodeName + "_ro"] != "undefined")
|
||||
if (readonly === true && typeof et2_registry[_nodeName + "_ro"] != "undefined")
|
||||
{
|
||||
constructor = et2_registry[_nodeName + "_ro"];
|
||||
}
|
||||
|
@ -13,13 +13,13 @@
|
||||
/*egw:uses
|
||||
jsapi.jsapi; // Needed for egw_seperateJavaScript
|
||||
/api/js/tinymce/tinymce.min.js;
|
||||
et2_core_baseWidget;
|
||||
et2_core_editableWidget;
|
||||
*/
|
||||
|
||||
/**
|
||||
* @augments et2_inputWidget
|
||||
*/
|
||||
var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2_IResizeable],
|
||||
var et2_htmlarea = (function(){ "use strict"; return et2_editableWidget.extend([et2_IResizeable],
|
||||
{
|
||||
attributes: {
|
||||
'mode': {
|
||||
@ -87,7 +87,7 @@ var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2
|
||||
this._super.apply(this, arguments);
|
||||
this.editor = null; // TinyMce editor instance
|
||||
this.supportedWidgetClasses = []; // Allow no child widgets
|
||||
this.htmlNode = jQuery(document.createElement("textarea"))
|
||||
this.htmlNode = jQuery(document.createElement(this.options.readonly ? "div" : "textarea"))
|
||||
.css('height', this.options.height)
|
||||
.addClass('et2_textbox_ro');
|
||||
this.setDOMNode(this.htmlNode[0]);
|
||||
@ -99,7 +99,12 @@ var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2
|
||||
*/
|
||||
doLoadingFinished: function() {
|
||||
this._super.apply(this, arguments);
|
||||
if(this.mode == 'ascii' || this.editor != null) return;
|
||||
|
||||
this.init_editor();
|
||||
},
|
||||
|
||||
init_editor: function() {
|
||||
if(this.mode == 'ascii' || this.editor != null || this.options.readonly) return;
|
||||
var imageUpload = '';
|
||||
var self = this;
|
||||
if (this.options.imageUpload && this.options.imageUpload[0] !== '/' && this.options.imageUpload.substr(0, 4) != 'http')
|
||||
@ -192,6 +197,34 @@ var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2
|
||||
}
|
||||
},
|
||||
|
||||
set_readonly: function(_value)
|
||||
{
|
||||
if(this.options.readonly === _value) return;
|
||||
var value = this.get_value();
|
||||
this.options.readonly = _value;
|
||||
if(this.options.readonly)
|
||||
{
|
||||
this.editor.remove();
|
||||
this.htmlNode = jQuery(document.createElement(this.options.readonly ? "div" : "textarea"))
|
||||
.css('height', this.options.height)
|
||||
.addClass('et2_textbox_ro');
|
||||
this.editor = null;
|
||||
this.setDOMNode(this.htmlNode[0]);
|
||||
this.set_value(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!this.editor)
|
||||
{
|
||||
this.htmlNode = jQuery(document.createElement("textarea"))
|
||||
.css('height', this.options.height)
|
||||
.val(value);
|
||||
this.setDOMNode(this.htmlNode[0]);
|
||||
this.init_editor();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function runs when the filepicker in image dialog is clicked
|
||||
*
|
||||
@ -315,13 +348,22 @@ var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2
|
||||
}
|
||||
else
|
||||
{
|
||||
this.htmlNode.val(_value);
|
||||
this.value = _value;
|
||||
if(this.options.readonly)
|
||||
{
|
||||
this.htmlNode.empty().append(_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.htmlNode.val(_value);
|
||||
}
|
||||
}
|
||||
this.value = _value;
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
return this.editor ? this.editor.getContent() : this.htmlNode.val();
|
||||
return this.editor ? this.editor.getContent() : (
|
||||
this.options.readonly ? this.value : this.htmlNode.val()
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user