simple_form_nested_fields 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "simple_form_nested_fields"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
1
+ #= require simple_form_nested_fields__links
2
+ #= require simple_form_nested_fields__sortable
3
+
4
+ do ($ = jQuery, window, document) ->
5
+ pluginName = 'SimpleFormNestedFields'
6
+ defaults =
7
+ debug: false
8
+
9
+ class Plugin
10
+ constructor: (@element, options) ->
11
+ @options = $.extend {}, defaults, options
12
+ @_defaults = defaults
13
+ @_name = pluginName
14
+ @$element = $(@element)
15
+ @init()
16
+
17
+ init: ->
18
+ @$element.SimpleFormNestedFields__Links()
19
+ @$element.SimpleFormNestedFields__Sortable() if @is_sortable()
20
+
21
+ destroy: ->
22
+ @$element.data('plugin_SimpleFormNestedFields__Links').destroy()
23
+ @$element.data('plugin_SimpleFormNestedFields__Sortable').destroy()
24
+
25
+ is_sortable: -> @element.classList.contains('simple_form_nested_fields__sortable')
26
+
27
+ # A really lightweight plugin wrapper around the constructor,
28
+ # preventing against multiple instantiations
29
+ $.fn[pluginName] = (options) ->
30
+ @each ->
31
+ if !$.data(@, "plugin_#{pluginName}")
32
+ $.data(@, "plugin_#{pluginName}", new Plugin(@, options))
@@ -0,0 +1,49 @@
1
+ do ($ = jQuery, window, document) ->
2
+ pluginName = 'SimpleFormNestedFields__Links'
3
+ defaults =
4
+ debug: false
5
+ new_item_class_name: 'simple_form_nested_fields__item__new'
6
+ regexp: new RegExp("__INDEX_PLACEHOLDER__", 'g')
7
+
8
+ class Plugin
9
+ constructor: (@element, options) ->
10
+ @options = $.extend {}, defaults, options
11
+ @_defaults = defaults
12
+ @_name = pluginName
13
+ @$element = $(@element)
14
+ @init()
15
+
16
+ init: ->
17
+ @$element.on "click.#{@_name}", '.simple_form_nested_fields__link', (e) =>
18
+ e.preventDefault()
19
+ link = e.target
20
+ switch
21
+ when link.classList.contains('simple_form_nested_fields__link__add') then @add_new_item(link)
22
+ when link.classList.contains('simple_form_nested_fields__link__remove') then @remove_item(link)
23
+
24
+ destroy: ->
25
+ @$element.off "click.#{@_name}", '.simple_form_nested_fields__link__add'
26
+
27
+ get_index: -> new Date().getTime()
28
+ get_template: (link) -> $(link).data('template').replace(@options.regexp, @get_index())
29
+ get_items_container: -> @$element.find('.simple_form_nested_fields__items')
30
+
31
+ add_new_item: (link) ->
32
+ $template = $(@get_template(link))
33
+ $template.addClass(@options.new_item_class_name)
34
+ @get_items_container().append($template)
35
+
36
+ remove_item: (link) ->
37
+ $item = $(link).closest('.simple_form_nested_fields__item')
38
+ if $item.hasClass(@options.new_item_class_name)
39
+ $item.remove()
40
+ else
41
+ $item.find('input[type=hidden]').val('1')
42
+ $item.hide()
43
+
44
+ # A really lightweight plugin wrapper around the constructor,
45
+ # preventing against multiple instantiations
46
+ $.fn[pluginName] = (options) ->
47
+ @each ->
48
+ if !$.data(@, "plugin_#{pluginName}")
49
+ $.data(@, "plugin_#{pluginName}", new Plugin(@, options))
@@ -0,0 +1,55 @@
1
+ #= require sortablejs/1.6.1/index.js
2
+
3
+ do ($ = jQuery, window, document) ->
4
+ pluginName = 'SimpleFormNestedFields__Sortable'
5
+ defaults =
6
+ debug: false
7
+
8
+ class Plugin
9
+ constructor: (@element, options) ->
10
+ @$element = $(@element)
11
+ @$simple_form_nested_fields = @$element.data('plugin_SimpleFormNestedFields')
12
+ @options = $.extend {}, defaults, options
13
+ @_defaults = defaults
14
+ @_name = pluginName
15
+ @init()
16
+
17
+ init: ->
18
+ return if @sortable
19
+
20
+ @sortable = new Sortable(
21
+ @get_items_container()[0],
22
+
23
+ animation: 150,
24
+ draggable: '.simple_form_nested_fields__item',
25
+ ghostClass: '.simple_form_nested_fields__ghost',
26
+ handle: '.simple_form_nested_fields__item_handle',
27
+
28
+ # TODO: onAdd is not being triggered?
29
+ onAdd: (e) => @update_item_positions(),
30
+ onUpdate: (e) => @update_item_positions(),
31
+ onRemove: (e) => @update_item_positions(),
32
+ )
33
+
34
+ @$element.on "update_item_positions.#{@_name}", (e) =>
35
+ e.stopPropagation()
36
+ @update_item_positions()
37
+
38
+ @update_item_positions()
39
+
40
+ destroy: ->
41
+ @sortable.destroy() if @sortable
42
+
43
+ update_item_positions: ->
44
+ @get_items().each (i, el) =>
45
+ $(el).find('input[name*="position"]').val(i+1)
46
+
47
+ get_items: -> @get_items_container().find('.simple_form_nested_fields__item')
48
+ get_items_container: -> @$element.find('.simple_form_nested_fields__items')
49
+
50
+ # A really lightweight plugin wrapper around the constructor,
51
+ # preventing against multiple instantiations
52
+ $.fn[pluginName] = (options) ->
53
+ @each ->
54
+ if !$.data(@, "plugin_#{pluginName}")
55
+ $.data(@, "plugin_#{pluginName}", new Plugin(@, options))
@@ -0,0 +1,2 @@
1
+ /*! Sortable 1.6.1 - MIT | git://github.com/rubaxa/Sortable.git */
2
+ !function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():window.Sortable=a()}(function(){"use strict";function a(a,b){if(!a||!a.nodeType||1!==a.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(a);this.el=a,this.options=b=t({},b),a[T]=this;var c={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0}};for(var d in c)!(d in b)&&(b[d]=c[d]);ga(b);for(var e in this)"_"===e.charAt(0)&&"function"==typeof this[e]&&(this[e]=this[e].bind(this));this.nativeDraggable=!b.forceFallback&&$,f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),f(a,"pointerdown",this._onTapStart),this.nativeDraggable&&(f(a,"dragover",this),f(a,"dragenter",this)),ea.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a,b){"clone"!==a.lastPullMode&&(b=!0),z&&z.state!==b&&(i(z,"display",b?"none":""),b||z.state&&(a.options.group.revertClone?(A.insertBefore(z,B),a._animate(w,z)):A.insertBefore(z,w)),z.state=b)}function c(a,b,c){if(a){c=c||V;do if(">*"===b&&a.parentNode===c||r(a,b))return a;while(a=d(a))}return null}function d(a){var b=a.host;return b&&b.nodeType?b:a.parentNode}function e(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function f(a,b,c){a.addEventListener(b,c,Z)}function g(a,b,c){a.removeEventListener(b,c,Z)}function h(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(R," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(R," ")}}function i(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return V.defaultView&&V.defaultView.getComputedStyle?c=V.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function j(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;e<f;e++)c(d[e],e);return d}return[]}function k(a,b,c,d,e,f,g){a=a||b[T];var h=V.createEvent("Event"),i=a.options,j="on"+c.charAt(0).toUpperCase()+c.substr(1);h.initEvent(c,!0,!0),h.to=b,h.from=e||b,h.item=d||b,h.clone=z,h.oldIndex=f,h.newIndex=g,b.dispatchEvent(h),i[j]&&i[j].call(a,h)}function l(a,b,c,d,e,f,g,h){var i,j,k=a[T],l=k.options.onMove;return i=V.createEvent("Event"),i.initEvent("move",!0,!0),i.to=b,i.from=a,i.dragged=c,i.draggedRect=d,i.related=e||b,i.relatedRect=f||b.getBoundingClientRect(),i.willInsertAfter=h,a.dispatchEvent(i),l&&(j=l.call(k,i,g)),j}function m(a){a.draggable=!1}function n(){aa=!1}function o(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5||b.clientX-(d.left+d.width)>5}function p(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function q(a,b){var c=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"===a.nodeName.toUpperCase()||">*"!==b&&!r(a,b)||c++;return c}function r(a,b){if(a){b=b.split(".");var c=b.shift().toUpperCase(),d=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");return!(""!==c&&a.nodeName.toUpperCase()!=c||b.length&&((" "+a.className+" ").match(d)||[]).length!=b.length)}return!1}function s(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function t(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function u(a){return X?X(a).clone(!0)[0]:Y&&Y.dom?Y.dom(a).cloneNode(!0):a.cloneNode(!0)}function v(a){for(var b=a.getElementsByTagName("input"),c=b.length;c--;){var d=b[c];d.checked&&da.push(d)}}if("undefined"==typeof window||!window.document)return function(){throw new Error("Sortable.js requires a window with a document")};var w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q={},R=/\s+/g,S=/left|right|inline/,T="Sortable"+(new Date).getTime(),U=window,V=U.document,W=U.parseInt,X=U.jQuery||U.Zepto,Y=U.Polymer,Z=!1,$=!!("draggable"in V.createElement("div")),_=function(a){return!navigator.userAgent.match(/Trident.*rv[ :]?11\./)&&(a=V.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents)}(),aa=!1,ba=Math.abs,ca=Math.min,da=[],ea=[],fa=s(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h,i,j=c[T],k=b.scrollSensitivity,l=b.scrollSpeed,m=a.clientX,n=a.clientY,o=window.innerWidth,p=window.innerHeight;if(E!==c&&(D=b.scroll,E=c,F=b.scrollFn,D===!0)){D=c;do if(D.offsetWidth<D.scrollWidth||D.offsetHeight<D.scrollHeight)break;while(D=D.parentNode)}D&&(d=D,e=D.getBoundingClientRect(),f=(ba(e.right-m)<=k)-(ba(e.left-m)<=k),g=(ba(e.bottom-n)<=k)-(ba(e.top-n)<=k)),f||g||(f=(o-m<=k)-(m<=k),g=(p-n<=k)-(n<=k),(f||g)&&(d=U)),Q.vx===f&&Q.vy===g&&Q.el===d||(Q.el=d,Q.vx=f,Q.vy=g,clearInterval(Q.pid),d&&(Q.pid=setInterval(function(){return i=g?g*l:0,h=f?f*l:0,"function"==typeof F?F.call(j,h,i,a):void(d===U?U.scrollTo(U.pageXOffset+h,U.pageYOffset+i):(d.scrollTop+=i,d.scrollLeft+=h))},24)))}},30),ga=function(a){function b(a,b){return void 0!==a&&a!==!0||(a=c.name),"function"==typeof a?a:function(c,d){var e=d.options.group.name;return b?a:a&&(a.join?a.indexOf(e)>-1:e==a)}}var c={},d=a.group;d&&"object"==typeof d||(d={name:d}),c.name=d.name,c.checkPull=b(d.pull,!0),c.checkPut=b(d.put),c.revertClone=d.revertClone,a.group=c};a.prototype={constructor:a,_onTapStart:function(a){var b,d=this,e=this.el,f=this.options,g=f.preventOnFilter,h=a.type,i=a.touches&&a.touches[0],j=(i||a).target,l=a.target.shadowRoot&&a.path&&a.path[0]||j,m=f.filter;if(v(e),!w&&!(/mousedown|pointerdown/.test(h)&&0!==a.button||f.disabled)&&(j=c(j,f.draggable,e),j&&C!==j)){if(b=q(j,f.draggable),"function"==typeof m){if(m.call(this,a,j,this))return k(d,l,"filter",j,e,b),void(g&&a.preventDefault())}else if(m&&(m=m.split(",").some(function(a){if(a=c(l,a.trim(),e))return k(d,a,"filter",j,e,b),!0})))return void(g&&a.preventDefault());f.handle&&!c(l,f.handle,e)||this._prepareDragStart(a,i,j,b)}},_prepareDragStart:function(a,b,c,d){var e,g=this,i=g.el,l=g.options,n=i.ownerDocument;c&&!w&&c.parentNode===i&&(N=a,A=i,w=c,x=w.parentNode,B=w.nextSibling,C=c,L=l.group,J=d,this._lastX=(b||a).clientX,this._lastY=(b||a).clientY,w.style["will-change"]="transform",e=function(){g._disableDelayedDrag(),w.draggable=g.nativeDraggable,h(w,l.chosenClass,!0),g._triggerDragStart(a,b),k(g,A,"choose",w,A,J)},l.ignore.split(",").forEach(function(a){j(w,a.trim(),m)}),f(n,"mouseup",g._onDrop),f(n,"touchend",g._onDrop),f(n,"touchcancel",g._onDrop),f(n,"pointercancel",g._onDrop),f(n,"selectstart",g),l.delay?(f(n,"mouseup",g._disableDelayedDrag),f(n,"touchend",g._disableDelayedDrag),f(n,"touchcancel",g._disableDelayedDrag),f(n,"mousemove",g._disableDelayedDrag),f(n,"touchmove",g._disableDelayedDrag),f(n,"pointermove",g._disableDelayedDrag),g._dragStartTimer=setTimeout(e,l.delay)):e())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),g(a,"mouseup",this._disableDelayedDrag),g(a,"touchend",this._disableDelayedDrag),g(a,"touchcancel",this._disableDelayedDrag),g(a,"mousemove",this._disableDelayedDrag),g(a,"touchmove",this._disableDelayedDrag),g(a,"pointermove",this._disableDelayedDrag)},_triggerDragStart:function(a,b){b=b||("touch"==a.pointerType?a:null),b?(N={target:w,clientX:b.clientX,clientY:b.clientY},this._onDragStart(N,"touch")):this.nativeDraggable?(f(w,"dragend",this),f(A,"dragstart",this._onDragStart)):this._onDragStart(N,!0);try{V.selection?setTimeout(function(){V.selection.empty()}):window.getSelection().removeAllRanges()}catch(a){}},_dragStarted:function(){if(A&&w){var b=this.options;h(w,b.ghostClass,!0),h(w,b.dragClass,!1),a.active=this,k(this,A,"start",w,A,J)}else this._nulling()},_emulateDragOver:function(){if(O){if(this._lastX===O.clientX&&this._lastY===O.clientY)return;this._lastX=O.clientX,this._lastY=O.clientY,_||i(y,"display","none");var a=V.elementFromPoint(O.clientX,O.clientY),b=a,c=ea.length;if(b)do{if(b[T]){for(;c--;)ea[c]({clientX:O.clientX,clientY:O.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);_||i(y,"display","")}},_onTouchMove:function(b){if(N){var c=this.options,d=c.fallbackTolerance,e=c.fallbackOffset,f=b.touches?b.touches[0]:b,g=f.clientX-N.clientX+e.x,h=f.clientY-N.clientY+e.y,j=b.touches?"translate3d("+g+"px,"+h+"px,0)":"translate("+g+"px,"+h+"px)";if(!a.active){if(d&&ca(ba(f.clientX-this._lastX),ba(f.clientY-this._lastY))<d)return;this._dragStarted()}this._appendGhost(),P=!0,O=f,i(y,"webkitTransform",j),i(y,"mozTransform",j),i(y,"msTransform",j),i(y,"transform",j),b.preventDefault()}},_appendGhost:function(){if(!y){var a,b=w.getBoundingClientRect(),c=i(w),d=this.options;y=w.cloneNode(!0),h(y,d.ghostClass,!1),h(y,d.fallbackClass,!0),h(y,d.dragClass,!0),i(y,"top",b.top-W(c.marginTop,10)),i(y,"left",b.left-W(c.marginLeft,10)),i(y,"width",b.width),i(y,"height",b.height),i(y,"opacity","0.8"),i(y,"position","fixed"),i(y,"zIndex","100000"),i(y,"pointerEvents","none"),d.fallbackOnBody&&V.body.appendChild(y)||A.appendChild(y),a=y.getBoundingClientRect(),i(y,"width",2*b.width-a.width),i(y,"height",2*b.height-a.height)}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;this._offUpEvents(),L.checkPull(this,this,w,a)&&(z=u(w),z.draggable=!1,z.style["will-change"]="",i(z,"display","none"),h(z,this.options.chosenClass,!1),A.insertBefore(z,w),k(this,A,"clone",w)),h(w,d.dragClass,!0),b?("touch"===b?(f(V,"touchmove",this._onTouchMove),f(V,"touchend",this._onDrop),f(V,"touchcancel",this._onDrop),f(V,"pointermove",this._onTouchMove),f(V,"pointerup",this._onDrop)):(f(V,"mousemove",this._onTouchMove),f(V,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,50)):(c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,w)),f(V,"drop",this),setTimeout(this._dragStarted,0))},_onDragOver:function(d){var e,f,g,h,j=this.el,k=this.options,m=k.group,p=a.active,q=L===m,r=!1,s=k.sort;if(void 0!==d.preventDefault&&(d.preventDefault(),!k.dragoverBubble&&d.stopPropagation()),!w.animated&&(P=!0,p&&!k.disabled&&(q?s||(h=!A.contains(w)):M===this||(p.lastPullMode=L.checkPull(this,p,w,d))&&m.checkPut(this,p,w,d))&&(void 0===d.rootEl||d.rootEl===this.el))){if(fa(d,k,this.el),aa)return;if(e=c(d.target,k.draggable,j),f=w.getBoundingClientRect(),M!==this&&(M=this,r=!0),h)return b(p,!0),x=A,void(z||B?A.insertBefore(w,z||B):s||A.appendChild(w));if(0===j.children.length||j.children[0]===y||j===d.target&&o(j,d)){if(0!==j.children.length&&j.children[0]!==y&&j===d.target&&(e=j.lastElementChild),e){if(e.animated)return;g=e.getBoundingClientRect()}b(p,q),l(A,j,w,f,e,g,d)!==!1&&(w.contains(j)||(j.appendChild(w),x=j),this._animate(f,w),e&&this._animate(g,e))}else if(e&&!e.animated&&e!==w&&void 0!==e.parentNode[T]){G!==e&&(G=e,H=i(e),I=i(e.parentNode)),g=e.getBoundingClientRect();var t=g.right-g.left,u=g.bottom-g.top,v=S.test(H.cssFloat+H.display)||"flex"==I.display&&0===I["flex-direction"].indexOf("row"),C=e.offsetWidth>w.offsetWidth,D=e.offsetHeight>w.offsetHeight,E=(v?(d.clientX-g.left)/t:(d.clientY-g.top)/u)>.5,F=e.nextElementSibling,J=!1;if(v){var K=w.offsetTop,N=e.offsetTop;J=K===N?e.previousElementSibling===w&&!C||E&&C:e.previousElementSibling===w||w.previousElementSibling===e?(d.clientY-g.top)/u>.5:N>K}else r||(J=F!==w&&!D||E&&D);var O=l(A,j,w,f,e,g,d,J);O!==!1&&(1!==O&&O!==-1||(J=1===O),aa=!0,setTimeout(n,30),b(p,q),w.contains(j)||(J&&!F?j.appendChild(w):e.parentNode.insertBefore(w,J?F:e)),x=w.parentNode,this._animate(f,w),this._animate(g,e))}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();1===a.nodeType&&(a=a.getBoundingClientRect()),i(b,"transition","none"),i(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,i(b,"transition","all "+c+"ms"),i(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){i(b,"transition",""),i(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;g(V,"touchmove",this._onTouchMove),g(V,"pointermove",this._onTouchMove),g(a,"mouseup",this._onDrop),g(a,"touchend",this._onDrop),g(a,"pointerup",this._onDrop),g(a,"touchcancel",this._onDrop),g(a,"pointercancel",this._onDrop),g(a,"selectstart",this)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(Q.pid),clearTimeout(this._dragStartTimer),g(V,"mousemove",this._onTouchMove),this.nativeDraggable&&(g(V,"drop",this),g(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(P&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),y&&y.parentNode&&y.parentNode.removeChild(y),A!==x&&"clone"===a.active.lastPullMode||z&&z.parentNode&&z.parentNode.removeChild(z),w&&(this.nativeDraggable&&g(w,"dragend",this),m(w),w.style["will-change"]="",h(w,this.options.ghostClass,!1),h(w,this.options.chosenClass,!1),k(this,A,"unchoose",w,A,J),A!==x?(K=q(w,d.draggable),K>=0&&(k(null,x,"add",w,A,J,K),k(this,A,"remove",w,A,J,K),k(null,x,"sort",w,A,J,K),k(this,A,"sort",w,A,J,K))):w.nextSibling!==B&&(K=q(w,d.draggable),K>=0&&(k(this,A,"update",w,A,J,K),k(this,A,"sort",w,A,J,K))),a.active&&(null!=K&&K!==-1||(K=J),k(this,A,"end",w,A,J,K),this.save()))),this._nulling()},_nulling:function(){A=w=x=y=B=z=C=D=E=N=O=P=K=G=H=M=L=a.active=null,da.forEach(function(a){a.checked=!0}),da.length=0},handleEvent:function(a){switch(a.type){case"drop":case"dragend":this._onDrop(a);break;case"dragover":case"dragenter":w&&(this._onDragOver(a),e(a));break;case"selectstart":a.preventDefault()}},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;e<f;e++)a=d[e],c(a,g.draggable,this.el)&&b.push(a.getAttribute(g.dataIdAttr)||p(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:(c[a]=b,void("group"===a&&ga(c)))},destroy:function(){var a=this.el;a[T]=null,g(a,"mousedown",this._onTapStart),g(a,"touchstart",this._onTapStart),g(a,"pointerdown",this._onTapStart),this.nativeDraggable&&(g(a,"dragover",this),g(a,"dragenter",this)),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),ea.splice(ea.indexOf(this._onDragOver),1),this._onDrop(),this.el=a=null}},f(V,"touchmove",function(b){a.active&&b.preventDefault()});try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:function(){Z={capture:!1,passive:!1}}}))}catch(a){}return a.utils={on:f,off:g,css:i,find:j,is:function(a,b){return!!c(a,b,a)},extend:t,throttle:s,closest:c,toggleClass:h,clone:u,index:q},a.create=function(b,c){return new a(b,c)},a.version="1.6.1",a});
@@ -0,0 +1,5 @@
1
+ en:
2
+ simple_form_nested_fields:
3
+ links:
4
+ add: 'Add %{model_name}'
5
+ remove: 'Remove'
@@ -0,0 +1,17 @@
1
+ require 'simple_form'
2
+
3
+ require 'rails'
4
+
5
+ require 'simple_form_nested_fields/version'
6
+
7
+ require 'simple_form_nested_fields/action_view_extension'
8
+ require 'simple_form_nested_fields/nested_fields_builder'
9
+ require 'simple_form_nested_fields/railtie' if defined?(Rails)
10
+
11
+ I18n.load_path += Dir.glob(File.join(File.dirname(__FILE__), 'config', 'locales', '*.yml'))
12
+
13
+ module SimpleFormNestedFields
14
+ def self.asset_path
15
+ File.expand_path('assets/javascripts', __dir__)
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleFormNestedFields
2
+ module ActionViewExtension
3
+ module Builder
4
+ def nested_fields_for(record_name, record_object = nil, options = {}, &block)
5
+ SimpleFormNestedFields::NestedFieldsBuilder.new(self, @template, record_name, record_object, options).nested_fields_for(&block)
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ module ActionView::Helpers
12
+ class FormBuilder
13
+ include SimpleFormNestedFields::ActionViewExtension::Builder
14
+ end
15
+ end
@@ -0,0 +1,120 @@
1
+ module SimpleFormNestedFields
2
+ class NestedFieldsBuilder
3
+ extend Forwardable
4
+
5
+ BASE_DOM_CLASS = 'simple_form_nested_fields'.freeze
6
+ CHILD_INDEX_STRING = '__INDEX_PLACEHOLDER__'.freeze
7
+
8
+ attr_accessor :builder, :template, :record_name, :record_object, :options
9
+
10
+ def initialize(builder, template, record_name, record_object, options = {})
11
+ @builder = builder
12
+ @template = template
13
+ @record_name = record_name
14
+ @record_object = record_object
15
+ @options = options
16
+ end
17
+
18
+ def_delegators :builder, :object, :object_name, :simple_fields_for
19
+ def_delegators :template, :concat, :content_tag, :hidden_field_tag, :link_to, :render
20
+
21
+ def nested_fields_for
22
+ dom_class = [bem_class, bem_class(m: record_name)]
23
+ dom_class << bem_class(m: :sortable) if is_sortable?
24
+
25
+ content_tag(:div, class: dom_class) do
26
+ concat nested_fields_title
27
+ concat nested_fields_items
28
+ concat nested_fields_links
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def is_sortable?
35
+ options[:sortable] == true
36
+ end
37
+
38
+ def partial_path
39
+ options.fetch(:partial, File.join(object.model_name.collection, relation.klass.model_name.collection, 'fields'))
40
+ end
41
+
42
+ def relation
43
+ object.reflect_on_association(record_name)
44
+ end
45
+
46
+ def nested_fields_title
47
+ dom_class = bem_class(e: :title)
48
+ title = relation.klass.model_name.human.pluralize
49
+ content_tag(:div, title, class: dom_class).html_safe
50
+ end
51
+
52
+ def nested_fields_items
53
+ content_tag(:div, class: bem_class(e: :items)) do
54
+ simple_fields_for(record_name, record_object, options) do |fields|
55
+ dom_class = bem_class(e: :item, m: relation.klass)
56
+ dom_data = { id: fields.object.id.to_s }
57
+
58
+ content_tag(:div, class: dom_class, data: dom_data) do
59
+ concat nested_fields_item_handle
60
+ concat render(partial_path, fields: fields)
61
+ concat link_to_remove(fields)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ def nested_fields_links
68
+ dom_class = bem_class(e: :links)
69
+ content_tag(:div, link_to_add, class: dom_class).html_safe
70
+ end
71
+
72
+ def link_to_add
73
+ label = options.fetch(:label_add, ::I18n.t(:add, scope: %i[simple_form_nested_fields links], model_name: relation.klass.model_name.human))
74
+ dom_class = [bem_class(e: :link), bem_class(e: :link, m: :add)]
75
+ dom_data = { template: CGI.escapeHTML(nested_fields_template).html_safe, turbolinks: 'false' }
76
+ link_to(label, '#', class: dom_class, data: dom_data).html_safe
77
+ end
78
+
79
+ def nested_fields_item_handle
80
+ return unless is_sortable?
81
+ dom_class = bem_class(e: :item_handle)
82
+ content_tag(:div, nil, class: dom_class).html_safe
83
+ end
84
+
85
+ def nested_fields_template
86
+ dom_class = bem_class(e: :item, m: relation.klass)
87
+ content_tag :div, nested_fields_template_string, class: dom_class
88
+ end
89
+
90
+ def nested_fields_template_string
91
+ simple_fields_for(record_name, relation.klass.new, child_index: CHILD_INDEX_STRING) do |fields|
92
+ nested_fields_item_handle.to_s.html_safe +
93
+ render(partial_path, fields: fields).html_safe +
94
+ link_to_remove(fields)
95
+ end.html_safe
96
+ end
97
+
98
+ def destroy_field_tag(fields)
99
+ return if fields.object.new_record?
100
+ hidden_field_tag("#{fields.object_name}[_destroy]", fields.object._destroy).html_safe
101
+ end
102
+
103
+ def link_to_remove(fields, options = {})
104
+ label = options.fetch(:label, ::I18n.t(:remove, scope: %i[simple_form_nested_fields links]))
105
+ dom_class = [bem_class(e: :link), bem_class(e: :link, m: :remove)]
106
+ dom_data = { turbolinks: 'false' }
107
+ [
108
+ destroy_field_tag(fields),
109
+ link_to(label, '#', class: dom_class, data: dom_data)
110
+ ].reject(&:blank?).join.html_safe
111
+ end
112
+
113
+ def bem_class(e: nil, m: nil)
114
+ res = [BASE_DOM_CLASS]
115
+ res << "__#{e}" if e.present?
116
+ res << "__#{m}" if m.present?
117
+ res.join
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails'
2
+
3
+ module SimpleFormNestedFields
4
+ class Railtie < Rails::Railtie
5
+ initializer 'simple_form_dependent_fields.assets' do |app|
6
+ app.config.assets.paths << SimpleFormNestedFields.asset_path
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleFormNestedFields
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "simple_form_nested_fields",
3
+ "version": "0.1.0",
4
+ "description": "…",
5
+ "main": "package/dist/index.js",
6
+ "repository": "https://github.com/tomasc/simple_form_nested_fields.git",
7
+ "author": "Tomáš Celizna <tomas.celizna@gmail.com>",
8
+ "license": "MIT",
9
+ "files": [
10
+ "package"
11
+ ],
12
+ "scripts": {
13
+ "build": "webpack"
14
+ },
15
+ "devDependencies": {
16
+ "babel-core": "^6.26.0",
17
+ "babel-loader": "^7.1.2",
18
+ "babel-preset-env": "^1.6.0",
19
+ "babel-preset-es2015": "^6.24.1",
20
+ "coffee-loader": "^0.9.0",
21
+ "coffeescript": "^2.0.2",
22
+ "css-loader": "^0.28.11",
23
+ "extract-text-webpack-plugin": "^3.0.2",
24
+ "jquery": "^3.2.1",
25
+ "jquery-bridget": "^2.0.1",
26
+ "jquery-ujs": "^1.2.2",
27
+ "node-sass": "^4.8.3",
28
+ "sass-loader": "^6.0.7",
29
+ "style-loader": "^0.20.3",
30
+ "webpack": "^3.8.1",
31
+ "webpack-dev-server": "2.11.2",
32
+ "webpack-merge": "^4.1.0"
33
+ },
34
+ "dependencies": {
35
+ "sortablejs": "^1.7.0"
36
+ },
37
+ "peerDependencies": {
38
+ "jquery": "^3.2.1"
39
+ }
40
+ }
@@ -0,0 +1,1924 @@
1
+ (function webpackUniversalModuleDefinition(root, factory) {
2
+ if(typeof exports === 'object' && typeof module === 'object')
3
+ module.exports = factory(require("jquery"));
4
+ else if(typeof define === 'function' && define.amd)
5
+ define("@tomasc/simple_form_nested_fields", ["jquery"], factory);
6
+ else if(typeof exports === 'object')
7
+ exports["@tomasc/simple_form_nested_fields"] = factory(require("jquery"));
8
+ else
9
+ root["@tomasc/simple_form_nested_fields"] = factory(root["jquery"]);
10
+ })(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__) {
11
+ return /******/ (function(modules) { // webpackBootstrap
12
+ /******/ // The module cache
13
+ /******/ var installedModules = {};
14
+ /******/
15
+ /******/ // The require function
16
+ /******/ function __webpack_require__(moduleId) {
17
+ /******/
18
+ /******/ // Check if module is in cache
19
+ /******/ if(installedModules[moduleId]) {
20
+ /******/ return installedModules[moduleId].exports;
21
+ /******/ }
22
+ /******/ // Create a new module (and put it into the cache)
23
+ /******/ var module = installedModules[moduleId] = {
24
+ /******/ i: moduleId,
25
+ /******/ l: false,
26
+ /******/ exports: {}
27
+ /******/ };
28
+ /******/
29
+ /******/ // Execute the module function
30
+ /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31
+ /******/
32
+ /******/ // Flag the module as loaded
33
+ /******/ module.l = true;
34
+ /******/
35
+ /******/ // Return the exports of the module
36
+ /******/ return module.exports;
37
+ /******/ }
38
+ /******/
39
+ /******/
40
+ /******/ // expose the modules object (__webpack_modules__)
41
+ /******/ __webpack_require__.m = modules;
42
+ /******/
43
+ /******/ // expose the module cache
44
+ /******/ __webpack_require__.c = installedModules;
45
+ /******/
46
+ /******/ // define getter function for harmony exports
47
+ /******/ __webpack_require__.d = function(exports, name, getter) {
48
+ /******/ if(!__webpack_require__.o(exports, name)) {
49
+ /******/ Object.defineProperty(exports, name, {
50
+ /******/ configurable: false,
51
+ /******/ enumerable: true,
52
+ /******/ get: getter
53
+ /******/ });
54
+ /******/ }
55
+ /******/ };
56
+ /******/
57
+ /******/ // getDefaultExport function for compatibility with non-harmony modules
58
+ /******/ __webpack_require__.n = function(module) {
59
+ /******/ var getter = module && module.__esModule ?
60
+ /******/ function getDefault() { return module['default']; } :
61
+ /******/ function getModuleExports() { return module; };
62
+ /******/ __webpack_require__.d(getter, 'a', getter);
63
+ /******/ return getter;
64
+ /******/ };
65
+ /******/
66
+ /******/ // Object.prototype.hasOwnProperty.call
67
+ /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
68
+ /******/
69
+ /******/ // __webpack_public_path__
70
+ /******/ __webpack_require__.p = "";
71
+ /******/
72
+ /******/ // Load entry module and return exports
73
+ /******/ return __webpack_require__(__webpack_require__.s = 1);
74
+ /******/ })
75
+ /************************************************************************/
76
+ /******/ ([
77
+ /* 0 */
78
+ /***/ (function(module, exports) {
79
+
80
+ module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
81
+
82
+ /***/ }),
83
+ /* 1 */
84
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
85
+
86
+ "use strict";
87
+ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
88
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__links__ = __webpack_require__(2);
89
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__links___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__links__);
90
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__sortable__ = __webpack_require__(3);
91
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__sortable___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__sortable__);
92
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__simple_form_nested_fields__ = __webpack_require__(5);
93
+ /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__simple_form_nested_fields___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__simple_form_nested_fields__);
94
+
95
+
96
+
97
+
98
+
99
+ /***/ }),
100
+ /* 2 */
101
+ /***/ (function(module, exports, __webpack_require__) {
102
+
103
+ "use strict";
104
+ /* WEBPACK VAR INJECTION */(function(jQuery) {
105
+
106
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
107
+
108
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
109
+
110
+ (function ($, window, document) {
111
+ var Plugin, defaults, pluginName;
112
+ pluginName = 'SimpleFormNestedFields__Links';
113
+ defaults = {
114
+ debug: false,
115
+ new_item_class_name: 'simple_form_nested_fields__item__new',
116
+ regexp: new RegExp("__INDEX_PLACEHOLDER__", 'g') // regexp: new RegExp("<%= Modulor::NestedFieldsBuilder::CHILD_INDEX_STRING %>", 'g')
117
+ };
118
+ Plugin = function () {
119
+ function Plugin(element, options) {
120
+ _classCallCheck(this, Plugin);
121
+
122
+ this.element = element;
123
+ this.options = $.extend({}, defaults, options);
124
+ this._defaults = defaults;
125
+ this.$element = $(this.element);
126
+ this.init();
127
+ }
128
+
129
+ _createClass(Plugin, [{
130
+ key: 'init',
131
+ value: function init() {
132
+ var _this = this;
133
+
134
+ return this.$element.on('click.' + this._name, '.simple_form_nested_fields__link', function (e) {
135
+ var link;
136
+ e.preventDefault();
137
+ link = e.target;
138
+ switch (false) {
139
+ case !link.classList.contains('simple_form_nested_fields__link__add'):
140
+ return _this.add_new_item(link);
141
+ case !link.classList.contains('simple_form_nested_fields__link__remove'):
142
+ return _this.remove_item(link);
143
+ }
144
+ });
145
+ }
146
+ }, {
147
+ key: 'destroy',
148
+ value: function destroy() {
149
+ return this.$element.off('click.' + this._name, '.simple_form_nested_fields__link__add');
150
+ }
151
+ }, {
152
+ key: 'get_index',
153
+ value: function get_index() {
154
+ return new Date().getTime();
155
+ }
156
+ }, {
157
+ key: 'get_template',
158
+ value: function get_template(link) {
159
+ return $(link).data('template').replace(this.options.regexp, this.get_index());
160
+ }
161
+ }, {
162
+ key: 'get_items_container',
163
+ value: function get_items_container() {
164
+ return this.$element.find('.simple_form_nested_fields__items');
165
+ }
166
+ }, {
167
+ key: 'add_new_item',
168
+ value: function add_new_item(link) {
169
+ var $template;
170
+ $template = $(this.get_template(link));
171
+ $template.addClass(this.options.new_item_class_name);
172
+ return this.get_items_container().append($template);
173
+ }
174
+ }, {
175
+ key: 'remove_item',
176
+ value: function remove_item(link) {
177
+ var $item;
178
+ $item = $(link).closest('.simple_form_nested_fields__item');
179
+ if ($item.hasClass(this.options.new_item_class_name)) {
180
+ return $item.remove();
181
+ } else {
182
+ $item.find('input[type=hidden]').val('1');
183
+ return $item.hide();
184
+ }
185
+ }
186
+ }]);
187
+
188
+ return Plugin;
189
+ }();
190
+ // A really lightweight plugin wrapper around the constructor,
191
+ // preventing against multiple instantiations
192
+ return $.fn[pluginName] = function (options) {
193
+ return this.each(function () {
194
+ if (!$.data(this, 'plugin_' + pluginName)) {
195
+ return $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
196
+ }
197
+ });
198
+ };
199
+ })(jQuery, window, document);
200
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)))
201
+
202
+ /***/ }),
203
+ /* 3 */
204
+ /***/ (function(module, exports, __webpack_require__) {
205
+
206
+ "use strict";
207
+ /* WEBPACK VAR INJECTION */(function(jQuery) {
208
+
209
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
210
+
211
+ var _sortablejs = __webpack_require__(4);
212
+
213
+ var _sortablejs2 = _interopRequireDefault(_sortablejs);
214
+
215
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
216
+
217
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
218
+
219
+ (function ($, window, document) {
220
+ var Plugin, defaults, pluginName;
221
+ pluginName = 'SimpleFormNestedFields__Sortable';
222
+ defaults = {
223
+ debug: false
224
+ };
225
+ Plugin = function () {
226
+ function Plugin(element, options) {
227
+ _classCallCheck(this, Plugin);
228
+
229
+ this.element = element;
230
+ this.$element = $(this.element);
231
+ this.$simple_form_nested_fields = this.$element.data('plugin_SimpleFormNestedFields');
232
+ this.options = $.extend({}, defaults, options);
233
+ this._defaults = defaults;
234
+ this._name = pluginName;
235
+ this.init();
236
+ }
237
+
238
+ _createClass(Plugin, [{
239
+ key: 'init',
240
+ value: function init() {
241
+ var _this = this;
242
+
243
+ if (this.sortable) {
244
+ return;
245
+ }
246
+ this.sortable = new _sortablejs2.default(this.get_items_container()[0], {
247
+ animation: 150,
248
+ draggable: '.simple_form_nested_fields__item',
249
+ ghostClass: '.simple_form_nested_fields__ghost',
250
+ handle: '.simple_form_nested_fields__item_handle',
251
+ // TODO: onAdd is not being triggered?
252
+ onAdd: function onAdd(e) {
253
+ return _this.update_item_positions();
254
+ },
255
+ onUpdate: function onUpdate(e) {
256
+ return _this.update_item_positions();
257
+ },
258
+ onRemove: function onRemove(e) {
259
+ return _this.update_item_positions();
260
+ }
261
+ });
262
+ this.$element.on('update_item_positions.' + this._name, function (e) {
263
+ e.stopPropagation();
264
+ return _this.update_item_positions();
265
+ });
266
+ return this.update_item_positions();
267
+ }
268
+ }, {
269
+ key: 'destroy',
270
+ value: function destroy() {
271
+ if (this.sortable) {
272
+ return this.sortable.destroy();
273
+ }
274
+ }
275
+ }, {
276
+ key: 'update_item_positions',
277
+ value: function update_item_positions() {
278
+ return this.get_items().each(function (i, el) {
279
+ return $(el).find('input[name*="position"]').val(i + 1);
280
+ });
281
+ }
282
+ }, {
283
+ key: 'get_items',
284
+ value: function get_items() {
285
+ return this.get_items_container().find('.simple_form_nested_fields__item');
286
+ }
287
+ }, {
288
+ key: 'get_items_container',
289
+ value: function get_items_container() {
290
+ return this.$element.find('.simple_form_nested_fields__items');
291
+ }
292
+ }]);
293
+
294
+ return Plugin;
295
+ }();
296
+ // A really lightweight plugin wrapper around the constructor,
297
+ // preventing against multiple instantiations
298
+ return $.fn[pluginName] = function (options) {
299
+ return this.each(function () {
300
+ if (!$.data(this, 'plugin_' + pluginName)) {
301
+ return $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
302
+ }
303
+ });
304
+ };
305
+ })(jQuery, window, document);
306
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)))
307
+
308
+ /***/ }),
309
+ /* 4 */
310
+ /***/ (function(module, exports, __webpack_require__) {
311
+
312
+ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/**!
313
+ * Sortable
314
+ * @author RubaXa <trash@rubaxa.org>
315
+ * @license MIT
316
+ */
317
+
318
+ (function sortableModule(factory) {
319
+ "use strict";
320
+
321
+ if (true) {
322
+ !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
323
+ __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
324
+ (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
325
+ __WEBPACK_AMD_DEFINE_FACTORY__),
326
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
327
+ }
328
+ else if (typeof module != "undefined" && typeof module.exports != "undefined") {
329
+ module.exports = factory();
330
+ }
331
+ else {
332
+ /* jshint sub:true */
333
+ window["Sortable"] = factory();
334
+ }
335
+ })(function sortableFactory() {
336
+ "use strict";
337
+
338
+ if (typeof window === "undefined" || !window.document) {
339
+ return function sortableError() {
340
+ throw new Error("Sortable.js requires a window with a document");
341
+ };
342
+ }
343
+
344
+ var dragEl,
345
+ parentEl,
346
+ ghostEl,
347
+ cloneEl,
348
+ rootEl,
349
+ nextEl,
350
+ lastDownEl,
351
+
352
+ scrollEl,
353
+ scrollParentEl,
354
+ scrollCustomFn,
355
+
356
+ lastEl,
357
+ lastCSS,
358
+ lastParentCSS,
359
+
360
+ oldIndex,
361
+ newIndex,
362
+
363
+ activeGroup,
364
+ putSortable,
365
+
366
+ autoScroll = {},
367
+
368
+ tapEvt,
369
+ touchEvt,
370
+
371
+ moved,
372
+
373
+ /** @const */
374
+ R_SPACE = /\s+/g,
375
+ R_FLOAT = /left|right|inline/,
376
+
377
+ expando = 'Sortable' + (new Date).getTime(),
378
+
379
+ win = window,
380
+ document = win.document,
381
+ parseInt = win.parseInt,
382
+ setTimeout = win.setTimeout,
383
+
384
+ $ = win.jQuery || win.Zepto,
385
+ Polymer = win.Polymer,
386
+
387
+ captureMode = false,
388
+ passiveMode = false,
389
+
390
+ supportDraggable = ('draggable' in document.createElement('div')),
391
+ supportCssPointerEvents = (function (el) {
392
+ // false when IE11
393
+ if (!!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)) {
394
+ return false;
395
+ }
396
+ el = document.createElement('x');
397
+ el.style.cssText = 'pointer-events:auto';
398
+ return el.style.pointerEvents === 'auto';
399
+ })(),
400
+
401
+ _silent = false,
402
+
403
+ abs = Math.abs,
404
+ min = Math.min,
405
+
406
+ savedInputChecked = [],
407
+ touchDragOverListeners = [],
408
+
409
+ _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
410
+ // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
411
+ if (rootEl && options.scroll) {
412
+ var _this = rootEl[expando],
413
+ el,
414
+ rect,
415
+ sens = options.scrollSensitivity,
416
+ speed = options.scrollSpeed,
417
+
418
+ x = evt.clientX,
419
+ y = evt.clientY,
420
+
421
+ winWidth = window.innerWidth,
422
+ winHeight = window.innerHeight,
423
+
424
+ vx,
425
+ vy,
426
+
427
+ scrollOffsetX,
428
+ scrollOffsetY
429
+ ;
430
+
431
+ // Delect scrollEl
432
+ if (scrollParentEl !== rootEl) {
433
+ scrollEl = options.scroll;
434
+ scrollParentEl = rootEl;
435
+ scrollCustomFn = options.scrollFn;
436
+
437
+ if (scrollEl === true) {
438
+ scrollEl = rootEl;
439
+
440
+ do {
441
+ if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
442
+ (scrollEl.offsetHeight < scrollEl.scrollHeight)
443
+ ) {
444
+ break;
445
+ }
446
+ /* jshint boss:true */
447
+ } while (scrollEl = scrollEl.parentNode);
448
+ }
449
+ }
450
+
451
+ if (scrollEl) {
452
+ el = scrollEl;
453
+ rect = scrollEl.getBoundingClientRect();
454
+ vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
455
+ vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
456
+ }
457
+
458
+
459
+ if (!(vx || vy)) {
460
+ vx = (winWidth - x <= sens) - (x <= sens);
461
+ vy = (winHeight - y <= sens) - (y <= sens);
462
+
463
+ /* jshint expr:true */
464
+ (vx || vy) && (el = win);
465
+ }
466
+
467
+
468
+ if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
469
+ autoScroll.el = el;
470
+ autoScroll.vx = vx;
471
+ autoScroll.vy = vy;
472
+
473
+ clearInterval(autoScroll.pid);
474
+
475
+ if (el) {
476
+ autoScroll.pid = setInterval(function () {
477
+ scrollOffsetY = vy ? vy * speed : 0;
478
+ scrollOffsetX = vx ? vx * speed : 0;
479
+
480
+ if ('function' === typeof(scrollCustomFn)) {
481
+ return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt);
482
+ }
483
+
484
+ if (el === win) {
485
+ win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
486
+ } else {
487
+ el.scrollTop += scrollOffsetY;
488
+ el.scrollLeft += scrollOffsetX;
489
+ }
490
+ }, 24);
491
+ }
492
+ }
493
+ }
494
+ }, 30),
495
+
496
+ _prepareGroup = function (options) {
497
+ function toFn(value, pull) {
498
+ if (value === void 0 || value === true) {
499
+ value = group.name;
500
+ }
501
+
502
+ if (typeof value === 'function') {
503
+ return value;
504
+ } else {
505
+ return function (to, from) {
506
+ var fromGroup = from.options.group.name;
507
+
508
+ return pull
509
+ ? value
510
+ : value && (value.join
511
+ ? value.indexOf(fromGroup) > -1
512
+ : (fromGroup == value)
513
+ );
514
+ };
515
+ }
516
+ }
517
+
518
+ var group = {};
519
+ var originalGroup = options.group;
520
+
521
+ if (!originalGroup || typeof originalGroup != 'object') {
522
+ originalGroup = {name: originalGroup};
523
+ }
524
+
525
+ group.name = originalGroup.name;
526
+ group.checkPull = toFn(originalGroup.pull, true);
527
+ group.checkPut = toFn(originalGroup.put);
528
+ group.revertClone = originalGroup.revertClone;
529
+
530
+ options.group = group;
531
+ }
532
+ ;
533
+
534
+ // Detect support a passive mode
535
+ try {
536
+ window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
537
+ get: function () {
538
+ // `false`, because everything starts to work incorrectly and instead of d'n'd,
539
+ // begins the page has scrolled.
540
+ passiveMode = false;
541
+ captureMode = {
542
+ capture: false,
543
+ passive: passiveMode
544
+ };
545
+ }
546
+ }));
547
+ } catch (err) {}
548
+
549
+ /**
550
+ * @class Sortable
551
+ * @param {HTMLElement} el
552
+ * @param {Object} [options]
553
+ */
554
+ function Sortable(el, options) {
555
+ if (!(el && el.nodeType && el.nodeType === 1)) {
556
+ throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
557
+ }
558
+
559
+ this.el = el; // root element
560
+ this.options = options = _extend({}, options);
561
+
562
+
563
+ // Export instance
564
+ el[expando] = this;
565
+
566
+ // Default options
567
+ var defaults = {
568
+ group: Math.random(),
569
+ sort: true,
570
+ disabled: false,
571
+ store: null,
572
+ handle: null,
573
+ scroll: true,
574
+ scrollSensitivity: 30,
575
+ scrollSpeed: 10,
576
+ draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
577
+ ghostClass: 'sortable-ghost',
578
+ chosenClass: 'sortable-chosen',
579
+ dragClass: 'sortable-drag',
580
+ ignore: 'a, img',
581
+ filter: null,
582
+ preventOnFilter: true,
583
+ animation: 0,
584
+ setData: function (dataTransfer, dragEl) {
585
+ dataTransfer.setData('Text', dragEl.textContent);
586
+ },
587
+ dropBubble: false,
588
+ dragoverBubble: false,
589
+ dataIdAttr: 'data-id',
590
+ delay: 0,
591
+ forceFallback: false,
592
+ fallbackClass: 'sortable-fallback',
593
+ fallbackOnBody: false,
594
+ fallbackTolerance: 0,
595
+ fallbackOffset: {x: 0, y: 0},
596
+ supportPointer: Sortable.supportPointer !== false
597
+ };
598
+
599
+
600
+ // Set default options
601
+ for (var name in defaults) {
602
+ !(name in options) && (options[name] = defaults[name]);
603
+ }
604
+
605
+ _prepareGroup(options);
606
+
607
+ // Bind all private methods
608
+ for (var fn in this) {
609
+ if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
610
+ this[fn] = this[fn].bind(this);
611
+ }
612
+ }
613
+
614
+ // Setup drag mode
615
+ this.nativeDraggable = options.forceFallback ? false : supportDraggable;
616
+
617
+ // Bind events
618
+ _on(el, 'mousedown', this._onTapStart);
619
+ _on(el, 'touchstart', this._onTapStart);
620
+ options.supportPointer && _on(el, 'pointerdown', this._onTapStart);
621
+
622
+ if (this.nativeDraggable) {
623
+ _on(el, 'dragover', this);
624
+ _on(el, 'dragenter', this);
625
+ }
626
+
627
+ touchDragOverListeners.push(this._onDragOver);
628
+
629
+ // Restore sorting
630
+ options.store && this.sort(options.store.get(this));
631
+ }
632
+
633
+
634
+ Sortable.prototype = /** @lends Sortable.prototype */ {
635
+ constructor: Sortable,
636
+
637
+ _onTapStart: function (/** Event|TouchEvent */evt) {
638
+ var _this = this,
639
+ el = this.el,
640
+ options = this.options,
641
+ preventOnFilter = options.preventOnFilter,
642
+ type = evt.type,
643
+ touch = evt.touches && evt.touches[0],
644
+ target = (touch || evt).target,
645
+ originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0]) || target,
646
+ filter = options.filter,
647
+ startIndex;
648
+
649
+ _saveInputCheckedState(el);
650
+
651
+
652
+ // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
653
+ if (dragEl) {
654
+ return;
655
+ }
656
+
657
+ if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
658
+ return; // only left button or enabled
659
+ }
660
+
661
+ // cancel dnd if original target is content editable
662
+ if (originalTarget.isContentEditable) {
663
+ return;
664
+ }
665
+
666
+ target = _closest(target, options.draggable, el);
667
+
668
+ if (!target) {
669
+ return;
670
+ }
671
+
672
+ if (lastDownEl === target) {
673
+ // Ignoring duplicate `down`
674
+ return;
675
+ }
676
+
677
+ // Get the index of the dragged element within its parent
678
+ startIndex = _index(target, options.draggable);
679
+
680
+ // Check filter
681
+ if (typeof filter === 'function') {
682
+ if (filter.call(this, evt, target, this)) {
683
+ _dispatchEvent(_this, originalTarget, 'filter', target, el, el, startIndex);
684
+ preventOnFilter && evt.preventDefault();
685
+ return; // cancel dnd
686
+ }
687
+ }
688
+ else if (filter) {
689
+ filter = filter.split(',').some(function (criteria) {
690
+ criteria = _closest(originalTarget, criteria.trim(), el);
691
+
692
+ if (criteria) {
693
+ _dispatchEvent(_this, criteria, 'filter', target, el, el, startIndex);
694
+ return true;
695
+ }
696
+ });
697
+
698
+ if (filter) {
699
+ preventOnFilter && evt.preventDefault();
700
+ return; // cancel dnd
701
+ }
702
+ }
703
+
704
+ if (options.handle && !_closest(originalTarget, options.handle, el)) {
705
+ return;
706
+ }
707
+
708
+ // Prepare `dragstart`
709
+ this._prepareDragStart(evt, touch, target, startIndex);
710
+ },
711
+
712
+ _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex) {
713
+ var _this = this,
714
+ el = _this.el,
715
+ options = _this.options,
716
+ ownerDocument = el.ownerDocument,
717
+ dragStartFn;
718
+
719
+ if (target && !dragEl && (target.parentNode === el)) {
720
+ tapEvt = evt;
721
+
722
+ rootEl = el;
723
+ dragEl = target;
724
+ parentEl = dragEl.parentNode;
725
+ nextEl = dragEl.nextSibling;
726
+ lastDownEl = target;
727
+ activeGroup = options.group;
728
+ oldIndex = startIndex;
729
+
730
+ this._lastX = (touch || evt).clientX;
731
+ this._lastY = (touch || evt).clientY;
732
+
733
+ dragEl.style['will-change'] = 'all';
734
+
735
+ dragStartFn = function () {
736
+ // Delayed drag has been triggered
737
+ // we can re-enable the events: touchmove/mousemove
738
+ _this._disableDelayedDrag();
739
+
740
+ // Make the element draggable
741
+ dragEl.draggable = _this.nativeDraggable;
742
+
743
+ // Chosen item
744
+ _toggleClass(dragEl, options.chosenClass, true);
745
+
746
+ // Bind the events: dragstart/dragend
747
+ _this._triggerDragStart(evt, touch);
748
+
749
+ // Drag start event
750
+ _dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, rootEl, oldIndex);
751
+ };
752
+
753
+ // Disable "draggable"
754
+ options.ignore.split(',').forEach(function (criteria) {
755
+ _find(dragEl, criteria.trim(), _disableDraggable);
756
+ });
757
+
758
+ _on(ownerDocument, 'mouseup', _this._onDrop);
759
+ _on(ownerDocument, 'touchend', _this._onDrop);
760
+ _on(ownerDocument, 'touchcancel', _this._onDrop);
761
+ _on(ownerDocument, 'selectstart', _this);
762
+ options.supportPointer && _on(ownerDocument, 'pointercancel', _this._onDrop);
763
+
764
+ if (options.delay) {
765
+ // If the user moves the pointer or let go the click or touch
766
+ // before the delay has been reached:
767
+ // disable the delayed drag
768
+ _on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
769
+ _on(ownerDocument, 'touchend', _this._disableDelayedDrag);
770
+ _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
771
+ _on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
772
+ _on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
773
+ options.supportPointer && _on(ownerDocument, 'pointermove', _this._disableDelayedDrag);
774
+
775
+ _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
776
+ } else {
777
+ dragStartFn();
778
+ }
779
+
780
+
781
+ }
782
+ },
783
+
784
+ _disableDelayedDrag: function () {
785
+ var ownerDocument = this.el.ownerDocument;
786
+
787
+ clearTimeout(this._dragStartTimer);
788
+ _off(ownerDocument, 'mouseup', this._disableDelayedDrag);
789
+ _off(ownerDocument, 'touchend', this._disableDelayedDrag);
790
+ _off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
791
+ _off(ownerDocument, 'mousemove', this._disableDelayedDrag);
792
+ _off(ownerDocument, 'touchmove', this._disableDelayedDrag);
793
+ _off(ownerDocument, 'pointermove', this._disableDelayedDrag);
794
+ },
795
+
796
+ _triggerDragStart: function (/** Event */evt, /** Touch */touch) {
797
+ touch = touch || (evt.pointerType == 'touch' ? evt : null);
798
+
799
+ if (touch) {
800
+ // Touch device support
801
+ tapEvt = {
802
+ target: dragEl,
803
+ clientX: touch.clientX,
804
+ clientY: touch.clientY
805
+ };
806
+
807
+ this._onDragStart(tapEvt, 'touch');
808
+ }
809
+ else if (!this.nativeDraggable) {
810
+ this._onDragStart(tapEvt, true);
811
+ }
812
+ else {
813
+ _on(dragEl, 'dragend', this);
814
+ _on(rootEl, 'dragstart', this._onDragStart);
815
+ }
816
+
817
+ try {
818
+ if (document.selection) {
819
+ // Timeout neccessary for IE9
820
+ _nextTick(function () {
821
+ document.selection.empty();
822
+ });
823
+ } else {
824
+ window.getSelection().removeAllRanges();
825
+ }
826
+ } catch (err) {
827
+ }
828
+ },
829
+
830
+ _dragStarted: function () {
831
+ if (rootEl && dragEl) {
832
+ var options = this.options;
833
+
834
+ // Apply effect
835
+ _toggleClass(dragEl, options.ghostClass, true);
836
+ _toggleClass(dragEl, options.dragClass, false);
837
+
838
+ Sortable.active = this;
839
+
840
+ // Drag start event
841
+ _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, rootEl, oldIndex);
842
+ } else {
843
+ this._nulling();
844
+ }
845
+ },
846
+
847
+ _emulateDragOver: function () {
848
+ if (touchEvt) {
849
+ if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
850
+ return;
851
+ }
852
+
853
+ this._lastX = touchEvt.clientX;
854
+ this._lastY = touchEvt.clientY;
855
+
856
+ if (!supportCssPointerEvents) {
857
+ _css(ghostEl, 'display', 'none');
858
+ }
859
+
860
+ var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
861
+ var parent = target;
862
+ var i = touchDragOverListeners.length;
863
+
864
+ if (target && target.shadowRoot) {
865
+ target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
866
+ parent = target;
867
+ }
868
+
869
+ if (parent) {
870
+ do {
871
+ if (parent[expando]) {
872
+ while (i--) {
873
+ touchDragOverListeners[i]({
874
+ clientX: touchEvt.clientX,
875
+ clientY: touchEvt.clientY,
876
+ target: target,
877
+ rootEl: parent
878
+ });
879
+ }
880
+
881
+ break;
882
+ }
883
+
884
+ target = parent; // store last element
885
+ }
886
+ /* jshint boss:true */
887
+ while (parent = parent.parentNode);
888
+ }
889
+
890
+ if (!supportCssPointerEvents) {
891
+ _css(ghostEl, 'display', '');
892
+ }
893
+ }
894
+ },
895
+
896
+
897
+ _onTouchMove: function (/**TouchEvent*/evt) {
898
+ if (tapEvt) {
899
+ var options = this.options,
900
+ fallbackTolerance = options.fallbackTolerance,
901
+ fallbackOffset = options.fallbackOffset,
902
+ touch = evt.touches ? evt.touches[0] : evt,
903
+ dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x,
904
+ dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y,
905
+ translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
906
+
907
+ // only set the status to dragging, when we are actually dragging
908
+ if (!Sortable.active) {
909
+ if (fallbackTolerance &&
910
+ min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance
911
+ ) {
912
+ return;
913
+ }
914
+
915
+ this._dragStarted();
916
+ }
917
+
918
+ // as well as creating the ghost element on the document body
919
+ this._appendGhost();
920
+
921
+ moved = true;
922
+ touchEvt = touch;
923
+
924
+ _css(ghostEl, 'webkitTransform', translate3d);
925
+ _css(ghostEl, 'mozTransform', translate3d);
926
+ _css(ghostEl, 'msTransform', translate3d);
927
+ _css(ghostEl, 'transform', translate3d);
928
+
929
+ evt.preventDefault();
930
+ }
931
+ },
932
+
933
+ _appendGhost: function () {
934
+ if (!ghostEl) {
935
+ var rect = dragEl.getBoundingClientRect(),
936
+ css = _css(dragEl),
937
+ options = this.options,
938
+ ghostRect;
939
+
940
+ ghostEl = dragEl.cloneNode(true);
941
+
942
+ _toggleClass(ghostEl, options.ghostClass, false);
943
+ _toggleClass(ghostEl, options.fallbackClass, true);
944
+ _toggleClass(ghostEl, options.dragClass, true);
945
+
946
+ _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
947
+ _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
948
+ _css(ghostEl, 'width', rect.width);
949
+ _css(ghostEl, 'height', rect.height);
950
+ _css(ghostEl, 'opacity', '0.8');
951
+ _css(ghostEl, 'position', 'fixed');
952
+ _css(ghostEl, 'zIndex', '100000');
953
+ _css(ghostEl, 'pointerEvents', 'none');
954
+
955
+ options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
956
+
957
+ // Fixing dimensions.
958
+ ghostRect = ghostEl.getBoundingClientRect();
959
+ _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
960
+ _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
961
+ }
962
+ },
963
+
964
+ _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
965
+ var _this = this;
966
+ var dataTransfer = evt.dataTransfer;
967
+ var options = _this.options;
968
+
969
+ _this._offUpEvents();
970
+
971
+ if (activeGroup.checkPull(_this, _this, dragEl, evt)) {
972
+ cloneEl = _clone(dragEl);
973
+
974
+ cloneEl.draggable = false;
975
+ cloneEl.style['will-change'] = '';
976
+
977
+ _css(cloneEl, 'display', 'none');
978
+ _toggleClass(cloneEl, _this.options.chosenClass, false);
979
+
980
+ // #1143: IFrame support workaround
981
+ _this._cloneId = _nextTick(function () {
982
+ rootEl.insertBefore(cloneEl, dragEl);
983
+ _dispatchEvent(_this, rootEl, 'clone', dragEl);
984
+ });
985
+ }
986
+
987
+ _toggleClass(dragEl, options.dragClass, true);
988
+
989
+ if (useFallback) {
990
+ if (useFallback === 'touch') {
991
+ // Bind touch events
992
+ _on(document, 'touchmove', _this._onTouchMove);
993
+ _on(document, 'touchend', _this._onDrop);
994
+ _on(document, 'touchcancel', _this._onDrop);
995
+
996
+ if (options.supportPointer) {
997
+ _on(document, 'pointermove', _this._onTouchMove);
998
+ _on(document, 'pointerup', _this._onDrop);
999
+ }
1000
+ } else {
1001
+ // Old brwoser
1002
+ _on(document, 'mousemove', _this._onTouchMove);
1003
+ _on(document, 'mouseup', _this._onDrop);
1004
+ }
1005
+
1006
+ _this._loopId = setInterval(_this._emulateDragOver, 50);
1007
+ }
1008
+ else {
1009
+ if (dataTransfer) {
1010
+ dataTransfer.effectAllowed = 'move';
1011
+ options.setData && options.setData.call(_this, dataTransfer, dragEl);
1012
+ }
1013
+
1014
+ _on(document, 'drop', _this);
1015
+
1016
+ // #1143: Бывает элемент с IFrame внутри блокирует `drop`,
1017
+ // поэтому если вызвался `mouseover`, значит надо отменять весь d'n'd.
1018
+ // Breaking Chrome 62+
1019
+ // _on(document, 'mouseover', _this);
1020
+
1021
+ _this._dragStartId = _nextTick(_this._dragStarted);
1022
+ }
1023
+ },
1024
+
1025
+ _onDragOver: function (/**Event*/evt) {
1026
+ var el = this.el,
1027
+ target,
1028
+ dragRect,
1029
+ targetRect,
1030
+ revert,
1031
+ options = this.options,
1032
+ group = options.group,
1033
+ activeSortable = Sortable.active,
1034
+ isOwner = (activeGroup === group),
1035
+ isMovingBetweenSortable = false,
1036
+ canSort = options.sort;
1037
+
1038
+ if (evt.preventDefault !== void 0) {
1039
+ evt.preventDefault();
1040
+ !options.dragoverBubble && evt.stopPropagation();
1041
+ }
1042
+
1043
+ if (dragEl.animated) {
1044
+ return;
1045
+ }
1046
+
1047
+ moved = true;
1048
+
1049
+ if (activeSortable && !options.disabled &&
1050
+ (isOwner
1051
+ ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
1052
+ : (
1053
+ putSortable === this ||
1054
+ (
1055
+ (activeSortable.lastPullMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) &&
1056
+ group.checkPut(this, activeSortable, dragEl, evt)
1057
+ )
1058
+ )
1059
+ ) &&
1060
+ (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
1061
+ ) {
1062
+ // Smart auto-scrolling
1063
+ _autoScroll(evt, options, this.el);
1064
+
1065
+ if (_silent) {
1066
+ return;
1067
+ }
1068
+
1069
+ target = _closest(evt.target, options.draggable, el);
1070
+ dragRect = dragEl.getBoundingClientRect();
1071
+
1072
+ if (putSortable !== this) {
1073
+ putSortable = this;
1074
+ isMovingBetweenSortable = true;
1075
+ }
1076
+
1077
+ if (revert) {
1078
+ _cloneHide(activeSortable, true);
1079
+ parentEl = rootEl; // actualization
1080
+
1081
+ if (cloneEl || nextEl) {
1082
+ rootEl.insertBefore(dragEl, cloneEl || nextEl);
1083
+ }
1084
+ else if (!canSort) {
1085
+ rootEl.appendChild(dragEl);
1086
+ }
1087
+
1088
+ return;
1089
+ }
1090
+
1091
+
1092
+ if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
1093
+ (el === evt.target) && (_ghostIsLast(el, evt))
1094
+ ) {
1095
+ //assign target only if condition is true
1096
+ if (el.children.length !== 0 && el.children[0] !== ghostEl && el === evt.target) {
1097
+ target = el.lastElementChild;
1098
+ }
1099
+
1100
+ if (target) {
1101
+ if (target.animated) {
1102
+ return;
1103
+ }
1104
+
1105
+ targetRect = target.getBoundingClientRect();
1106
+ }
1107
+
1108
+ _cloneHide(activeSortable, isOwner);
1109
+
1110
+ if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) {
1111
+ if (!dragEl.contains(el)) {
1112
+ el.appendChild(dragEl);
1113
+ parentEl = el; // actualization
1114
+ }
1115
+
1116
+ this._animate(dragRect, dragEl);
1117
+ target && this._animate(targetRect, target);
1118
+ }
1119
+ }
1120
+ else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
1121
+ if (lastEl !== target) {
1122
+ lastEl = target;
1123
+ lastCSS = _css(target);
1124
+ lastParentCSS = _css(target.parentNode);
1125
+ }
1126
+
1127
+ targetRect = target.getBoundingClientRect();
1128
+
1129
+ var width = targetRect.right - targetRect.left,
1130
+ height = targetRect.bottom - targetRect.top,
1131
+ floating = R_FLOAT.test(lastCSS.cssFloat + lastCSS.display)
1132
+ || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
1133
+ isWide = (target.offsetWidth > dragEl.offsetWidth),
1134
+ isLong = (target.offsetHeight > dragEl.offsetHeight),
1135
+ halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
1136
+ nextSibling = target.nextElementSibling,
1137
+ after = false
1138
+ ;
1139
+
1140
+ if (floating) {
1141
+ var elTop = dragEl.offsetTop,
1142
+ tgTop = target.offsetTop;
1143
+
1144
+ if (elTop === tgTop) {
1145
+ after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
1146
+ }
1147
+ else if (target.previousElementSibling === dragEl || dragEl.previousElementSibling === target) {
1148
+ after = (evt.clientY - targetRect.top) / height > 0.5;
1149
+ } else {
1150
+ after = tgTop > elTop;
1151
+ }
1152
+ } else if (!isMovingBetweenSortable) {
1153
+ after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
1154
+ }
1155
+
1156
+ var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
1157
+
1158
+ if (moveVector !== false) {
1159
+ if (moveVector === 1 || moveVector === -1) {
1160
+ after = (moveVector === 1);
1161
+ }
1162
+
1163
+ _silent = true;
1164
+ setTimeout(_unsilent, 30);
1165
+
1166
+ _cloneHide(activeSortable, isOwner);
1167
+
1168
+ if (!dragEl.contains(el)) {
1169
+ if (after && !nextSibling) {
1170
+ el.appendChild(dragEl);
1171
+ } else {
1172
+ target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
1173
+ }
1174
+ }
1175
+
1176
+ parentEl = dragEl.parentNode; // actualization
1177
+
1178
+ this._animate(dragRect, dragEl);
1179
+ this._animate(targetRect, target);
1180
+ }
1181
+ }
1182
+ }
1183
+ },
1184
+
1185
+ _animate: function (prevRect, target) {
1186
+ var ms = this.options.animation;
1187
+
1188
+ if (ms) {
1189
+ var currentRect = target.getBoundingClientRect();
1190
+
1191
+ if (prevRect.nodeType === 1) {
1192
+ prevRect = prevRect.getBoundingClientRect();
1193
+ }
1194
+
1195
+ _css(target, 'transition', 'none');
1196
+ _css(target, 'transform', 'translate3d('
1197
+ + (prevRect.left - currentRect.left) + 'px,'
1198
+ + (prevRect.top - currentRect.top) + 'px,0)'
1199
+ );
1200
+
1201
+ target.offsetWidth; // repaint
1202
+
1203
+ _css(target, 'transition', 'all ' + ms + 'ms');
1204
+ _css(target, 'transform', 'translate3d(0,0,0)');
1205
+
1206
+ clearTimeout(target.animated);
1207
+ target.animated = setTimeout(function () {
1208
+ _css(target, 'transition', '');
1209
+ _css(target, 'transform', '');
1210
+ target.animated = false;
1211
+ }, ms);
1212
+ }
1213
+ },
1214
+
1215
+ _offUpEvents: function () {
1216
+ var ownerDocument = this.el.ownerDocument;
1217
+
1218
+ _off(document, 'touchmove', this._onTouchMove);
1219
+ _off(document, 'pointermove', this._onTouchMove);
1220
+ _off(ownerDocument, 'mouseup', this._onDrop);
1221
+ _off(ownerDocument, 'touchend', this._onDrop);
1222
+ _off(ownerDocument, 'pointerup', this._onDrop);
1223
+ _off(ownerDocument, 'touchcancel', this._onDrop);
1224
+ _off(ownerDocument, 'pointercancel', this._onDrop);
1225
+ _off(ownerDocument, 'selectstart', this);
1226
+ },
1227
+
1228
+ _onDrop: function (/**Event*/evt) {
1229
+ var el = this.el,
1230
+ options = this.options;
1231
+
1232
+ clearInterval(this._loopId);
1233
+ clearInterval(autoScroll.pid);
1234
+ clearTimeout(this._dragStartTimer);
1235
+
1236
+ _cancelNextTick(this._cloneId);
1237
+ _cancelNextTick(this._dragStartId);
1238
+
1239
+ // Unbind events
1240
+ _off(document, 'mouseover', this);
1241
+ _off(document, 'mousemove', this._onTouchMove);
1242
+
1243
+ if (this.nativeDraggable) {
1244
+ _off(document, 'drop', this);
1245
+ _off(el, 'dragstart', this._onDragStart);
1246
+ }
1247
+
1248
+ this._offUpEvents();
1249
+
1250
+ if (evt) {
1251
+ if (moved) {
1252
+ evt.preventDefault();
1253
+ !options.dropBubble && evt.stopPropagation();
1254
+ }
1255
+
1256
+ ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
1257
+
1258
+ if (rootEl === parentEl || Sortable.active.lastPullMode !== 'clone') {
1259
+ // Remove clone
1260
+ cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
1261
+ }
1262
+
1263
+ if (dragEl) {
1264
+ if (this.nativeDraggable) {
1265
+ _off(dragEl, 'dragend', this);
1266
+ }
1267
+
1268
+ _disableDraggable(dragEl);
1269
+ dragEl.style['will-change'] = '';
1270
+
1271
+ // Remove class's
1272
+ _toggleClass(dragEl, this.options.ghostClass, false);
1273
+ _toggleClass(dragEl, this.options.chosenClass, false);
1274
+
1275
+ // Drag stop event
1276
+ _dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex);
1277
+
1278
+ if (rootEl !== parentEl) {
1279
+ newIndex = _index(dragEl, options.draggable);
1280
+
1281
+ if (newIndex >= 0) {
1282
+ // Add event
1283
+ _dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex);
1284
+
1285
+ // Remove event
1286
+ _dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex);
1287
+
1288
+ // drag from one list and drop into another
1289
+ _dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
1290
+ _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
1291
+ }
1292
+ }
1293
+ else {
1294
+ if (dragEl.nextSibling !== nextEl) {
1295
+ // Get the index of the dragged element within its parent
1296
+ newIndex = _index(dragEl, options.draggable);
1297
+
1298
+ if (newIndex >= 0) {
1299
+ // drag & drop within the same list
1300
+ _dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex);
1301
+ _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ if (Sortable.active) {
1307
+ /* jshint eqnull:true */
1308
+ if (newIndex == null || newIndex === -1) {
1309
+ newIndex = oldIndex;
1310
+ }
1311
+
1312
+ _dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex);
1313
+
1314
+ // Save sorting
1315
+ this.save();
1316
+ }
1317
+ }
1318
+
1319
+ }
1320
+
1321
+ this._nulling();
1322
+ },
1323
+
1324
+ _nulling: function() {
1325
+ rootEl =
1326
+ dragEl =
1327
+ parentEl =
1328
+ ghostEl =
1329
+ nextEl =
1330
+ cloneEl =
1331
+ lastDownEl =
1332
+
1333
+ scrollEl =
1334
+ scrollParentEl =
1335
+
1336
+ tapEvt =
1337
+ touchEvt =
1338
+
1339
+ moved =
1340
+ newIndex =
1341
+
1342
+ lastEl =
1343
+ lastCSS =
1344
+
1345
+ putSortable =
1346
+ activeGroup =
1347
+ Sortable.active = null;
1348
+
1349
+ savedInputChecked.forEach(function (el) {
1350
+ el.checked = true;
1351
+ });
1352
+ savedInputChecked.length = 0;
1353
+ },
1354
+
1355
+ handleEvent: function (/**Event*/evt) {
1356
+ switch (evt.type) {
1357
+ case 'drop':
1358
+ case 'dragend':
1359
+ this._onDrop(evt);
1360
+ break;
1361
+
1362
+ case 'dragover':
1363
+ case 'dragenter':
1364
+ if (dragEl) {
1365
+ this._onDragOver(evt);
1366
+ _globalDragOver(evt);
1367
+ }
1368
+ break;
1369
+
1370
+ case 'mouseover':
1371
+ this._onDrop(evt);
1372
+ break;
1373
+
1374
+ case 'selectstart':
1375
+ evt.preventDefault();
1376
+ break;
1377
+ }
1378
+ },
1379
+
1380
+
1381
+ /**
1382
+ * Serializes the item into an array of string.
1383
+ * @returns {String[]}
1384
+ */
1385
+ toArray: function () {
1386
+ var order = [],
1387
+ el,
1388
+ children = this.el.children,
1389
+ i = 0,
1390
+ n = children.length,
1391
+ options = this.options;
1392
+
1393
+ for (; i < n; i++) {
1394
+ el = children[i];
1395
+ if (_closest(el, options.draggable, this.el)) {
1396
+ order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
1397
+ }
1398
+ }
1399
+
1400
+ return order;
1401
+ },
1402
+
1403
+
1404
+ /**
1405
+ * Sorts the elements according to the array.
1406
+ * @param {String[]} order order of the items
1407
+ */
1408
+ sort: function (order) {
1409
+ var items = {}, rootEl = this.el;
1410
+
1411
+ this.toArray().forEach(function (id, i) {
1412
+ var el = rootEl.children[i];
1413
+
1414
+ if (_closest(el, this.options.draggable, rootEl)) {
1415
+ items[id] = el;
1416
+ }
1417
+ }, this);
1418
+
1419
+ order.forEach(function (id) {
1420
+ if (items[id]) {
1421
+ rootEl.removeChild(items[id]);
1422
+ rootEl.appendChild(items[id]);
1423
+ }
1424
+ });
1425
+ },
1426
+
1427
+
1428
+ /**
1429
+ * Save the current sorting
1430
+ */
1431
+ save: function () {
1432
+ var store = this.options.store;
1433
+ store && store.set(this);
1434
+ },
1435
+
1436
+
1437
+ /**
1438
+ * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
1439
+ * @param {HTMLElement} el
1440
+ * @param {String} [selector] default: `options.draggable`
1441
+ * @returns {HTMLElement|null}
1442
+ */
1443
+ closest: function (el, selector) {
1444
+ return _closest(el, selector || this.options.draggable, this.el);
1445
+ },
1446
+
1447
+
1448
+ /**
1449
+ * Set/get option
1450
+ * @param {string} name
1451
+ * @param {*} [value]
1452
+ * @returns {*}
1453
+ */
1454
+ option: function (name, value) {
1455
+ var options = this.options;
1456
+
1457
+ if (value === void 0) {
1458
+ return options[name];
1459
+ } else {
1460
+ options[name] = value;
1461
+
1462
+ if (name === 'group') {
1463
+ _prepareGroup(options);
1464
+ }
1465
+ }
1466
+ },
1467
+
1468
+
1469
+ /**
1470
+ * Destroy
1471
+ */
1472
+ destroy: function () {
1473
+ var el = this.el;
1474
+
1475
+ el[expando] = null;
1476
+
1477
+ _off(el, 'mousedown', this._onTapStart);
1478
+ _off(el, 'touchstart', this._onTapStart);
1479
+ _off(el, 'pointerdown', this._onTapStart);
1480
+
1481
+ if (this.nativeDraggable) {
1482
+ _off(el, 'dragover', this);
1483
+ _off(el, 'dragenter', this);
1484
+ }
1485
+
1486
+ // Remove draggable attributes
1487
+ Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
1488
+ el.removeAttribute('draggable');
1489
+ });
1490
+
1491
+ touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
1492
+
1493
+ this._onDrop();
1494
+
1495
+ this.el = el = null;
1496
+ }
1497
+ };
1498
+
1499
+
1500
+ function _cloneHide(sortable, state) {
1501
+ if (sortable.lastPullMode !== 'clone') {
1502
+ state = true;
1503
+ }
1504
+
1505
+ if (cloneEl && (cloneEl.state !== state)) {
1506
+ _css(cloneEl, 'display', state ? 'none' : '');
1507
+
1508
+ if (!state) {
1509
+ if (cloneEl.state) {
1510
+ if (sortable.options.group.revertClone) {
1511
+ rootEl.insertBefore(cloneEl, nextEl);
1512
+ sortable._animate(dragEl, cloneEl);
1513
+ } else {
1514
+ rootEl.insertBefore(cloneEl, dragEl);
1515
+ }
1516
+ }
1517
+ }
1518
+
1519
+ cloneEl.state = state;
1520
+ }
1521
+ }
1522
+
1523
+
1524
+ function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
1525
+ if (el) {
1526
+ ctx = ctx || document;
1527
+
1528
+ do {
1529
+ if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) {
1530
+ return el;
1531
+ }
1532
+ /* jshint boss:true */
1533
+ } while (el = _getParentOrHost(el));
1534
+ }
1535
+
1536
+ return null;
1537
+ }
1538
+
1539
+
1540
+ function _getParentOrHost(el) {
1541
+ var parent = el.host;
1542
+
1543
+ return (parent && parent.nodeType) ? parent : el.parentNode;
1544
+ }
1545
+
1546
+
1547
+ function _globalDragOver(/**Event*/evt) {
1548
+ if (evt.dataTransfer) {
1549
+ evt.dataTransfer.dropEffect = 'move';
1550
+ }
1551
+ evt.preventDefault();
1552
+ }
1553
+
1554
+
1555
+ function _on(el, event, fn) {
1556
+ el.addEventListener(event, fn, captureMode);
1557
+ }
1558
+
1559
+
1560
+ function _off(el, event, fn) {
1561
+ el.removeEventListener(event, fn, captureMode);
1562
+ }
1563
+
1564
+
1565
+ function _toggleClass(el, name, state) {
1566
+ if (el) {
1567
+ if (el.classList) {
1568
+ el.classList[state ? 'add' : 'remove'](name);
1569
+ }
1570
+ else {
1571
+ var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
1572
+ el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
1573
+ }
1574
+ }
1575
+ }
1576
+
1577
+
1578
+ function _css(el, prop, val) {
1579
+ var style = el && el.style;
1580
+
1581
+ if (style) {
1582
+ if (val === void 0) {
1583
+ if (document.defaultView && document.defaultView.getComputedStyle) {
1584
+ val = document.defaultView.getComputedStyle(el, '');
1585
+ }
1586
+ else if (el.currentStyle) {
1587
+ val = el.currentStyle;
1588
+ }
1589
+
1590
+ return prop === void 0 ? val : val[prop];
1591
+ }
1592
+ else {
1593
+ if (!(prop in style)) {
1594
+ prop = '-webkit-' + prop;
1595
+ }
1596
+
1597
+ style[prop] = val + (typeof val === 'string' ? '' : 'px');
1598
+ }
1599
+ }
1600
+ }
1601
+
1602
+
1603
+ function _find(ctx, tagName, iterator) {
1604
+ if (ctx) {
1605
+ var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
1606
+
1607
+ if (iterator) {
1608
+ for (; i < n; i++) {
1609
+ iterator(list[i], i);
1610
+ }
1611
+ }
1612
+
1613
+ return list;
1614
+ }
1615
+
1616
+ return [];
1617
+ }
1618
+
1619
+
1620
+
1621
+ function _dispatchEvent(sortable, rootEl, name, targetEl, toEl, fromEl, startIndex, newIndex) {
1622
+ sortable = (sortable || rootEl[expando]);
1623
+
1624
+ var evt = document.createEvent('Event'),
1625
+ options = sortable.options,
1626
+ onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
1627
+
1628
+ evt.initEvent(name, true, true);
1629
+
1630
+ evt.to = toEl || rootEl;
1631
+ evt.from = fromEl || rootEl;
1632
+ evt.item = targetEl || rootEl;
1633
+ evt.clone = cloneEl;
1634
+
1635
+ evt.oldIndex = startIndex;
1636
+ evt.newIndex = newIndex;
1637
+
1638
+ rootEl.dispatchEvent(evt);
1639
+
1640
+ if (options[onName]) {
1641
+ options[onName].call(sortable, evt);
1642
+ }
1643
+ }
1644
+
1645
+
1646
+ function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt, willInsertAfter) {
1647
+ var evt,
1648
+ sortable = fromEl[expando],
1649
+ onMoveFn = sortable.options.onMove,
1650
+ retVal;
1651
+
1652
+ evt = document.createEvent('Event');
1653
+ evt.initEvent('move', true, true);
1654
+
1655
+ evt.to = toEl;
1656
+ evt.from = fromEl;
1657
+ evt.dragged = dragEl;
1658
+ evt.draggedRect = dragRect;
1659
+ evt.related = targetEl || toEl;
1660
+ evt.relatedRect = targetRect || toEl.getBoundingClientRect();
1661
+ evt.willInsertAfter = willInsertAfter;
1662
+
1663
+ fromEl.dispatchEvent(evt);
1664
+
1665
+ if (onMoveFn) {
1666
+ retVal = onMoveFn.call(sortable, evt, originalEvt);
1667
+ }
1668
+
1669
+ return retVal;
1670
+ }
1671
+
1672
+
1673
+ function _disableDraggable(el) {
1674
+ el.draggable = false;
1675
+ }
1676
+
1677
+
1678
+ function _unsilent() {
1679
+ _silent = false;
1680
+ }
1681
+
1682
+
1683
+ /** @returns {HTMLElement|false} */
1684
+ function _ghostIsLast(el, evt) {
1685
+ var lastEl = el.lastElementChild,
1686
+ rect = lastEl.getBoundingClientRect();
1687
+
1688
+ // 5 — min delta
1689
+ // abs — нельзя добавлять, а то глюки при наведении сверху
1690
+ return (evt.clientY - (rect.top + rect.height) > 5) ||
1691
+ (evt.clientX - (rect.left + rect.width) > 5);
1692
+ }
1693
+
1694
+
1695
+ /**
1696
+ * Generate id
1697
+ * @param {HTMLElement} el
1698
+ * @returns {String}
1699
+ * @private
1700
+ */
1701
+ function _generateId(el) {
1702
+ var str = el.tagName + el.className + el.src + el.href + el.textContent,
1703
+ i = str.length,
1704
+ sum = 0;
1705
+
1706
+ while (i--) {
1707
+ sum += str.charCodeAt(i);
1708
+ }
1709
+
1710
+ return sum.toString(36);
1711
+ }
1712
+
1713
+ /**
1714
+ * Returns the index of an element within its parent for a selected set of
1715
+ * elements
1716
+ * @param {HTMLElement} el
1717
+ * @param {selector} selector
1718
+ * @return {number}
1719
+ */
1720
+ function _index(el, selector) {
1721
+ var index = 0;
1722
+
1723
+ if (!el || !el.parentNode) {
1724
+ return -1;
1725
+ }
1726
+
1727
+ while (el && (el = el.previousElementSibling)) {
1728
+ if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && (selector === '>*' || _matches(el, selector))) {
1729
+ index++;
1730
+ }
1731
+ }
1732
+
1733
+ return index;
1734
+ }
1735
+
1736
+ function _matches(/**HTMLElement*/el, /**String*/selector) {
1737
+ if (el) {
1738
+ selector = selector.split('.');
1739
+
1740
+ var tag = selector.shift().toUpperCase(),
1741
+ re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
1742
+
1743
+ return (
1744
+ (tag === '' || el.nodeName.toUpperCase() == tag) &&
1745
+ (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
1746
+ );
1747
+ }
1748
+
1749
+ return false;
1750
+ }
1751
+
1752
+ function _throttle(callback, ms) {
1753
+ var args, _this;
1754
+
1755
+ return function () {
1756
+ if (args === void 0) {
1757
+ args = arguments;
1758
+ _this = this;
1759
+
1760
+ setTimeout(function () {
1761
+ if (args.length === 1) {
1762
+ callback.call(_this, args[0]);
1763
+ } else {
1764
+ callback.apply(_this, args);
1765
+ }
1766
+
1767
+ args = void 0;
1768
+ }, ms);
1769
+ }
1770
+ };
1771
+ }
1772
+
1773
+ function _extend(dst, src) {
1774
+ if (dst && src) {
1775
+ for (var key in src) {
1776
+ if (src.hasOwnProperty(key)) {
1777
+ dst[key] = src[key];
1778
+ }
1779
+ }
1780
+ }
1781
+
1782
+ return dst;
1783
+ }
1784
+
1785
+ function _clone(el) {
1786
+ if (Polymer && Polymer.dom) {
1787
+ return Polymer.dom(el).cloneNode(true);
1788
+ }
1789
+ else if ($) {
1790
+ return $(el).clone(true)[0];
1791
+ }
1792
+ else {
1793
+ return el.cloneNode(true);
1794
+ }
1795
+ }
1796
+
1797
+ function _saveInputCheckedState(root) {
1798
+ var inputs = root.getElementsByTagName('input');
1799
+ var idx = inputs.length;
1800
+
1801
+ while (idx--) {
1802
+ var el = inputs[idx];
1803
+ el.checked && savedInputChecked.push(el);
1804
+ }
1805
+ }
1806
+
1807
+ function _nextTick(fn) {
1808
+ return setTimeout(fn, 0);
1809
+ }
1810
+
1811
+ function _cancelNextTick(id) {
1812
+ return clearTimeout(id);
1813
+ }
1814
+
1815
+ // Fixed #973:
1816
+ _on(document, 'touchmove', function (evt) {
1817
+ if (Sortable.active) {
1818
+ evt.preventDefault();
1819
+ }
1820
+ });
1821
+
1822
+ // Export utils
1823
+ Sortable.utils = {
1824
+ on: _on,
1825
+ off: _off,
1826
+ css: _css,
1827
+ find: _find,
1828
+ is: function (el, selector) {
1829
+ return !!_closest(el, selector, el);
1830
+ },
1831
+ extend: _extend,
1832
+ throttle: _throttle,
1833
+ closest: _closest,
1834
+ toggleClass: _toggleClass,
1835
+ clone: _clone,
1836
+ index: _index,
1837
+ nextTick: _nextTick,
1838
+ cancelNextTick: _cancelNextTick
1839
+ };
1840
+
1841
+
1842
+ /**
1843
+ * Create sortable instance
1844
+ * @param {HTMLElement} el
1845
+ * @param {Object} [options]
1846
+ */
1847
+ Sortable.create = function (el, options) {
1848
+ return new Sortable(el, options);
1849
+ };
1850
+
1851
+
1852
+ // Export
1853
+ Sortable.version = '1.7.0';
1854
+ return Sortable;
1855
+ });
1856
+
1857
+
1858
+ /***/ }),
1859
+ /* 5 */
1860
+ /***/ (function(module, exports, __webpack_require__) {
1861
+
1862
+ "use strict";
1863
+ /* WEBPACK VAR INJECTION */(function(jQuery) {
1864
+
1865
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
1866
+
1867
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1868
+
1869
+ (function ($, window, document) {
1870
+ var Plugin, defaults, pluginName;
1871
+ pluginName = 'SimpleFormNestedFields';
1872
+ defaults = {
1873
+ debug: false
1874
+ };
1875
+ Plugin = function () {
1876
+ function Plugin(element, options) {
1877
+ _classCallCheck(this, Plugin);
1878
+
1879
+ this.element = element;
1880
+ this.options = $.extend({}, defaults, options);
1881
+ this._defaults = defaults;
1882
+ this._name = pluginName;
1883
+ this.$element = $(this.element);
1884
+ this.init();
1885
+ }
1886
+
1887
+ _createClass(Plugin, [{
1888
+ key: 'init',
1889
+ value: function init() {
1890
+ this.$element.SimpleFormNestedFields__Links();
1891
+ if (this.is_sortable()) {
1892
+ return this.$element.SimpleFormNestedFields__Sortable();
1893
+ }
1894
+ }
1895
+ }, {
1896
+ key: 'destroy',
1897
+ value: function destroy() {
1898
+ this.$element.data('plugin_SimpleFormNestedFields__Links').destroy();
1899
+ return this.$element.data('plugin_SimpleFormNestedFields__Sortable').destroy();
1900
+ }
1901
+ }, {
1902
+ key: 'is_sortable',
1903
+ value: function is_sortable() {
1904
+ return this.element.classList.contains('simple_form_nested_fields__sortable');
1905
+ }
1906
+ }]);
1907
+
1908
+ return Plugin;
1909
+ }();
1910
+ // A really lightweight plugin wrapper around the constructor,
1911
+ // preventing against multiple instantiations
1912
+ return $.fn[pluginName] = function (options) {
1913
+ return this.each(function () {
1914
+ if (!$.data(this, 'plugin_' + pluginName)) {
1915
+ return $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
1916
+ }
1917
+ });
1918
+ };
1919
+ })(jQuery, window, document);
1920
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)))
1921
+
1922
+ /***/ })
1923
+ /******/ ]);
1924
+ });