Skip to content

Instantly share code, notes, and snippets.

@cellog
Created September 30, 2010 03:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cellog/603994 to your computer and use it in GitHub Desktop.
Save cellog/603994 to your computer and use it in GitHub Desktop.
[qx] demo of editable label
/* ************************************************************************
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("&", "&amp;").replace("<", "&lt;").replace("<", "&gt;");
}
}
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