/*!
* Copyright (c) 2009 Francesco Mele jsbeans@francescomele.com
*
* This Software is licenced under the LGPL Licence (GNU Lesser General
* Public License).
* In addition to the LGPL Licence the Software is subject to the
* following conditions:
*
* i every modification must be public and comunicated to the Author
* ii every "jsbean" added to this library must be self consistent
* except for the dependence from jsbeans-x.x.x.js
* iii copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* A javascript Object with both static and instance methods
* @namespace jsbeans
* @class Select
* @constructor
* @param [id] {String} if provided it stores the Select Object for future use.
* */
jsbeans.Select = function() {
this._id = arguments[0] || null;
};
/**
* Orders Select's Options by their text, not by value.<br/>
* It calls the static method
* @method order
* @param [caseSensitive] {boolean} optional, <code>false</code>
* */
jsbeans.Select.prototype.order = function() {
jsbeans.Select.order(this._id, arguments[0]);
};
/**
* Filters Options of a second Select based on value of the selected option pf the first.<br/>
* Second options are mapped using style class. See <a href="../jsbeans.Select.html">jsbeans.Select page</a> for details and running sample.
* @method setDependant
* @param childId {String}
* @param [parentId] {String}
* */
jsbeans.Select.prototype.setDependant = function(childId /*, parentId*/) {
var parentId = arguments[1] || this._id;
var parent = document.getElementById(parentId);
var child = document.getElementById(childId);
if (parent == null || child == null) {
return;
}
var div = document.createElement("div");
div.style.display = "none";
div.innerHTML = "<select style='display:none' id='" + parentId + childId + "'></select>";
document.body.appendChild(div);
var pc = document.getElementById(parentId + childId);
for (var i = 0; i < child.childNodes.length; i++) {
pc.appendChild(child.childNodes[i].cloneNode(true));
}
child.innerHTML = "";
var _dependant = function(all, dependant, val) {
for (var i = 0; i < all.options.length; i++) {
var className = all.options[i].className;
var classes = typeof(className) != "undefined" ? className.split(" ") : new Array();
for (var j = 0; j < classes.length; j++) {
if (classes[j] != "" && classes[j] == "sub_" + val) {
dependant.appendChild(all.options[i].cloneNode(true));
}
}
}
};
var parentVal = parent.value;
_dependant(pc, child, parentVal);
parent.onchange = function() {
child.innerHTML = "";
var parentVal = this.value;
_dependant(pc, child, parentVal);
};
parent = null;
};
/**
* @method _get
* @param object {String | DOM}
* @return {DOM}
* @private
* @static
* */
jsbeans.Select._get = function(v) {
var res = null;
if (typeof(v) == "string") {
res = document.getElementById(v);
}
else if (typeof(v) == "object") {
res = v;
}
if (res != null && res.nodeName && res.nodeName.toString().toLowerCase() == "select") {
return res;
}
return null;
};
/**
* Useful primarly in multiple selects, a way to delete Options.
* @method removeSelected
* @param object {String | DOM} the Select Object or its <code>id</code>
* @static
* */
jsbeans.Select.removeSelected = function(sel) {
sel = jsbeans.Select._get(sel);
if (sel == null) {
return;
}
var toBeRemoved = new Array();
for (var i = 0, opt; opt = sel.options[i]; i++) {
if (opt.selected) {
toBeRemoved.push(opt);
}
}
for (var i = 0, opt; opt = toBeRemoved[i]; i++) {
sel.removeChild(opt);
}
};
/**
* @method _remove
* @param node {DOM}
* @param arr {Array}
* @private
* @static
* */
jsbeans.Select._remove = function(o, a) {
for (var i = 0, opt; opt = a[i]; i++) {
o.removeChild(opt);
}
};
/**
* Copy selected Options from {@param} <code class="param">source</code> to {@param} <code class="param">destination</code> removing them from {@param} <code class="param">source</code>.
* @method move
* @param source {String | DOM} the Select Object (or its <code>id</code>)
* @param destination {String | DOM} the Select Object (or its <code>id</code>)
* @param [options] {JSON}
* <pre>
* order: boolean, // order both source and destination by text. Optional, default false.
* orderSource: boolean, // order only source by text.
* orderDestination: boolean, // order only destination by text.
* </pre>
* @static
* */
jsbeans.Select.move = function(from, to /*, options*/) {
from = jsbeans.Select._get(from);
to = jsbeans.Select._get(to);
if (from == null || to == null) {
return;
}
var options = arguments[2] || {order: true};
var toBeRemoved = new Array();
for (var i = 0, opt; opt = from.options[i]; i++) {
if (opt.selected) {
var found = false;
for (var j = 0, opt2; opt2 = to.options[j]; j++) {
if (opt2.text == opt.text) {
found = true;
break;
}
}
if (!found) {
to.appendChild(opt.cloneNode(true));
toBeRemoved.push(opt);
}
}
}
for (var i = 0, opt; opt = toBeRemoved[i]; i++) {
from.removeChild(opt);
}
if (options.order && options.order == true) {
jsbeans.Select.order(from);
jsbeans.Select.order(to);
}
else {
if (options.orderSource && options.orderSource == true) {
jsbeans.Select.order(from);
}
if (options.orderDestination && options.orderDestination == true) {
jsbeans.Select.order(to);
}
}
};
/**
* Copy all Options from {@param} <code class="param">source</code> to {@param} <code class="param">destination</code> removing them from {@param} <code class="param">source</code>.
* @method moveAll
* @param source {String | DOM} the Select Object (or its <code>id</code>)
* @param destination {String | DOM} the Select Object (or its <code>id</code>)
* @param [options] {JSON}
* <pre>
* order: boolean, // order destination by text. Optional, default false.
* orderDestination: boolean, // order only destination by text.
* </pre>
* @static
* */
jsbeans.Select.moveAll = function(from, to /*, options*/) {
from = jsbeans.Select._get(from);
to = jsbeans.Select._get(to);
if (from == null || to == null) {
return;
}
var options = arguments[2] || {order: true};
var toBeRemoved = new Array();
for (var i = 0, opt; opt = from.options[i]; i++) {
var found = false;
for (var j = 0, opt2; opt2 = to.options[j]; j++) {
if (opt2.text == opt.text) {
found = true;
break;
}
}
if (!found) {
to.appendChild(opt.cloneNode(true));
toBeRemoved.push(opt);
}
}
for (var i = 0, opt; opt = toBeRemoved[i]; i++) {
from.removeChild(opt);
}
if (options.order && options.order == true) {
jsbeans.Select.order(to);
}
else {
if (options.orderDestination && options.orderDestination == true) {
jsbeans.Select.order(to);
}
}
};
/**
* Copy selected Options from {@param} <code class="param">source</code> to {@param} <code class="param">destination</code>.
* @method copy
* @param source {String | DOM} the Select Object (or its <code>id</code>)
* @param destination {String | DOM} the Select Object (or its <code>id</code>)
* @param [options] {JSON}
* <pre>
* order: boolean, // order both destination by text. Optional, default false.
* orderDestination: boolean, // order only destination by text.
* </pre>
* @static
* */
jsbeans.Select.copy = function(from, to /*, options*/) {
from = jsbeans.Select._get(from);
to = jsbeans.Select._get(to);
if (from == null || to == null) {
return;
}
var options = arguments[2] || {order: true};
for (var i = 0, opt; opt = from.options[i]; i++) {
if (opt.selected) {
var found = false;
for (var j = 0, opt2; opt2 = to.options[j]; j++) {
if (opt2.text == opt.text) {
found = true;
break;
}
}
if (!found) {
to.appendChild(opt.cloneNode(true));
}
}
}
if (options.order && options.order == true) {
jsbeans.Select.order(to);
}
else {
if (options.orderDestination && options.orderDestination == true) {
jsbeans.Select.order(to);
}
}
};
/**
* Copy selected Options from {@param} <code class="param">source</code> to {@param} <code class="param">destination</code>.
* @method copyAll
* @param source {String | DOM} the Select Object (or its <code>id</code>)
* @param destination {String | DOM} the Select Object (or its <code>id</code>)
* @param [options] {JSON}
* <pre>
* order: boolean, // order destination by text. Optional, default false.
* orderDestination: boolean, // order only destination by text.
* </pre>
* @static
* */
jsbeans.Select.copyAll = function(from, to /*, options*/) {
from = jsbeans.Select._get(from);
to = jsbeans.Select._get(to);
if (from == null || to == null) {
return;
}
var options = arguments[2] || {order: true};
for (var i = 0, opt; opt = from.options[i]; i++) {
var found = false;
for (var j = 0, opt2; opt2 = to.options[j]; j++) {
if (opt2.text == opt.text) {
found = true;
break;
}
}
if (!found) {
to.appendChild(opt.cloneNode(true));
}
}
if (options.order && options.order == true) {
jsbeans.Select.order(to);
}
else {
if (options.orderDestination && options.orderDestination == true) {
jsbeans.Select.order(to);
}
}
};
/**
* Returns the lowest Options among {@param} <code class="param">select</code>'s Options by text using <code><</code> operator.
* @method min
* @param select {String | DOM} the Select Object (or its <code>id</code>)
* @return object {Option}
* @static
* */
jsbeans.Select.min = function(select) {
select = jsbeans.Select._get(select);
if (select == null || !select.options || select.options.length == 0) {
return null;
}
var res = select.options[0];
for (var i = 0, opt; opt = select.options[i]; i++) {
if (opt.text < res.text) {
res = opt;
}
}
return res;
};
/**
* Returns the highest Options among {@param} <code class="param">select</code>'s Options by text using <code>></code> operator.
* @method min
* @param select {String | DOM} the Select Object (or its <code>id</code>)
* @return object {Option}
* @static
* */
jsbeans.Select.max = function(select) {
select = jsbeans.Select._get(select);
if (select == null || !select.options || select.options.length == 0) {
return null;
}
var res = select.options[0];
for (var i = 0, opt; opt = select.options[i]; i++) {
if (opt.text > res.text) {
res = opt;
}
}
return res;
};
/**
* Shows only Options of {@param} <code class="param">select</code> whose text contains string {@param} <code class="param">value</code>.
* @method filter
* @param value {String}
* @param select {String | DOM} the Select Object (or its <code>id</code>)
* @static
* */
jsbeans.Select.filter = function(value, select) {
select = jsbeans.Select._get(select);
if (select == null || value == null) {
// TODO check if may return void
return null;
}
var sel = document.getElementById("jsbeans_Select_filter_" + select);
if (sel == null || typeof(sel) == "undefined") {
// clone the select and hide it
sel = document.createElement("select");
sel.setAttribute("id", "jsbeans_Select_filter_" + select);
sel.style.display = "none";
sel.style.position = "absolute";
sel.style.top = "-1000px";
sel.style.left = "-1000px";
for (var i = 0; i < select.options.length; i++) {
sel.appendChild(select.options[i].cloneNode(true));
}
document.body.appendChild(sel);
}
// empty the select
select.innerHTML = "";
var value = value.toLowerCase();
// now fill the select with matching options
for (var i = 0, opt; opt = sel.options[i]; i++) {
if (opt.text.toLowerCase().indexOf(value) != -1) {
select.appendChild(opt.cloneNode(true));
}
}
};
/**
* As {@method} <code class="methd">filter</code> creates hidden selects, developer can purge all created ones calling this.<br/>
* Please note that selects currently filtered may <strong>NOT</strong> be restored! Developer may need to clean filter's input before calling this;<br/>
* jQuery sample: <code>$("#filterInput").val("").keyup();<br/>jsbeans.Select.filterObjectCleaner();</code>
* @method filterObjectCleaner
* @static
* */
jsbeans.Select.filterObjectCleaner = function() {
var selects = document.getElementsByTagName("select");
for (var i = 0, sel; sel = selects[i]; i++) {
if (sel.id && sel.id.indexOf("jsbeans_Select_filter_") != -1) {
sel.parentNode.removeChild(sel);
}
}
};
/**
* Orders Options by text.
* @method order
* @param select {String | DOM}
* @param [caseSensitive] {boolean} default <code>false</code>
* @static
* */
jsbeans.Select.order = function(id /*, caseSensitive*/) {
var sel = jsbeans.Select._get(id);
if (sel == null) {
return;
}
var caseSensitive = arguments[1] || false;
var _o = new Array();
for (var i = 0, opt; opt = sel.options[i]; i++) {
if (caseSensitive) {
_o.push(opt.text);
}
else {
_o.push(opt.text.toLowerCase());
}
}
_o = _o.sort();
var res = new Array();
for (var i = 0; i < _o.length; i++) {
for (var j = 0, opt; opt = sel.options[j]; j++) {
if (caseSensitive) {
if (opt.text == _o[i]) {
res.push(opt);
break;
}
}
else {
if (opt.text.toLowerCase() == _o[i].toLowerCase()) {
res.push(opt);
break;
}
}
}
}
for (var i = 0, opt; opt = sel.options[i]; i++) {
opt = null;
}
for (var i = 0; i < res.length; i++) {
sel.appendChild(res[i]);
}
};