Created
September 19, 2011 21:55
-
-
Save froop/1227730 to your computer and use it in GitHub Desktop.
[JavaScript] MultiSelectBox with QUnit test
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
/*global document, Option */ | |
var MSELECT = {}; | |
MSELECT.MultiSelectBox = function (parentElem) { | |
"use strict"; | |
if (!parentElem || !parentElem.appendChild) { | |
throw new Error("Invalid parameter of 'parentElem'"); | |
} | |
var tableElem = document.createElement("table"), | |
srcTitle = document.createElement("th"), | |
destTitle = document.createElement("th"), | |
srcSelectBox = document.createElement("select"), | |
destSelectBox = document.createElement("select"), | |
selectButton = document.createElement("input"), | |
removeButton = document.createElement("input"), | |
insertMode = false, | |
GUARD = "-"; | |
// Setup public methods. | |
this.setSrcList = function (options) { | |
if (!options || !(options instanceof Array)) { | |
throw new Error("Invalid parameter of 'options'"); | |
} | |
MSELECT.setSelectBoxOptions(srcSelectBox, options); | |
return this; | |
}; | |
this.getDestListValues = function () { | |
var result = [], idx, max = destSelectBox.options.length, option; | |
for (idx = 0; idx < max; idx += 1) { | |
option = destSelectBox.options[idx]; | |
if (option.value !== GUARD) { | |
result.push(option.value); | |
} | |
} | |
return result.join(","); | |
}; | |
this.addSelected = function () { | |
var findInOptions, findFirstSelected, mergeOptions, sortOptions, | |
newDestOptions; | |
findInOptions = function (options, value) { | |
var idx, max = options.length; | |
for (idx = 0; idx < max; idx += 1) { | |
if (options[idx].value === value) { | |
return idx; | |
} | |
} | |
return -1; | |
}; | |
findFirstSelected = function (options) { | |
var idx, max = options.length; | |
for (idx = 0; idx < max; idx += 1) { | |
if (options[idx].selected || options[idx].value === GUARD) { | |
break; | |
} | |
} | |
return idx; | |
}; | |
mergeOptions = function (options1, options2) { | |
var result, idx, delIdx; | |
result = options1.slice(0); // Array copy | |
for (idx = options2.length - 1; idx >= 0; idx -= 1) { | |
delIdx = findInOptions(result, options2[idx].value); | |
if (delIdx >= 0) { | |
result.splice(delIdx, 1); | |
} | |
result.splice(findFirstSelected(result), 0, options2[idx]); | |
} | |
return result; | |
}; | |
sortOptions = function (rule, target) { | |
var result = [], ruleIdx, max = rule.length, targetIdx; | |
for (ruleIdx = 0; ruleIdx < max; ruleIdx += 1) { | |
targetIdx = findInOptions(target, rule[ruleIdx].value); | |
if (targetIdx >= 0) { | |
result.push(target[targetIdx]); | |
} | |
} | |
return result; | |
}; | |
(function () { | |
var baseOptions = MSELECT.copySelectBoxOptions(destSelectBox, false), | |
addOptions = MSELECT.copySelectBoxOptions(srcSelectBox, true); | |
newDestOptions = mergeOptions(baseOptions, addOptions); | |
if (insertMode) { | |
MSELECT.clearSelected(addOptions); | |
} else { | |
MSELECT.clearSelected(baseOptions); | |
newDestOptions = sortOptions(srcSelectBox.options, newDestOptions); | |
} | |
MSELECT.setSelectBoxOptions(destSelectBox, newDestOptions); | |
MSELECT.clearSelected(srcSelectBox.options); | |
}()); | |
return this; | |
}; | |
this.removeSelected = function () { | |
var idx, item, options = destSelectBox.options; | |
for (idx = options.length - 1; idx >= 0; idx -= 1) { | |
item = options[idx]; | |
if (item.value === GUARD) { | |
options[idx].selected = false; | |
} else if (item.selected) { | |
options[idx] = null; | |
} | |
} | |
return this; | |
}; | |
this.selectItem = function (value) { | |
var options = srcSelectBox.options, optMax = options.length, optIdx; | |
for (optIdx = 0; optIdx < optMax; optIdx += 1) { | |
if (options[optIdx].value === value) { | |
options[optIdx].selected = true; | |
break; | |
} | |
} | |
}; | |
this.addSelectedAuto = function (valueStr) { | |
var values = valueStr.split(","), valMax = values.length, valIdx, | |
scrollToTop = function (selectBox) { | |
var options = srcSelectBox.options; | |
if (options.length > 0) { | |
options[0].selected = true; | |
options[0].selected = false; | |
} | |
}; | |
MSELECT.clearSelected(srcSelectBox.options); | |
for (valIdx = 0; valIdx < valMax; valIdx += 1) { | |
this.selectItem(values[valIdx]); | |
} | |
this.addSelected(); | |
MSELECT.clearSelected(srcSelectBox.options); | |
MSELECT.clearSelected(destSelectBox.options); | |
scrollToTop(srcSelectBox); | |
scrollToTop(destSelectBox); | |
return this; | |
}; | |
this.setSrcTitle = function (html) { | |
srcTitle.innerHTML = html; | |
return this; | |
}; | |
this.setDestTitle = function (html) { | |
destTitle.innerHTML = html; | |
return this; | |
}; | |
this.setSelectButtonText = function (text) { | |
selectButton.value = text; | |
return this; | |
}; | |
this.setRemoveButtonText = function (text) { | |
removeButton.value = text; | |
return this; | |
}; | |
this.setInsertMode = function () { | |
insertMode = true; | |
destSelectBox.options[0] = new Option("- - - - - - - - - -", GUARD); | |
return this; | |
}; | |
// for test. | |
this.getSrcSelectBox = function () { | |
return srcSelectBox; | |
}; | |
this.getDestSelectBox = function () { | |
return destSelectBox; | |
}; | |
// Setup DOM elements. | |
srcTitle.className = destTitle.className = "title"; | |
srcSelectBox.multiple = destSelectBox.multiple = "multiple"; | |
selectButton.type = removeButton.type = "button"; | |
MSELECT.addEventListener(selectButton, (function (that) { | |
return function () { | |
that.addSelected(); | |
}; | |
}(this))); | |
MSELECT.addEventListener(removeButton, (function (that) { | |
return function () { | |
that.removeSelected(); | |
}; | |
}(this))); | |
// Build DOM elements. | |
(function createTableHeader() { | |
var theadElem = document.createElement("thead"), | |
trElem = document.createElement("tr"); | |
trElem.appendChild(srcTitle); | |
trElem.appendChild(document.createElement("th")); | |
trElem.appendChild(destTitle); | |
theadElem.appendChild(trElem); | |
tableElem.appendChild(theadElem); | |
}()); | |
(function createTableBody() { | |
var tbodyElem = document.createElement("tbody"), | |
trElem = document.createElement("tr"), | |
srcBody = document.createElement("td"), | |
buttonsBody = document.createElement("td"), | |
destBody = document.createElement("td"); | |
srcBody.appendChild(srcSelectBox); | |
buttonsBody.appendChild(selectButton); | |
buttonsBody.appendChild(document.createElement("br")); | |
buttonsBody.appendChild(removeButton); | |
destBody.appendChild(destSelectBox); | |
trElem.appendChild(srcBody); | |
trElem.appendChild(buttonsBody); | |
trElem.appendChild(destBody); | |
tbodyElem.appendChild(trElem); | |
tableElem.appendChild(tbodyElem); | |
}()); | |
parentElem.appendChild(tableElem); | |
}; | |
// Utilities | |
MSELECT.setSelectBoxOptions = function (selectBox, options) { | |
"use strict"; | |
if (!options || !(options instanceof Array)) { | |
throw new Error("Invalid parameter of 'options'"); | |
} | |
var idx, max = options.length; | |
selectBox.options.length = 0; | |
for (idx = 0; idx < max; idx += 1) { | |
try { | |
selectBox.options[idx] = options[idx]; | |
} catch (e) { | |
throw new Error("Invalid parameter of 'options[" + idx + "]'"); | |
} | |
} | |
}; | |
MSELECT.copySelectBoxOptions = function (selectBox, selectedOnly) { | |
"use strict"; | |
var result = [], idx, max = selectBox.options.length, orgOpt, copyOpt; | |
for (idx = 0; idx < max; idx += 1) { | |
orgOpt = selectBox.options[idx]; | |
if (!selectedOnly || orgOpt.selected) { | |
copyOpt = new Option(orgOpt.text, orgOpt.value); | |
copyOpt.selected = orgOpt.selected; | |
result.push(copyOpt); | |
} | |
} | |
return result; | |
}; | |
MSELECT.clearSelected = function (options) { | |
"use strict"; | |
var idx, max = options.length; | |
for (idx = 0; idx < max; idx += 1) { | |
options[idx].selected = false; | |
} | |
}; | |
MSELECT.addEventListener = function (element, eventListner) { | |
"use strict"; | |
if (element.addEventListener) { // W3C | |
element.addEventListener("click", eventListner, false); | |
} else if (element.attachEvent) { // IE | |
element.attachEvent("onclick", eventListner); | |
} else { | |
element.onclick = eventListner; | |
} | |
}; |
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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j"> | |
<style type="text/css"> | |
select { | |
width: 120px; | |
height: 120px; | |
} | |
input[type="button"] { | |
width: 70px; | |
} | |
table { | |
border-spacing: 0; | |
} | |
table .title { | |
color: white; | |
background-color: blue; | |
} | |
</style> | |
<script type="text/javascript" src="MultiSelectBox.js"></script> | |
<script type="text/javascript"> | |
var msBox, msBoxInsert; | |
window.onload = function () { | |
var options = [ | |
new Option("0000000000", "00"), | |
new Option("0101010101", "01"), | |
new Option("0202020202", "02"), | |
new Option("0303030303", "03"), | |
new Option("0404040404", "04"), | |
new Option("0505050505", "05"), | |
new Option("0606060606", "06"), | |
new Option("0707070707", "07"), | |
new Option("0808080808", "08"), | |
new Option("0909090909", "09"), | |
new Option("12345678901234567890", "10") | |
], | |
optionsInsert = [ | |
new Option("0000000000", "00"), | |
new Option("1111111111", "01"), | |
new Option("2222222222", "02"), | |
new Option("3333333333", "03"), | |
new Option("4444444444", "04"), | |
new Option("5555555555", "05"), | |
new Option("6666666666", "06"), | |
new Option("7777777777", "07"), | |
new Option("8888888888", "08"), | |
new Option("9999999999", "09") | |
]; | |
msBox = new MSELECT.MultiSelectBox(document.getElementById("multi_select")) | |
.setSrcList(options).setSrcTitle("src").setDestTitle("dest") | |
.setSelectButtonText("select>>").setRemoveButtonText("<<remove") | |
.addSelectedAuto("00,01"); | |
msBoxInsert = new MSELECT.MultiSelectBox(document.getElementById("multi_select_insert")) | |
.setSrcList(optionsInsert).setSrcTitle("src (insert)").setDestTitle("dest (insert)") | |
.setSelectButtonText("select>>").setRemoveButtonText("<<remove").setInsertMode(); | |
} | |
</script> | |
</head> | |
<body> | |
<div> | |
<div id="multi_select"></div> | |
<input type="button" value="test" onclick="alert(msBox.getDestListValues())"/> | |
</div> | |
<br/> | |
<div> | |
<div id="multi_select_insert"></div> | |
<input type="button" value="test" onclick="alert(msBoxInsert.getDestListValues())"/> | |
</div> | |
</body> | |
</html> |
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
var target; | |
module("MultiSelectBox", { | |
setup: function () { | |
target = createDefaultTarget(); | |
}, | |
teardown: function () { | |
} | |
}); | |
test("setSrcList", function () { | |
equals(target.getSrcSelectBox().options.length, 4); | |
}); | |
test("setSrcListTwice", function () { | |
var options = [ new Option("text0b", "value0b") ]; | |
target.setSrcList(options); | |
equals(target.getSrcSelectBox().options.length, 1); | |
}); | |
test("setSrcListSelected", function () { | |
var option1 = new Option("text0", "value0"), | |
option2 = new Option("text1", "value1"), | |
options = []; | |
option1.selected = true; | |
options = [option1, option2]; | |
target.setSrcList(options); | |
ok(target.getSrcSelectBox().options[0].selected); | |
ok(!target.getSrcSelectBox().options[1].selected); | |
}); | |
test("getDestListValues", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value0,value2"); | |
}); | |
test("getDestListValuesEmpty", function () { | |
equals(target.getDestListValues(), ""); | |
}); | |
test("addSelectedFirst", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value0"); | |
ok(!target.getSrcSelectBox().options[0].selected); | |
}); | |
test("addSelectedLast", function () { | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value2"); | |
}); | |
test("addSelectedMiddle", function () { | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value1"); | |
}); | |
test("addSelectedMulti", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value0,value1,value2"); | |
}); | |
test("addSelectedNone", function () { | |
target.addSelected(); | |
equals(target.getDestListValues(), ""); | |
}); | |
test("addSelectedTwice", function () { | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
ok(target.getDestSelectBox().options[0].selected); | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
ok(target.getDestSelectBox().options[1].selected); | |
ok(!target.getDestSelectBox().options[0].selected); | |
equals(target.getDestListValues(), "value1,value2"); | |
}); | |
test("addSelectedDupli", function () { | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value1"); | |
ok(target.getDestSelectBox().options[0].selected); | |
}); | |
test("addSelectedMulti", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value0,value1"); | |
ok(target.getDestSelectBox().options[0].selected); | |
ok(target.getDestSelectBox().options[1].selected); | |
}); | |
test("addSelectedSort", function () { | |
var options = [ new Option("text2", "value2"), | |
new Option("text1", "value1"), | |
new Option("text0", "value0") ]; | |
target.setSrcList(options); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value2,value1,value0"); | |
}); | |
test("addSelectedInsertNoSelect", function () { | |
target.setInsertMode(); | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value1,value0"); | |
equals(target.getDestSelectBox().options[2].value, "-"); | |
}); | |
test("addSelectedInsert", function () { | |
target.setInsertMode(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[2].selected = true; | |
target.getDestSelectBox().options[0].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value2,value0,value1"); | |
}); | |
test("addSelectedInsertExist", function () { | |
target.setInsertMode(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[1].selected = true; | |
target.getDestSelectBox().options[0].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value1,value0"); | |
}); | |
test("addSelectedInsertExistMulti", function () { | |
target.setInsertMode(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
equals(target.getDestListValues(), "value0,value1"); | |
}); | |
test("removeSelectedFirst", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.addSelected(); | |
MSELECT.clearSelected(target.getDestSelectBox().options); | |
target.getDestSelectBox().options[0].selected = true; | |
equals("value0,value1", target.getDestListValues()); | |
target.removeSelected(); | |
equals(target.getDestListValues(), "value1"); | |
}); | |
test("removeSelectedLast", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
MSELECT.clearSelected(target.getDestSelectBox().options); | |
target.getDestSelectBox().options[2].selected = true; | |
equals("value0,value1,value2", target.getDestListValues()); | |
target.removeSelected(); | |
equals(target.getDestListValues(), "value0,value1"); | |
}); | |
test("removeSelectedMiddle", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
MSELECT.clearSelected(target.getDestSelectBox().options); | |
target.getDestSelectBox().options[1].selected = true; | |
target.removeSelected(); | |
equals(target.getDestListValues(), "value0,value2"); | |
}); | |
test("removeSelectedMulti", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.getSrcSelectBox().options[1].selected = true; | |
target.getSrcSelectBox().options[2].selected = true; | |
target.addSelected(); | |
MSELECT.clearSelected(target.getDestSelectBox().options); | |
target.getDestSelectBox().options[0].selected = true; | |
target.getDestSelectBox().options[1].selected = true; | |
target.removeSelected(); | |
equals(target.getDestListValues(), "value2"); | |
}); | |
test("removeSelectedAll", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
target.getDestSelectBox().options[0].selected = true; | |
target.removeSelected(); | |
equals(target.getDestListValues(), ""); | |
}); | |
test("removeSelectedNone", function () { | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
MSELECT.clearSelected(target.getDestSelectBox().options); | |
target.removeSelected(); | |
equals(target.getDestListValues(), "value0"); | |
}); | |
test("removeSelectedInsertMode", function () { | |
target.setInsertMode(); | |
target.getSrcSelectBox().options[0].selected = true; | |
target.addSelected(); | |
target.getDestSelectBox().options[0].selected = true; | |
target.getDestSelectBox().options[1].selected = true; | |
target.removeSelected(); | |
equals(target.getDestSelectBox().options[0].value, "-"); | |
}); | |
test("addSelectedAuto", function () { | |
target.getSrcSelectBox().options[3].selected = true; | |
target.addSelectedAuto("value1"); | |
target.addSelectedAuto("value0,value2"); | |
equals(target.getDestListValues(), "value0,value1,value2"); | |
ok(!target.getSrcSelectBox().options[0].selected); | |
ok(!target.getDestSelectBox().options[0].selected); | |
}); | |
test("addSelectedAutoInsertMode", function () { | |
target.setInsertMode(); | |
target.addSelectedAuto("value1"); | |
target.addSelectedAuto("value0,value2"); | |
equals(target.getDestListValues(), "value1,value0,value2"); | |
}); | |
test("addSelectedAutoEmpty", function () { | |
target.addSelectedAuto(""); | |
equals(target.getDestListValues(), ""); | |
}); | |
test("setInsertMode", function () { | |
target.setInsertMode(); | |
equals(target.getDestSelectBox().options[0].value, "-"); | |
}); | |
var createDefaultTarget = function () { | |
var parent = document.createElement("div"), | |
target = new MSELECT.MultiSelectBox(parent), | |
options = [ new Option("text0", "value0"), | |
new Option("text1", "value1"), | |
new Option("text2", "value2"), | |
new Option("text3", "value3") ]; | |
target.setSrcTitle("title1"); | |
target.setDestTitle("title2"); | |
target.setSelectButtonText("add"); | |
target.setRemoveButtonText("remove"); | |
target.setSrcList(options); | |
return target; | |
}; |
Insert mode に対応。これまでは並び順固定だったのが任意の順番ができるように
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
QUnitテストケースMultiSelectBoxTest.jsのequals関数の引数expectedとresultが逆なのに気づいて修正。
元々JsTestDriver用に作っていたのを転用したのだが、testとequalsの部分だけ置換で動くようになったので、
結果NG時の表示がおかしくなるだけで結果OK時には問題なかったので盲点だった。