Created
September 30, 2010 03:56
-
-
Save cellog/603994 to your computer and use it in GitHub Desktop.
[qx] demo of editable label
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ************************************************************************ | |
qooxdoo - the new era of web development | |
http://qooxdoo.org | |
Copyright: | |
2010, Gregory Beaver | |
License: | |
LGPL: http://www.gnu.org/licenses/lgpl.html | |
EPL: http://www.eclipse.org/org/documents/epl-v10.php | |
See the LICENSE file in the project's top-level directory for details. | |
Authors: | |
* Gregory Beaver | |
************************************************************************ */ | |
/* ************************************************************************ | |
************************************************************************ */ | |
/** | |
* An *editable label* is a label that when clicked becomes a form field | |
* that can then be edited. | |
* | |
* All form widgets that have a value property are supported. An editable | |
* label can be added to any form object and will transparently pass information | |
* from the form or its controller to its contained form element. Any form | |
* element that has a model property will also transparently be passed any | |
* external changes. | |
* | |
* A delegate can be defined that can be used to create the form element | |
* just-in-time or post-process the value for display as the label. | |
* | |
* <pre class='javascript> | |
* // simple | |
* var label = new qx.ui.form.EditableLabel(new qx.ui.form.TextField("hi")); | |
* | |
* // with delegate. | |
* // this example will instantiate a date chooser just-in-time | |
* // with the date Sep. 2, 1976 and set its height/width to 350 | |
* // and mark it required for the form renderer and validator | |
* var label = new qx.ui.form.EditableLabel(null, { | |
* placeholder: "This is displayed if value is null or empty string", | |
* converter: function(value) | |
* { | |
* var mo = value.getMonth() + 1; | |
* if (mo < 10) { | |
* mo = "0" + mo; | |
* } | |
* var da = value.getDate(); | |
* if (da < 10) { | |
* da = "0" + da; | |
* } | |
* return value.getFullYear()+"-"+mo+"-"+da; | |
* }, | |
* standardfield: { | |
* clazz: qx.ui.control.DateField, | |
* args: [new Date(1976, 9, 2)], | |
* init: { | |
* height: 350, | |
* width: 350 | |
* required: true | |
* } | |
* } | |
* }); | |
* </pre> | |
* | |
* For complex initializations, instead of using standardfield, pass | |
* in a function that can be used to lazy load the widget just-in-time | |
* | |
* <pre class='javascript'> | |
* var label = new qx.ui.form.EditableLabel(null, { | |
* lazyload : function() | |
* { | |
* var obj = new really.complex.Widget(); | |
* obj.doThis(); | |
* obj.doThat(); | |
* return obj; | |
* } | |
* }); | |
* </pre> | |
* | |
* To use the editable label with a form element that uses selections such | |
* as a selectbox or list, you must pass in 2 converter functions that will | |
* convert from the value to a selection, and from the selection to a value. If | |
* a controller is specified, the controller's selection will be used instead of | |
* the form element's selection | |
* | |
* <pre class='javascript'> | |
* var mycontroller = new qx.data.controller.List(qx.data.marshal.Json.createModel([ | |
* {name: "Thing 1", data: "Thing 1 data"}, | |
* {name: "Thing 2", data: "Thing 2 data"}, | |
* {name: "Thing 3", data: "Thing 3 data"}, | |
* ])); | |
* var label = new qx.ui.form.EditableLabel(null, { | |
* placeholder: "(Not entered)", | |
* converter : function (value) { | |
* if (!value) { | |
* return null; | |
* } | |
* return value.name; | |
* }, | |
* selectiontovalue : { | |
* controller : mycontroller, | |
* tovalue : function(sel) { | |
* if (!sel || !sel.getLength()) { | |
* return null; | |
* } | |
* return sel.getItem(0); | |
* }, | |
* toselection : function(value) { | |
* if (!value) { | |
* return new qx.data.Array(); | |
* } | |
* return new qx.data.Array([value]); | |
* } | |
* }, | |
* standardfield : { | |
* clazz : qx.ui.form.SelectBox | |
* } | |
* }); | |
* </pre> | |
* Note: the editable label will set the focusable property to true for any | |
* widget passed in | |
*/ | |
qx.Class.define("qx.ui.form.EditableLabel", { | |
extend: qx.ui.core.Widget, | |
implement : [ | |
qx.ui.form.IStringForm, | |
qx.ui.form.IForm | |
], | |
include: [ | |
qx.ui.form.MForm, | |
qx.ui.form.MModelProperty | |
], | |
properties : { | |
appearance : { | |
init : "editablelabel", | |
refine : true | |
}, | |
value : { | |
event : "changeValue", | |
init : null, | |
nullable : true, | |
apply : "_applyValue" | |
}, | |
formelement : { | |
check : "qx.ui.core.Widget", | |
event : "changeFormelement", | |
nullable: true | |
}, | |
label : { | |
check : "qx.ui.basic.Label", | |
event : "changeLabel" | |
} | |
}, | |
members : { | |
_selection : null, | |
_selectionListener : function(e) | |
{ | |
this.setValue(this._delegate.selectiontovalue.tovalue(e.getData())); | |
}, | |
_applyValue : function() | |
{ | |
var a, n = this.getValue(); | |
a = n; | |
if (this._delegate && this._delegate.converter) { | |
a = this._delegate.converter(n); | |
} | |
if (typeof a == 'number' || typeof a == 'boolean') { | |
a = String(a); | |
} | |
if (!a) { | |
a = '(Not set)'; | |
} else { | |
if (this._delegate && this._delegate.postprocess) { | |
a = this._delegate.postprocess(a); | |
} else { | |
a = String(a); | |
a = a.replace("&", "&").replace("<", "<").replace("<", ">"); | |
} | |
} | |
if (this.getLabel().getValue() == a) { | |
return; | |
} | |
this.getLabel().setValue(a); | |
if (!this.getFormelement()) { | |
return; | |
} | |
this._applyFormValue(); | |
}, | |
_applyFormValue : function() | |
{ | |
var n = this.getValue(); | |
if (this._delegate && this._delegate.selectiontovalue) { | |
var context = this._delegate.selectiontovalue.controller; | |
if (!context) { | |
context = this.getFormelement(); | |
} else { | |
context = context.getModel(); | |
} | |
n = this._delegate.selectiontovalue.toselection.call(context, n); | |
if (this._selection) { | |
var ok = true; | |
if (n instanceof Array) { | |
ok = qx.lang.Array.equals(n, this._selection); | |
} else { | |
ok = n.equals(this._selection); | |
} | |
if (ok) { | |
return; | |
} | |
} | |
if (this._delegate.selectiontovalue.controller) { | |
this._delegate.selectiontovalue.controller.setSelection(n); | |
this._delegate.selectiontovalue.controller.update(); | |
} else { | |
this.getFormelement().setSelection(n); | |
} | |
this._selection = n; | |
} else { | |
this.getFormelement().setValue(n); | |
} | |
}, | |
_delegate: null, | |
_labelwidth: 200, | |
_stack: null, | |
_handleClick : function () | |
{ | |
if (this._stack.getChildren().length == 1) { | |
if (this._delegate.standardfield) { | |
var el, args = []; | |
if (this._delegate.standardfield.args) { | |
args = this._delegate.standardfield.args; | |
} | |
switch (args.length) { | |
case 0 : | |
el = new this._delegate.standardfield.clazz(); | |
break; | |
case 1 : | |
el = new this._delegate.standardfield.clazz(args[0]); | |
break; | |
case 2 : | |
el = new this._delegate.standardfield.clazz(args[0], args[1], args[2]); | |
break; | |
case 3 : | |
el = new this._delegate.standardfield.clazz(args[0], args[1], args[2]); | |
break; | |
case 4 : | |
el = new this._delegate.standardfield.clazz(args[0], args[1], args[2], args[3]); | |
break; | |
case 5 : | |
el = new this._delegate.standardfield.clazz(args[0], args[1], args[2], args[3], args[4]); | |
break; | |
} | |
if (this._delegate.standardfield.init) { | |
el.set(this._delegate.standardfield.init); | |
} | |
this.setFormelement(el); | |
} else { | |
this.setFormelement(this._delegate.lazyload(this.getValue())); | |
} | |
this._setupElement(this.getFormelement()); | |
} | |
this._stack.setSelection([this.getFormelement()]); | |
this.getFormelement().focus(); | |
}, | |
_handleFocusout : function() | |
{ | |
this._stack.setSelection([this.getLabel()]); | |
}, | |
setLabelWidth : function(width) | |
{ | |
this.getLabel().setWidth(width); | |
}, | |
_setupElement: function(el) | |
{ | |
el.addListener("focusout", this._handleFocusout, this); | |
if (this._delegate && this._delegate.selectiontovalue) { | |
if (this._delegate.selectiontovalue.controller) { | |
this._delegate.selectiontovalue.controller.setTarget(el); | |
this._delegate.selectiontovalue.controller.addListener("changeSelection", | |
this._selectionListener, this); | |
this._applyFormValue(); | |
} else { | |
el.addListener("changeSelection", this._selectionListener, this); | |
el.setSelection(this._delegate.selectiontovalue.toselection(this.getValue())); | |
} | |
} else { | |
if (null !== el.getValue() && null === this.getValue()) { | |
// for spinners and other elements with default values | |
this.setValue(el.getValue()); | |
} else { | |
el.setValue(this.getValue()); | |
} | |
el.addListener("changeValue", this._receiveValue, this); | |
} | |
if (qx.Class.supportsEvent(el, "execute")) { | |
el.addListener("execute", this._handleFocusout, this); | |
} | |
el.setFocusable(true); | |
this._stack.add(el); | |
// handle model synchronization | |
if (el.setModel) { | |
this.addListener("changeModel", function(e) { | |
this.setModel(e.getData()); | |
}, el); | |
} | |
}, | |
_receiveValue: function(e) | |
{ | |
this.setValue(e.getData()); | |
}, | |
_onMouseOver : function(e) | |
{ | |
if (this._stack.getSelection()[0] == this.getFormelement()) { | |
return; | |
} | |
this.addState("hovered"); | |
}, | |
_onMouseOut : function(e) | |
{ | |
this.removeState("hovered"); | |
} | |
}, | |
construct : function(formelement, delegate) | |
{ | |
this.base(arguments); | |
this.addListener("mouseover", this._onMouseOver, this); | |
this.addListener("mouseout", this._onMouseOut, this); | |
if (delegate && qx.core.Variant.isSet("qx.debug", "on")) { | |
if (delegate.standardfield) { | |
if (!delegate.standardfield.clazz) { | |
throw new Error("editable label delegate standardfield must specify class" + | |
" to create with clazz variable"); | |
} | |
if (delegate.args && !(delegate.args instanceof Array)) { | |
delegate.args = [delegate.args]; | |
} | |
} | |
if (delegate.selectiontovalue) { | |
if (!delegate.selectiontovalue.toselection || | |
!(delegate.selectiontovalue.toselection instanceof Function)) { | |
throw new Error("editable label delegate selectiontovalue.toselection must " + | |
" be a function"); | |
} | |
if (!delegate.selectiontovalue.tovalue || | |
!(delegate.selectiontovalue.tovalue instanceof Function)) { | |
throw new Error("editable label delegate selectiontovalue.tovalue must " + | |
" be a function"); | |
} | |
} | |
if (delegate.lazyload && !(delegate.lazyload instanceof Function)) { | |
throw new Error("editable label delegate lazyload must be a function"); | |
} | |
} | |
if (formelement === undefined) { | |
formelement = null; | |
delegate = { | |
placeholder: "Click to edit", | |
standardfield: { | |
clazz: qx.ui.form.TextField | |
} | |
}; | |
} | |
this._setLayout(new qx.ui.layout.Grow()); | |
this._stack = new qx.ui.container.Stack(); | |
this._stack.setDynamic(true); | |
var placeholder = ""; | |
if (delegate && delegate.placeholder) { | |
placeholder = delegate.placeholder; | |
} | |
var label = new qx.ui.basic.Label(placeholder).set({ | |
rich: true, | |
wrap: true, | |
width: 200 | |
}); | |
this.setLabel(label); | |
this.setFormelement(formelement); | |
this._delegate = delegate; | |
label.addListener("click", this._handleClick, this); | |
this._stack.add(label); | |
if (!delegate || (!delegate.lazyload && !delegate.standardfield)) { | |
if (!formelement) { | |
formelement = new qx.ui.form.TextField(""); | |
} | |
this._setupElement(formelement); | |
} | |
this._add(this._stack); | |
} | |
}); | |
/* ************************************************************************ | |
Copyright: | |
License: | |
Authors: | |
#asset (qooxdoo/Oxygen/16/actions/edit-delete.png) | |
************************************************************************ */ | |
qx.Theme.define("demobrowser.demo.ui.Appearance", | |
{ | |
extend : qx.theme.modern.Appearance, | |
appearances : | |
{ | |
"editablelabel" : | |
{ | |
alias : "widget", | |
include : "widget", | |
style : function(states) | |
{ | |
if (states.hovered) { | |
return { | |
decorator : "editablelabel-hovered" | |
}; | |
} else { | |
return { | |
decorator : undefined | |
}; | |
} | |
} | |
} | |
} | |
}); | |
/* ************************************************************************ | |
Copyright: | |
License: | |
Authors: | |
************************************************************************ */ | |
qx.Theme.define("demobrowser.demo.ui.Decoration", | |
{ | |
extend : qx.theme.modern.Decoration, | |
decorations : | |
{ | |
"editablelabel-hovered" : | |
{ | |
decorator : qx.ui.decoration.Beveled, | |
style : { | |
backgroundColor : "table-row-background-odd", | |
outerColor : "border-focused" | |
} | |
} | |
} | |
});/* ************************************************************************ | |
qooxdoo - the new era of web development | |
http://qooxdoo.org | |
Copyright: | |
2004-2009 1&1 Internet AG, Germany, http://www.1und1.de | |
License: | |
LGPL: http://www.gnu.org/licenses/lgpl.html | |
EPL: http://www.eclipse.org/org/documents/epl-v10.php | |
See the LICENSE file in the project's top-level directory for details. | |
Authors: | |
* Martin Wittemann (martinwittemann) | |
************************************************************************ */ | |
/** | |
* @lint ignoreDeprecated(alert) | |
*/ | |
qx.Class.define("demobrowser.demo.ui.FormRenderer", | |
{ | |
extend : qx.application.Standalone, | |
members : | |
{ | |
main : function() | |
{ | |
this.base(arguments); | |
qx.theme.manager.Decoration.getInstance().setTheme(demobrowser.demo.ui.Decoration); | |
qx.theme.manager.Appearance.getInstance().setTheme(demobrowser.demo.ui.Appearance); | |
// create the form | |
var form = new qx.ui.form.Form(); | |
// add the first headline | |
form.addGroupHeader("Registration"); | |
// add usernamne | |
form.add(new qx.ui.form.EditableLabel(null, { | |
placeholder: "(Not yet entered)", | |
standardfield: { | |
clazz: qx.ui.form.TextField, | |
init : { | |
required: true | |
} | |
} | |
}), "Name"); | |
// add password | |
form.add(new qx.ui.form.EditableLabel(null, { | |
placeholder: "(Not yet entered)", | |
converter: function(value) { | |
return "****"; | |
}, | |
lazyload: function() { | |
return new qx.ui.form.PasswordField() | |
.set({"required": true}); | |
} | |
}), "Password"); | |
// add a save checkbox | |
form.add(new qx.ui.form.EditableLabel(null, { | |
placeholder: "No", | |
converter: function(value) { | |
if (value) { | |
return "Yes"; | |
} else { | |
return "No"; | |
} | |
}, | |
standardfield : { | |
clazz: qx.ui.form.CheckBox | |
} | |
}), "Save?"); | |
// add the second header | |
form.addGroupHeader("Personal Information"); | |
// add some additional widgets | |
form.add(new qx.ui.form.EditableLabel(null, { | |
standardfield : { | |
clazz: qx.ui.form.Spinner | |
} | |
}), "Age"); | |
form.add(new qx.ui.form.EditableLabel(), "Country"); | |
var genderBox = new qx.ui.form.SelectBox(); | |
genderBox.add(new qx.ui.form.ListItem("male")); | |
genderBox.add(new qx.ui.form.ListItem("female")); | |
var gendercontroller = new qx.data.controller.List(); | |
var gendermodel = qx.data.marshal.Json.createModel([ | |
{"name" : "male"}, | |
{"name" : "female"}, | |
{"name" : "other"} | |
], 1); | |
gendercontroller.setModel(gendermodel); | |
gendercontroller.setLabelPath("name"); | |
form.add(new qx.ui.form.EditableLabel(null, { | |
placeholder : "(Not yet selected)", | |
standardfield : { | |
clazz : qx.ui.form.SelectBox, | |
init : { | |
required: true, | |
allowGrowY: false | |
} | |
}, | |
selectiontovalue : { | |
controller: gendercontroller, | |
toselection : function(value) { | |
if (value == null) { | |
return null; | |
} | |
// model2target | |
for (var i = 0; i < this.getLength(); i++) { | |
if (this.getItem(i).getName() == value) { | |
return new qx.data.Array([this.getItem(i)]); | |
} | |
} | |
return new qx.data.Array([this.getItem(0)]); | |
}, | |
tovalue : function(sel) { | |
if (!sel) { | |
return null; | |
} | |
return sel.getItem(0).getName(); | |
} | |
} | |
}), "Gender"); | |
form.add(new qx.ui.form.EditableLabel(null, { | |
placeholder : "(Not yet entered)", | |
standardfield : { | |
clazz: qx.ui.form.TextArea | |
} | |
}), "Bio"); | |
// send button with validation | |
var sendButton = new qx.ui.form.Button("Send"); | |
sendButton.addListener("execute", function() { | |
if (form.validate()) { | |
alert("send..."); | |
} | |
}, this); | |
form.addButton(sendButton); | |
// reset button | |
var resetButton = new qx.ui.form.Button("Reset"); | |
resetButton.addListener("execute", function() { | |
form.reset(); | |
}, this); | |
form.addButton(resetButton); | |
// create the form and add it to the document | |
this.getRoot().add(new qx.ui.form.renderer.Single(form), {left: 10, top: 10}); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment