123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- // Generated by CoffeeScript 2.0.0-beta4
- (function() {
- // ------------------------------------------------------------------------
- // 變數與常數設置
- // ------------------------------------------------------------------------
- // 模組名稱。
- var Attribute, ClassName, EVENT_NAMESPACE, Error, Event, MODULE_NAMESPACE, Metadata, Mode, NAME, Order, Selector, Settings;
- NAME = 'sortable';
- // 模組事件鍵名。
- EVENT_NAMESPACE = `.${NAME}`;
- // 模組命名空間。
- MODULE_NAMESPACE = `module-${NAME}`;
- // 滑鼠拖曳出外,回來可以點擊依然可以放到 pull 容器
- // 模組設定。
- Settings = {
- // 消音所有提示,甚至是錯誤訊息。
- silent: false,
- // 顯示除錯訊息。
- debug: true,
- // 監聽 DOM 結構異動並自動重整快取。
- observeChanges: true,
- // 指定的拖曳把手選擇器,設置為 `false` 則為整個元素皆可拖曳。
- handle: false,
- // 到拖曳開始之前必須按住的指定毫秒數,避免點擊成為不必要的拖曳。
- delay: 350,
- // 是否能在相同拖放排序內重新排序。
- sort: true,
- // 群組名稱,相同的名稱拖放排序清單可以交替其項目。
- group: false,
- // 此拖放排序的支援模式。(`all` 表示可拖放、`put` 表示僅可放入、`pull` 表示僅可移出、`all` 表示都可)
- mode: 'all',
- // 這個拖放排序是否已垂直清單為主,改為 `false` 會有利於水平清單。
- vertical: true,
- // 當拖拉開始時所會呼叫的回呼函式。
- onDragStart: (value) => {},
- // 當拖拉途中所會呼叫的回呼函式,間隔是 350 毫秒。
- onDrag: (value) => {},
- // 當拖拉結束並丟下元素時所會呼叫的回呼函式。
- onDrop: (value) => {},
- // 當放下被禁止(如:範圍外、被回呼函式拒絕)時所會呼叫的函式。
- onDeny: (value) => {},
- // 當放下時跟一開始沒有差異時所會呼叫的回呼函式。
- onCancel: (value) => {},
- // 當有變動(新增、移除、重新排序)時所會呼叫的回呼函式。
- onChange: (value) => {},
- // 當項目新增時所會呼叫的回呼函式,回傳 `false` 表示不接受此新增。
- onAdd: (value) => {},
- // 當項目被移出時所會呼叫的回呼函式。
- onRemove: (value) => {}
- };
- // 事件名稱。
- Event = {
- DRAGSTART: `dragstart${EVENT_NAMESPACE}`,
- DRAG: `drag${EVENT_NAMESPACE}`,
- DROP: `drop${EVENT_NAMESPACE}`,
- DENY: `deny${EVENT_NAMESPACE}`,
- CANCEL: `cancel${EVENT_NAMESPACE}`,
- CHANGE: `change${EVENT_NAMESPACE}`,
- ADD: `add${EVENT_NAMESPACE}`,
- REMOVE: `remove${EVENT_NAMESPACE}`,
- MOUSEMOVE: `mousemove${EVENT_NAMESPACE}`,
- MOUSEUP: `mouseup${EVENT_NAMESPACE}`,
- MOUSEDOWN: `mousedown${EVENT_NAMESPACE}`
- };
- // 中繼資料名稱。
- Metadata = {
- X_OFFSET: 'xOffset',
- Y_OFFSET: 'yOffset',
- ENABLE: 'enable'
- };
- // 模式 =
- Mode = {
- PULL: 'pull',
- PUT: 'put',
- ALL: 'all'
- };
- // 順序。
- Order = {
- AFTER: 'after',
- BEFORE: 'before'
- };
- // 元素標籤。
- Attribute = {
- GROUP: 'data-draggable-group',
- CONTAINER: 'data-draggable-container',
- DRAGGABLE: 'data-draggable',
- DRAGGING: 'data-draggable-dragging',
- VALUE: 'data-value',
- GHOST: 'data-draggable-ghost',
- PLACEHOLDER: 'data-draggable-placeholder',
- NATIVE_DRAGGABLE: 'draggable',
- HIDDEN: 'hidden'
- };
- // 樣式名稱。
- ClassName = {};
- // 選擇器名稱。
- Selector = {
- BODY: 'body',
- NATIVE_DRAGGABLE: `[${Attribute.NATIVE_DRAGGABLE}]`,
- DRAGGING: `[${Attribute.DRAGGING}]`,
- DRAGGABLE: `[${Attribute.DRAGGABLE}]`,
- GHOST: `[${Attribute.GHOST}]`,
- PLACEHOLDER: `[${Attribute.PLACEHOLDER}]`,
- CONTAINER: `[${Attribute.CONTAINER}]`,
- PLACEHOLDER: `[${Attribute.PLACEHOLDER}]`,
- GROUP: `[${Attribute.GROUP}]`,
- HIDDEN_DRAGGABLE: `[${Attribute.DRAGGABLE}][${Attribute.HIDDEN}]`,
- TRUE_DRAGGABLE: `[${Attribute.DRAGGABLE}]:not([${Attribute.HIDDEN}])`,
- DRAGGABLE_VALUE: (value) => {
- return `[${Attribute.VALUE}='${value}']`;
- }
- };
- // 錯誤訊息。
- Error = {};
- // ------------------------------------------------------------------------
- // 模組註冊
- // ------------------------------------------------------------------------
- ts.register({NAME, MODULE_NAMESPACE, Error, Settings}, ({$allModules, $this, element, debug, settings}) => {
- var $original, $placeholder, draggingInterval, draggingTimer, module;
- // ------------------------------------------------------------------------
- // 區域變數
- // ------------------------------------------------------------------------
- $original = ts();
- $placeholder = ts();
- draggingTimer = null;
- draggingInterval = 350;
- // ------------------------------------------------------------------------
- // 模組定義
- // ------------------------------------------------------------------------
- return module = {
- sort: (values) => {
- var i, len, value;
- for (i = 0, len = values.length; i < len; i++) {
- value = values[i];
- $this.find(Selector.DRAGGABLE_VALUE(value)).appendTo(element);
- }
- return $allModules;
- },
- enable: () => {
- $this.data(Metadata.ENABLE, true);
- return $allModules;
- },
- disable: () => {
- $this.data(Metadata.ENABLE, false);
- return $allModules;
- },
- start: {
- dragging: () => {
- draggingTimer = setInterval(() => {
- return module.trigger.drag();
- }, draggingInterval);
- return $original.attr(Attribute.DRAGGING, 'true');
- }
- },
- stop: {
- dragging: () => {
- return clearInterval(draggingTimer);
- }
- },
- reset: {
- dragging: () => {
- return ts(Selector.DRAGGING).removeAttr(Attribute.DRAGGING);
- }
- },
- hide: {
- original: () => {
- return $original.attr(Attribute.HIDDEN, 'hidden');
- }
- },
- unhide: {
- original: () => {
- return $(Selector.HIDDEN_DRAGGABLE).removeAttr(Attribute.HIDDEN);
- }
- },
- set: {
- group: (name) => {
- return $this.attr(Attribute.GROUP, settings.group);
- }
- },
- get: {
- $dragging: () => {
- return ts(Selector.DRAGGING);
- },
- $draggable: (element) => {
- return ts(element).closest(Selector.DRAGGABLE);
- },
- last: {
- $item: () => {
- return $this.find(Selector.DRAGGABLE).last();
- }
- },
- dragging: {
- element: () => {
- return ts(Selector.HIDDEN_DRAGGABLE).get();
- },
- value: () => {
- return ts(Selector.HIDDEN_DRAGGABLE).attr(Attribute.VALUE);
- }
- },
- container: (element) => {
- return ts(element).closest(Selector.CONTAINER);
- },
- group: {
- name: () => {
- return $this.attr(Attribute.GROUP);
- }
- },
- mode: () => {
- return settings.mode;
- },
- sort: () => {
- return settings.sort;
- },
- value: () => {
- var values;
- values = [];
- $this.find(Selector.DRAGGABLE).each(function() {
- var value;
- value = ts(this).attr(Attribute.VALUE);
- if (value) {
- return values.push(value);
- }
- });
- return values;
- }
- },
- is: {
- draggable: (element) => {
- return ts(element).attr(Attribute.DRAGGABLE) === 'true';
- },
- child: (element) => {
- return $this.contains(element);
- },
- sortable: () => {
- return settings.sort === true;
- },
- vertical: () => {
- return settings.vertical === true;
- },
- enable: () => {
- return $this.data(Metadata.ENABLE);
- },
- disable: () => {
- return !$this.data(Metadata.ENABLE);
- },
- same: {
- group: ($target) => {
- var $container, name;
- $container = module.get.container($target);
- if ($container.is(element)) {
- return true;
- }
- name = $container.sortable('get group name');
- return name !== null && name === module.get.group.name();
- },
- container: ($container) => {
- return $container.is(element);
- }
- },
- handle: (element) => {
- return ts(element).is(settings.handle);
- }
- },
- has: {
- dragging: () => {
- return $this.find(Selector.DRAGGING).exists();
- },
- placeholder: () => {
- return $this.find(Selector.PLACEHOLDER).exists();
- },
- item: () => {
- return $this.find(Selector.DRAGGABLE).exists();
- },
- handle: () => {
- return settings.handle !== false;
- }
- },
- create: {
- ghost: (x, y) => {
- return $original.clone().attr(Attribute.GHOST, 'true').data({
- [`${Metadata.X_OFFSET}`]: x - $original.rect().x,
- [`${Metadata.Y_OFFSET}`]: y - $original.rect().y
- }).css({
- width: $original.rect().width,
- height: $original.rect().height
- }).appendTo(Selector.BODY);
- },
- placeholder: () => {
- return $placeholder = $original.clone().attr(Attribute.PLACEHOLDER, 'true').removeAttr(Attribute.DRAGGING).appendTo(Selector.BODY);
- }
- },
- remove: {
- ghost: () => {
- return ts(Selector.GHOST).remove();
- },
- placeholder: () => {
- return ts(Selector.PLACEHOLDER).remove();
- }
- },
- move: {
- ghost: (x, y) => {
- var $ghost;
- $ghost = ts(Selector.GHOST);
- return $ghost.css({
- top: y - $ghost.data(Metadata.Y_OFFSET),
- left: x - $ghost.data(Metadata.X_OFFSET)
- });
- },
- placeholder: (x, y) => {
- var $container, $draggable, $last, $pointing, isAllOrSin, isTanOrCos, isVertical;
- $pointing = ts.fromPoint(x, y);
- $draggable = $pointing.closest(Selector.DRAGGABLE);
- $container = module.get.container($draggable);
- if ($draggable.exists()) {
- isAllOrSin = y - $draggable.rect().y < $draggable.rect().height / 2;
- isTanOrCos = x - $draggable.rect().x < $draggable.rect().width / 2;
- isVertical = $container.sortable('is vertical');
- if ((isAllOrSin && isVertical) || (isTanOrCos && !isVertical)) {
- $placeholder.insertBefore($draggable);
- } else {
- $placeholder.insertAfter($draggable);
- }
- return;
- }
- $container = module.get.container($pointing);
- $draggable = $container.find(Selector.TRUE_DRAGGABLE);
- if (!$container.exists()) {
- return;
- }
- if (!$draggable.exists()) {
- module.insert.placeholder($container);
- return;
- }
- $last = $draggable.last();
- if ($last.exists()) {
- return module.append.placeholder(Order.AFTER, $last);
- }
- },
- original: () => {
- return module.get.$dragging().insertAfter(ts(Selector.PLACEHOLDER));
- }
- },
- append: {
- placeholder: (order, to) => {
- switch (order) {
- case Order.BEFORE:
- return $placeholder.insertBefore(to);
- case Order.AFTER:
- return $placeholder.insertAfter(to);
- }
- }
- },
- insert: {
- placeholder: (to) => {
- return $placeholder.appendTo(to);
- }
- },
- trigger: {
- dragStart: () => {
- return $this.trigger(Event.DRAGSTART, module.get.dragging.element(), module.get.dragging.value());
- },
- drag: () => {
- return $this.trigger(Event.DRAG, module.get.dragging.element(), module.get.dragging.value());
- },
- drop: () => {
- return $this.trigger(Event.DROP, module.get.dragging.element(), module.get.dragging.value());
- },
- deny: () => {
- return $this.trigger(Event.DENY, module.get.dragging.element(), module.get.dragging.value());
- },
- cancel: () => {
- return $this.trigger(Event.CANCEL, module.get.dragging.element(), module.get.dragging.value());
- },
- change: () => {
- return $this.trigger(Event.CHANGE, module.get.dragging.element(), module.get.dragging.value());
- },
- add: (valueElement, value) => {
- debug('發生 ADD 事件', valueElement, value);
- return settings.onAdd.call(valueElement, value);
- },
- remove: () => {
- return $this.trigger(Event.REMOVE, module.get.dragging.element(), module.get.dragging.value());
- }
- },
- unbind: {
- mousemove: () => {
- return ts(Selector.BODY).off(Event.MOUSEMOVE);
- }
- },
- bind: {
- mousemove: () => {
- return ts(Selector.BODY).on(Event.MOUSEMOVE, (event) => {
- var $container, $element, $placeholderContainer, hasContainerItem, hasPlaceholder, isContainerSortable, isPullContainer, isPutContainer, isSameContainer, isSortable;
- debug('發生 MOUSEMOVE 事件', element, this);
- if (module.is.disable()) {
- return;
- }
- module.move.ghost(event.clientX, event.clientY);
- if (!module.has.dragging()) {
- return;
- }
- $element = ts.fromPoint(event.clientX, event.clientY);
- $container = module.get.container($element);
- if (!module.is.same.group($element)) {
- return;
- }
- if ($container.sortable('is disable')) {
- return;
- }
- hasPlaceholder = module.has.placeholder();
- isSortable = module.is.sortable();
- isPullContainer = $container.sortable('get mode') === Mode.PULL;
- isSameContainer = module.is.same.container($container);
- switch (false) {
- case !isPullContainer:
- return;
- case !(!isSortable && isSameContainer && hasPlaceholder):
- return;
- }
- $placeholderContainer = module.get.container($placeholder);
- hasContainerItem = $container.sortable('has item');
- isContainerSortable = $container.sortable('is sortable');
- isPutContainer = $placeholderContainer.sortable('get mode') === Mode.PUT;
- isSortable = $placeholderContainer.sortable('is sortable');
- switch (false) {
- case !(!isSameContainer && isPutContainer && isSortable):
- return;
- case !(!isSameContainer && !isContainerSortable):
- if (!hasContainerItem) {
- module.insert.placeholder($container);
- } else {
- module.append.placeholder(Order.AFTER, $container.sortable('get last $item'));
- }
- return;
- case !(!isSortable && isSameContainer && !hasPlaceholder):
- module.append.placeholder(Order.AFTER, $original);
- return;
- }
- return module.move.placeholder(event.clientX, event.clientY);
- });
- },
- events: () => {
- $this.on(Event.DRAGSTART, (event, context, value) => {
- debug('發生 DRAGSTART 事件', context, value);
- return settings.onDragStart.call(context, event, value);
- });
- $this.on(Event.DRAG, (event, context, value) => {
- debug('發生 DRAG 事件', context, value);
- return settings.onDrag.call(context, event, value);
- });
- $this.on(Event.DROP, (event, context, value) => {
- debug('發生 DROP 事件', context, value);
- return settings.onDrop.call(context, event, value);
- });
- $this.on(Event.DENY, (event, context, value) => {
- debug('發生 DENY 事件', context, value);
- return settings.onDeny.call(context, event, value);
- });
- $this.on(Event.CANCEL, (event, context, value) => {
- debug('發生 CANCEL 事件', context, value);
- return settings.onCancel.call(context, event, value);
- });
- $this.on(Event.CHANGE, (event, context, value) => {
- debug('發生 CHANGE 事件', context, value);
- return settings.onChange.call(context, event, value);
- });
- $this.on(Event.REMOVE, (event, context, value) => {
- debug('發生 REMOVE 事件', context, value);
- return settings.onRemove.call(context, event, value);
- });
- ts(Selector.BODY).on(Event.MOUSEDOWN, (event) => {
- var $target;
- debug('發生 MOUSEDOWN 事件', element, this);
- if (module.is.disable()) {
- return;
- }
- $target = ts(event.target);
- if (module.has.handle() && !module.is.handle($target)) {
- return;
- }
- if (!module.is.draggable($target)) {
- $target = module.get.$draggable($target);
- }
- switch (false) {
- case !!$target.exists():
- return;
- case !!module.is.child($target):
- return;
- case !(module.get.mode() === Mode.PUT && !module.is.sortable()):
- return;
- }
- $original = $target;
- module.trigger.dragStart();
- module.start.dragging();
- module.create.ghost(event.clientX, event.clientY);
- module.move.ghost(event.clientX, event.clientY);
- module.create.placeholder();
- module.move.placeholder(event.clientX, event.clientY);
- module.hide.original();
- return module.bind.mousemove();
- });
- return ts(Selector.BODY).on(Event.MOUSEUP, (event) => {
- var $container, newValue, oldValue;
- debug('發生 MOUSEUP 事件', element, this);
- if (module.is.disable()) {
- return;
- }
- module.stop.dragging();
- module.remove.ghost();
- module.unbind.mousemove();
- if (!module.has.dragging()) {
- return;
- }
- module.trigger.drop();
- $container = module.get.container(event.target);
- if ($container.exists() && module.is.same.container($container)) {
- oldValue = module.get.value().toString();
- module.move.original();
- newValue = module.get.value().toString();
- if (oldValue !== '' || newValue !== '') {
- if (oldValue === newValue) {
- module.trigger.cancel();
- } else {
- module.trigger.change();
- }
- }
- } else {
- if ($container.sortable('trigger add', module.get.dragging.element(), module.get.dragging.value())) {
- module.move.original();
- $container.sortable('trigger change');
- module.trigger.remove();
- module.trigger.change();
- } else {
- module.trigger.cancel();
- module.trigger.deny();
- }
- }
- module.remove.placeholder();
- module.unhide.original();
- return module.reset.dragging();
- });
- }
- },
- // ------------------------------------------------------------------------
- // 基礎方法
- // ------------------------------------------------------------------------
- initialize: () => {
- debug('初始化拖放排序', element);
- module.bind.events();
- module.enable();
- $this.attr(Attribute.CONTAINER, true).find(Selector.NATIVE_DRAGGABLE).removeAttr(Attribute.NATIVE_DRAGGABLE).attr(Attribute.DRAGGABLE, 'true');
- if (settings.group !== false) {
- return module.set.group(settings.group);
- }
- },
- instantiate: () => {
- return debug('實例化拖放排序', element);
- },
- refresh: () => {
- return $allModules;
- },
- destroy: () => {
- debug('摧毀拖放排序', element);
- $this.removeData(MODULE_NAMESPACE).off(EVENT_NAMESPACE);
- return $allModules;
- }
- };
- });
- }).call(this);
|