blob: ad956d3ff5f7729864e318ad64753edeb7da3062 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
dojo.provide("cocoon.forms.MultiValueEditor");
/**
* A free-entry multivalue field editor.
*
* Some functionality that's not visible at first sight:
* - items can be moved around using ctrl+up and ctrl+down.
* - an item can be replaced/updated by pressing ctrl+enter in the input box
*/
dojo.widget.defineWidget(
// widget name and class
"cocoon.forms.MultiValueEditor",
// superclass
dojo.widget.HtmlWidget,
function() {
},
// properties and methods
{
isContainer: false,
cformsIdPrefix: "id-prefix-not-set",
resourcesUri: cocoon.resourcesUri, // to make this available to the template
templatePath: cocoon.resourcesUri + "/forms/js/templates/MultiValueEditor.html",
fillInTemplate: function(args, frag) {
cocoon.forms.MultiValueEditor.superclass.fillInTemplate(this, args, frag);
dojo.event.connect(this.entry, "onkeypress", this, "_processInputKey");
dojo.event.connect(this.select, "onkeydown", this, "_processSelectKey");
dojo.event.connect(this.select, "onchange", this, "_processSelectChange");
dojo.event.connect(this.deleteButton, "onclick", this, "_deleteValues");
dojo.event.connect(this.moveUpButton, "onclick", this, "_moveUp");
dojo.event.connect(this.moveDownButton, "onclick", this, "_moveDown");
dojo.event.connect(this, "addedTo", this, "_addOnSubmitHandler");
this._readData(this.getFragNodeRef(frag));
},
/**
* Reads the data for the select-list from a table in the original widget-defining element.
*/
_readData: function(origFrag) {
var table = dojo.dom.getFirstChildElement(origFrag, "table");
if (table != null) {
var tbody = dojo.dom.firstElement(table, "tbody");
if (tbody != null) {
var tr = dojo.dom.firstElement(tbody, "tr");
while (tr != null) {
var td = dojo.dom.firstElement(tr, "td");
if (td != null) {
var text = dojo.dom.textContent(td);
this.select.options[this.select.options.length] = new Option(text, text);
}
tr = dojo.dom.nextElement(tr, "tr");
}
}
} else {
dojo.debug("MultiValueEditor: no data table found");
}
},
_addOnSubmitHandler: function(parent) {
var form = this._getForm(this);
if (form != null) {
var onSubmitHandler = {};
onSubmitHandler.forms_onsubmit = dojo.lang.hitch(this, "_selectAll");
cocoon.forms.addOnSubmitHandler(form, onSubmitHandler);
} else {
dojo.debug("MultiValueEditor is not being added to a form -- no onSubmitHandler then.");
}
},
/**
* Finds the HTML form to which a widget belongs.
* The widget is passed as an argument since this might become a generic
* utility function outside of this wiget.
*/
_getForm: function(widget) {
do {
if (widget.domNode != null && widget.domNode.tagName != null && widget.domNode.tagName.toLowerCase() == "form") {
return widget.domNode;
}
widget = widget.parent; // parent property points to the parent widget
} while (widget != null)
return null;
},
/**
* Key event handler for keypresses in the input box.
*/
_processInputKey: function(event) {
if (event.keyCode == 13 || event.keyCode == 10) {
dojo.event.browser.stopEvent(event);
var entry = this.entry;
var select = this.select;
var newItem = entry.value;
if (newItem == null || newItem == "")
return;
// if ctrl+enter is pressed, the first selected item is replaced with the new value
// (otherwise, the new value is appended at the end of the list)
var replace = event.ctrlKey;
var newItemPos = -1;
for (var i = 0; i < select.options.length; i++) {
if (select.options[i].selected && replace && newItemPos == -1)
newItemPos = i;
select.options[i].selected = false;
}
if (newItemPos == -1)
newItemPos = select.options.length;
select.options[newItemPos] = new Option(newItem, newItem, false, true);
entry.value = "";
}
},
/**
* Key event handler for keypresses in the select list.
*/
_processSelectKey: function(event) {
// 46 = delete key
if (event.keyCode == 46) {
dojo.event.browser.stopEvent(event);
this._deleteValues();
} else if (event.ctrlKey && event.keyCode == 38) {
dojo.event.browser.stopEvent(event);
// key up = 38
this._moveUp();
} else if (event.ctrlKey && event.keyCode == 40) {
dojo.event.browser.stopEvent(event);
// key down = 40
this._moveDown();
}
},
_deleteValues: function(event) {
if (event) dojo.event.browser.stopEvent(event);
var options = this.select.options;
var i = 0;
var lastRemovedItem = -1;
while (i < options.length) {
if (options[i].selected) {
options[i] = null;
lastRemovedItem = i;
} else {
i++;
}
}
if (lastRemovedItem != -1) {
if (options.length > lastRemovedItem) {
options[lastRemovedItem].selected = true;
} else if (lastRemovedItem - 1 >= 0) {
options[lastRemovedItem - 1].selected = true;
}
}
},
_processSelectChange: function(event) {
if (event) dojo.event.browser.stopEvent(event);
var options = this.select.options;
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
this.entry.value = options[i].value;
break;
}
}
},
_moveUp: function(event) {
if (event) dojo.event.browser.stopEvent(event);
var options = this.select.options;
if (options.length == 0)
return;
if (options[0].selected)
return;
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
var prev = this._cloneOption(options[i - 1]);
var current = this._cloneOption(options[i]);
options[i - 1] = current;
options[i] = prev;
}
}
},
_cloneOption: function(option) {
return new Option(option.text, option.value, false, option.selected);
},
_moveDown: function(event) {
if (event) dojo.event.browser.stopEvent(event);
var options = this.select.options;
if (options.length == 0)
return;
if (options[options.length - 1].selected)
return;
for (var i = options.length - 1; i >= 0; i--) {
if (options[i].selected) {
var next = this._cloneOption(options[i + 1]);
var current = this._cloneOption(options[i]);
options[i + 1] = current;
options[i] = next;
}
}
},
_selectAll: function() {
var options = this.select.options;
for (var i = 0; i < options.length; i++) {
options[i].selected = true;
}
}
}
);