// Generated by CoffeeScript 2.0.0-beta4 (function() { // ------------------------------------------------------------------------ // 變數與常數設置 // ------------------------------------------------------------------------ // 模組名稱。 var Attribute, ClassName, EVENT_NAMESPACE, Error, Event, MODULE_NAMESPACE, NAME, Selector, Settings, TARGET; NAME = 'transfer'; // 模組事件鍵名。 EVENT_NAMESPACE = `.${NAME}`; // 模組命名空間。 MODULE_NAMESPACE = `module-${NAME}`; // 模組設定。 Settings = { // 消音所有提示,甚至是錯誤訊息。 silent: false, // 顯示除錯訊息。 debug: true, // 監聽 DOM 結構異動並自動重整快取。 observeChanges: true, // 當值移動時所會呼叫的回呼函式。 onMove: (values, to) => {}, // 當值有所移動、新增或移除時所會呼叫的函式。 onChange: (value) => {}, // 當值被選取時所會呼叫的函式。 onSelect: (value) => {}, // 當值被取消選取時所會呼叫的函式。 onUnselect: (value) => {}, // 搜尋時所會呼叫的函式。 onSearch: () => {} }; // 事件名稱。 Event = { CHANGE: `change${EVENT_NAMESPACE}`, SELECT: `select${EVENT_NAMESPACE}`, UNSELECT: `unselect${EVENT_NAMESPACE}`, MOVE: `move${EVENT_NAMESPACE}`, SEARCH: `search${EVENT_NAMESPACE}`, CLICK: `click${EVENT_NAMESPACE}` }; // 元素屬性標籤。 Attribute = { VALUE: 'data-value' }; // 目標 TARGET = { DESTINATION: 'destination', SOURCE: 'source' }; // 樣式名稱。 ClassName = { ITEM: 'item', ADD: 'add', SELECTED: 'selected' }; // 選擇器名稱。 Selector = { DESTINATION_ITEMS: '.destination.list .items', DESTINATION_ITEM: '.destination.list .items .item', DESTINATION_SELECTED_ITEM: '.destination.list .items .selected.item', SOURCE_ITEMS: '.source.list .items', SOURCE_ITEM: '.source.list .items .item', SOURCE_SELECTED_ITEM: '.source.list .items .selected.item', ANY_ITEM: '.items .item', ACTION_BUTTON: '.ts.add.button, .ts.remove.button', ITEM: (value) => { return `.items .item[data-value='${value}']`; }, SELECTED_ITEM: (value) => { return `.items .selected.item[data-value='${value}']`; } }; // 錯誤訊息。 Error = {}; // ------------------------------------------------------------------------ // 模組註冊 // ------------------------------------------------------------------------ ts.register({NAME, MODULE_NAMESPACE, Error, Settings}, ({$allModules, $this, element, debug, settings}) => { var module; // ------------------------------------------------------------------------ // 區域變數 // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // 模組定義 // ------------------------------------------------------------------------ return module = { get: { values: (from) => { var $item, values; values = []; switch (from) { case TARGET.DESTINATION: $item = $this.find(Selector.DESTINATION_ITEM); break; case TARGET.SOURCE: $item = $this.find(Selector.SOURCE_ITEM); } $item.each(function() { return values.push(ts(this).attr(Attribute.VALUE)); }); return values; }, selected: (from) => { var $item, selected; selected = []; switch (from) { case TARGET.DESTINATION: $item = $this.find(Selector.DESTINATION_SELECTED_ITEM); break; case TARGET.SOURCE: $item = $this.find(Selector.SOURCE_SELECTED_ITEM); } $item.each(function() { return selected.push(ts(this).attr(Attribute.VALUE)); }); return selected; }, destination: { values: () => { return module.get.values(TARGET.DESTINATION); }, selected: () => { return module.get.selected(TARGET.DESTINATION); } }, source: { values: () => { return module.get.values(TARGET.SOURCE); }, selected: () => { return module.get.selected(TARGET.SOURCE); } }, $item: (value) => { return $this.find(Selector.ITEM(value)); } }, create: { $value: (value, text) => { return ts('
').html(text).addClass(ClassName.ITEM).attr(Attribute.VALUE, value); } }, add: { destination: { value: (value, text) => { module.add.value(TARGET.DESTINATION, value, text); return $allModules; } }, source: { value: (value, text) => { module.add.value(TARGET.SOURCE, value, text); return $allModules; } }, value: (to, value, text) => { var $targetItems, i, item, len; switch (to) { case TARGET.DESTINATION: $targetItems = $this.find(Selector.DESTINATION_ITEMS); break; case TARGET.SOURCE: $targetItems = $this.find(Selector.SOURCE_ITEMS); } if (Array.isArray(value)) { for (i = 0, len = value.length; i < len; i++) { item = value[i]; if (module.has.value(item.value)) { continue; } $targetItems.append(module.create.$value(item.value, item.text)); } } else { if (module.has.value(value)) { return; } $targetItems.append(module.create.$value(value, text)); } module.scroll.toBottom($targetItems); return module.trigger.change(value); } }, has: { value: (value) => { return module.get.$item(value).length !== 0; } }, remove: { value: (value) => { var i, item, len; if (Array.isArray(value)) { for (i = 0, len = value.length; i < len; i++) { item = value[i]; module.get.$item(item).remove(); } } else { module.get.$item(value).remove(); } module.trigger.change(value); return $allModules; } }, set: { destination: { value: (values) => { $this.find(Selector.DESTINATION_ITEM).remove(); module.add.destination.value(value); return $allModules; } }, source: { value: (values) => { $this.find(Selector.SOURCE_ITEM).remove(); module.add.source.value(value); return $allModules; } } }, scroll: { toBottom: ($items) => { var items; items = $items.get(); return items.scrollTop = items.scrollHeight; }, destination: { toBottom: () => { return module.scroll.toBottom($this.find(Selector.DESTINATION_ITEMS)); } }, source: { toBottom: () => { return module.scroll.toBottom($this.find(Selector.SOURCE_ITEMS)); } } }, move: { values: (to, values) => { var $targetItems, i, len, value; if (!Array.isArray(values)) { values = [values]; } if (values.length === 0) { return; } switch (to) { case TARGET.DESTINATION: $targetItems = $this.find(Selector.DESTINATION_ITEMS); break; case TARGET.SOURCE: $targetItems = $this.find(Selector.SOURCE_ITEMS); } for (i = 0, len = values.length; i < len; i++) { value = values[i]; ts(Selector.ITEM(value)).appendTo($targetItems); module.unselect.value(value); } module.scroll.toBottom($targetItems); module.trigger.move(values, to); return module.trigger.change(values); }, to: { destination: (value) => { module.move.values(TARGET.DESTINATION, value); return $allModules; }, source: (value) => { module.move.values(TARGET.SOURCE, value); return $allModules; } } }, select: { value: (value) => { module.get.$item(value).addClass(ClassName.SELECTED); module.trigger.select(value); return $allModules; }, destination: { all: () => { $this.find(Selector.DESTINATION_ITEM).each(function() { return module.select.value(ts(this).attr(Attribute.VALUE)); }); return $allModules; } }, source: { all: () => { $this.find(Selector.SOURCE_ITEM).each(function() { return module.select.value(ts(this).attr(Attribute.VALUE)); }); return $allModules; } } }, unselect: { value: (value) => { module.get.$item(value).removeClass(ClassName.SELECTED); module.trigger.unselect(value); return $allModules; }, all: () => { module.unselect.destination.all(); module.unselect.source.all(); return $allModules; }, destination: { all: () => { $this.find(Selector.DESTINATION_ITEM).each(function() { return module.unselect.value(ts(this).attr(Attribute.VALUE)); }); return $allModules; } }, source: { all: () => { $this.find(Selector.SOURCE_ITEM).each(function() { return module.unselect.value(ts(this).attr(Attribute.VALUE)); }); return $allModules; } } }, is: { selected: (value) => { return $this.find(Selector.SELECTED_ITEM(value)).length !== 0; } }, trigger: { change: (value) => { return $this.trigger(Event.CHANGE, element, value); }, select: (value) => { return $this.trigger(Event.SELECT, element, value); }, unselect: (value) => { return $this.trigger(Event.UNSELECT, element, value); }, move: (values, to) => { return $this.trigger(Event.MOVE, element, values, to); } }, bind: { events: () => { $this.on(Event.CHANGE, (event, context, value) => { debug("發生 CHANGE 事件", context, value); return settings.onChange.call(context, event, value); }); $this.on(Event.SELECT, (event, context, value) => { debug("發生 SELECT 事件", context, value); return settings.onSelect.call(context, event, value); }); $this.on(Event.UNSELECT, (event, context, value) => { debug("發生 UNSELECT 事件", context, value); return settings.onUnselect.call(context, event, value); }); $this.on(Event.MOVE, (event, context, values, to) => { debug("發生 MOVE 事件", context, values, to); return settings.onMove.call(context, event, values, to); }); $this.on(Event.CLICK, Selector.ANY_ITEM, function() { var value; debug("發生 CLICK 事件", this); value = ts(this).attr(Attribute.VALUE); if (module.is.selected(value)) { return module.unselect.value(value); } else { return module.select.value(value); } }); return $this.on(Event.CLICK, Selector.ACTION_BUTTON, function() { debug("發生 BUTTON CLICK 事件", this); if (ts(this).hasClass(ClassName.ADD)) { return module.move.to.destination(module.get.source.selected()); } else { return module.move.to.source(module.get.destination.selected()); } }); } }, // ------------------------------------------------------------------------ // 基礎方法 // ------------------------------------------------------------------------ initialize: () => { debug('初始化穿梭框', element); return module.bind.events(); }, instantiate: () => { return debug('實例化穿梭框', element); }, refresh: () => { return $allModules; }, destroy: () => { debug('摧毀穿梭框', element); $this.removeData(MODULE_NAMESPACE).off(EVENT_NAMESPACE); return $allModules; } }; }); }).call(this);