Nikolay Suslov 7 năm trước cách đây
mục cha
commit
4db4dd66bf

+ 2 - 1
support/client/lib/index.html

@@ -35,6 +35,7 @@
      
     <script type="text/javascript" src="vwf/view/lib/cell.js"></script>
     <script type="text/javascript" src="vwf/view/lib/he.js"></script>
+    <script type="text/javascript" src="vwf/view/lib/draggabilly.pkgd.js"></script>
 
     <link rel="stylesheet" href="vwf/view/lib/mdc/dist/material-components-web.css">
     <script src= "vwf/view/lib/mdc/dist/material-components-web.js"></script>
@@ -167,7 +168,7 @@
         </div>
     </div>
     <div id="vwf-root"></div>
-  
+
 
     <script>mdc.autoInit()</script>
 

+ 296 - 85
support/client/lib/vwf/view/editor-new.js

@@ -86,7 +86,7 @@ define([
 
 
             $('body').append(
-                "<div id='drawer'></div><div id='toolbar'></div<div id='clientsList'></div><div id='editor' class='relClass'>\n" +
+                "<div id='editor' class='relClass'>\n" +
                 "  <div class='uiContainer'>\n" +
                 "    <div class='editor-tabs' id='tabs'>\n" +
                 "      <img id='x' style='display:none' src='images/tab_X.png' alt='x' />\n" +
@@ -110,8 +110,22 @@ define([
             );
 
             //style: "position: absolute; top: 0; left: 0; z-index: 2",
+        //    let draggie = new Draggabilly('.draggable');
+        //   let dragDiv = document.querySelector("#dragDiv").style.visibility = 'hidden';
 
-            
+        // let propDiv = document.createElement("div"); 
+        // var newContent = document.createTextNode("Hi there and greetings!"); 
+        // newDiv.appendChild(newContent); //add the text node to the newly created div. 
+
+        //<div id='drawer'></div><div id='toolbar'></div><div id='clientsList'></div>
+
+       
+
+        ["drawer", "toolbar", "propWindow", "clientsWindow"].forEach(item => {
+            let el = document.createElement("div");
+            el.setAttribute("id", item);
+            document.body.appendChild(el);}
+        );
 
             let protoPropertiesCell = function(m) {
                 return { 
@@ -170,12 +184,19 @@ define([
                         class: "mdc-list-item",
                         $text: m.name,
                         },
+                        {
+                            $cell: true,
+                            $type: "span",
+                            $text: "  "
+                        },
                         {
                             class: "mdc-textfield",
                             $cell: true,
-                            $type: "div",
-                            $components: [{
+                            $type: "span",
+                            $components: [
+                                {
                                 class: "mdc-textfield__input",
+                                id: "prop-" + m.name,
                                 $cell: true,
                                 $type: "input",
                                 type: "text",
@@ -185,6 +206,7 @@ define([
                                     try {
                                         propValue = JSON.parse(propValue);
                                         self.kernel.setProperty(this._currentNode, m.name, propValue);
+                                      
                                     } catch (e) {
                                         // restore the original value on error
                                         this.value = propValue;
@@ -199,6 +221,10 @@ define([
 
             }
 
+
+            
+
+
             let nodeLink = function(m){ 
                 return { 
                     $type: "li",
@@ -226,7 +252,7 @@ define([
             }
 
             let nodesCell = {
-                style:"overflow: scroll; max-height: 600px;",
+                style:"overflow-y: scroll; max-height: 800px;",
                 $cell: true,
                 $type: "div",
                 id: "currentNode",
@@ -269,50 +295,131 @@ define([
                     this.$components = [
                         {
                             $cell: true,
-                            $type: "a",
-                            class: "mdc-list-item mdc-persistent-drawer--selected",
-                            $href: "#",
-                            $text: "<--",
-                            onclick: function(e){
-                                let node = self.nodes[this._currentNode];
-                                if (node.parentID !== 0) {
-                                    //self.currentNodeID = node.parentID,
-                                    document.querySelector('#currentNode')._setNode(node.parentID)
+                            $type: "ul",
+                            class: "mdc-list",
+                            $components:[
+                                {
+                                    $cell: true,
+                                    $type: "a",
+                                    class: "mdc-list-item",
+                                    $href: "#",
+                                    $text: "<--",
+                                    onclick: function(e){
+                                        let node = self.nodes[this._currentNode];
+                                        if (node.parentID !== 0) {
+                                            //self.currentNodeID = node.parentID,
+                                            document.querySelector('#currentNode')._setNode(node.parentID)
+                                        }
+                                        
+                                      }
+        
+                                }, 
+                                {
+                                    $type: "li",
+                                    class: "mdc-list-item",
+                                    $components:[
+                                        { 
+                                    $text: "name",
+                                    $type: "span",
+                                    $init: function(){
+                                        let node = self.nodes[this._currentNode];
+                                        this.$text = node.name
+                                    },
+                                    class: "mdc-list-item__text mdc-typography--headline"
+                                    //<h1 class="mdc-typography--display4">Big header</h1>
+                                }]
+                                },
+                                {
+                                    $cell: true,
+                                    $type: "ul",
+                                    class: "mdc-list",
+                                    $components: this._getChildNodes().map(nodeLink)
+                                }, listDivider,  {
+                                    $type: "li",
+                                    class: "mdc-list-item",
+                                    $components:[
+                                        { 
+                                    $text: "Properties",
+                                    $type: "span",
+                                    class: "mdc-list-item__text mdc-typography--title"
+                                    //<h1 class="mdc-typography--display4">Big header</h1>
+                                }]
+                                },listDivider,
+                                {
+                                    $cell: true,
+                                    $type: "ul",
+                                    class: "mdc-list",
+                                    $components: this._getNodeProperties().map(propertiesCell)
+                                }, listDivider,
+                                {
+                                    $type: "li",
+                                    class: "mdc-list-item",
+                                    $components:[
+                                        { 
+                                    $text: "Proto properties",
+                                    $type: "span",
+                                    class: "mdc-list-item__text mdc-typography--title"
+                                    //<h1 class="mdc-typography--display4">Big header</h1>
+                                }]
+                                },
+                                {
+                                    $cell: true,
+                                    $type: "ul",
+                                    class: "mdc-list",
+                                    $components: this._getNodeProtoProperties().map(protoPropertiesCell)
                                 }
-                                
-                              }
 
+                            ]
                         },
-                        {
-                            $cell: true,
-                            $type: "a",
-                            class: "mdc-list-item mdc-persistent-drawer--selected",
-                            $href: "#",
-                            $text: this._currentNode
-                        }, listDivider,
-                        {
-                            $cell: true,
-                            $type: "ul",
-                            class: "mdc-list",
-                            $components: this._getChildNodes().map(nodeLink)
-                        }, listDivider,
-                        {
-                            $cell: true,
-                            $type: "ul",
-                            class: "mdc-list",
-                            $components: this._getNodeProperties().map(propertiesCell)
-                        }, listDivider,
-                        {
-                            $cell: true,
-                            $type: "ul",
-                            class: "mdc-list",
-                            $components: this._getNodeProtoProperties().map(protoPropertiesCell)
-                        }
+                        
+                        
+                       
+                        
                         ]
                 }
                 
             }
 
+           
+            let propWindow = {
+                $cell: true,
+                $type: "div",
+    
+                $components:[
+    
+                    {
+                        $cell: true,
+                    $type: "div",
+                    class: "mdc-list-group",
+                    $components: [
+                        {
+                        $cell: true,
+                        $type: "nav",
+                        class: "mdc-list",
+                        $components: [
+    
+                               //$text: 'Yes!'
+                    nodesCell
+                    
+                    
+    
+    
+                        ]
+                    }
+                    ]},
+                    
+                 
+            //     <button class="mdc-button">
+            //     Flat button
+            //   </button>
+        ]
+    
+            }
+
+            
+
+
+
             let clientListCell = {
                 $cell: true,
                 $type: "div",
@@ -328,7 +435,7 @@ define([
 
                 },
                 $update: function () {
-                    this.$components = this._filteredItems.map(Tr);
+                    
                 },
                 $components: [{
                     $cell: true,
@@ -346,16 +453,24 @@ define([
                 }]
             }
 
+            createCellWindow("clientsWindow", clientListCell);
+            createCellWindow("propWindow", propWindow);
+
             let drawerCell = {
                 $cell: true,
                 $type: "nav",
                 class: "mdc-persistent-drawer__drawer",
+
                 $components: [
+
                     {
                         $cell: true,
                         $type: "div",
                         class: "mdc-persistent-drawer__toolbar-spacer",
                     },
+
+                    
+
                     {
                         $cell: true,
                         $type: "div",
@@ -364,52 +479,67 @@ define([
                             $cell: true,
                             $type: "nav",
                             class: "mdc-list",
-                            $components: [{
-                                $cell: true,
-                                $type: "a",
-                                class: "mdc-list-item mdc-persistent-drawer--selected",
-                                $href: "#",
-                                $components: [{
+                            $components: [
+                                {
                                     $cell: true,
-                                    $type: "i",
-                                    class: "material-icons mdc-list-item__start-detail",
-                                    $text: "inbox"
+                                    $type: "a",
+                                    class: "mdc-list-item mdc-persistent-drawer--selected",
+                                    $href: "#",
+                                    onclick: function(e){
+                                        //self.currentNodeID = m.ID;
+                                        let currentNode = document.querySelector('#currentNode')._currentNode;
+                                        currentNode == '' ? document.querySelector('#currentNode')._setNode(vwf_view.kernel.find("", "/")[0]) :
+                                        document.querySelector('#currentNode')._setNode(currentNode);
+                                        document.querySelector('#propWindow').style.visibility = 'visible';
+                                      },
+                                    $components: [{
+                                        $cell: true,
+                                        $type: "i",
+                                        class: "material-icons mdc-list-item__start-detail",
+                                        $text: "inbox"
+                                    },
+                                    {
+                                        $text: "Properties "
+                                    }
+                                    ]
+    
                                 },
                                 {
-                                    $text: "Inbox "
-                                }
-                                ]
-
-                            },
-                            {
-                                $cell: true,
-                                $type: "a",
-                                class: "mdc-list-item mdc-persistent-drawer--selected",
-                                $href: "#",
-                                $components: [{
-                                    $type: "i",
-                                    class: "material-icons mdc-list-item__start-detail",
-                                    'aria-hidden': "true",
-                                    $text: "star"
+                                    $cell: true,
+                                    $type: "a",
+                                    class: "mdc-list-item mdc-persistent-drawer--selected",
+                                    $href: "#",
+                                    onclick: function(e){
+                                        //self.currentNodeID = m.ID;
+                                       
+                                        document.querySelector('#clientsWindow').style.visibility = 'visible';
+                                      },
+                                    $components: [{
+                                        $type: "i",
+                                        class: "material-icons mdc-list-item__start-detail",
+                                        'aria-hidden': "true",
+                                        $text: "star"
+                                    },
+                                    {
+                                        $text: "Clients "
+                                    }]
+    
                                 },
+    
                                 {
-                                    $text: "Star "
-                                }]
-
-                            },
-
-                            {
-                                class: "mdc-textfield",
-                                $cell: true,
-                                $type: "div",
-                                $components: [{
-                                    class: "mdc-textfield__input",
+                                    class: "mdc-textfield",
                                     $cell: true,
-                                    $type: "input",
-                                    type: "text"
-                                }]
-
-                            }, nodesCell
+                                    $type: "div",
+                                    $components: [{
+                                        class: "mdc-textfield__input",
+                                        $cell: true,
+                                        $type: "input",
+                                        type: "text"
+                                    }]
+    
+                                }
+    
+                                //nodesCell
                             ]
                         }]
                     }]
@@ -471,9 +601,13 @@ define([
             var drawer = new MDCPersistentDrawer(drawerEl);
             document.querySelector('.demo-menu').addEventListener('click', function () {
                 //self.currentNodeID = (self.currentNodeID == '') ? (vwf_view.kernel.find("", "/")[0]) : self.currentNodeID; 
-                let currentNode = document.querySelector('#currentNode')._currentNode;
-                currentNode == '' ? document.querySelector('#currentNode')._setNode(vwf_view.kernel.find("", "/")[0]) :
-                document.querySelector('#currentNode')._setNode(currentNode);
+
+
+                // let currentNode = document.querySelector('#currentNode')._currentNode;
+                // currentNode == '' ? document.querySelector('#currentNode')._setNode(vwf_view.kernel.find("", "/")[0]) :
+                // document.querySelector('#currentNode')._setNode(currentNode);
+
+
                 //document.querySelector('#currentNode')._setNode(self.currentNodeID);
                 drawer.open = !drawer.open;
             });
@@ -487,6 +621,9 @@ define([
 
 
 
+           
+            //==============
+
             
 
 
@@ -686,6 +823,15 @@ define([
                 // No need to escape propertyValue, because .val does its own escaping
                 $('#input-' + nodeIDAttribute + '-' + propertyNameAttribute).val(node.properties[propertyName].getValue());
             }
+
+            let propCell = document.querySelector("#currentNode #prop-"+propertyName);
+           
+            if (propCell !== null){
+                if (propCell._currentNode == nodeID) {
+                    propCell.value = node.properties[propertyName].getValue();
+                }
+        }
+
         },
 
         //gotProperty: [ /* nodeID, propertyName, propertyValue */ ],
@@ -737,6 +883,71 @@ define([
 
     });
 
+
+
+    function createCellWindow(elementID, cellNode) {
+
+        document.querySelector('#'+elementID).$cell({
+            $cell: true,
+            $type: "div",
+            id: elementID,
+            class: 'draggable',
+            $init: function(){
+                // let draggie = new Draggabilly('.draggable', {
+                //     handle: '.handle',
+                //     containment: true
+                //   });
+
+                // get all draggie elements
+                var draggableElems = document.querySelectorAll('.draggable');
+                // array of Draggabillies
+                var draggies = []
+                // init Draggabillies
+                for ( var i=0, len = draggableElems.length; i < len; i++ ) {
+                var draggableElem = draggableElems[i];
+                var draggie = new Draggabilly( draggableElem, {
+                    handle: '.handle',
+                    containment: true
+                });
+                draggies.push( draggie );
+                }
+
+
+                this.style.visibility = 'hidden';
+            },
+            $components: [
+                
+                {  
+                    $cell: true,
+                    $type: "div",
+                    class: "handle",
+                    $components: [
+                        {
+                            $cell: true,
+                            $type: "button",
+                            class: "mdc-button mdc-button--compact",
+                            $text: "X",
+                            onclick: function(e){
+                                //self.currentNodeID = m.ID;
+                                document.querySelector('#'+elementID).style.visibility = 'hidden';
+                              }
+        
+                        }
+                        
+                    ]
+                },
+               
+                cellNode
+              // { $text: "23423"}
+            ]
+        }
+        );
+
+
+    }
+
+
+
     // -- getChildByName --------------------------------------------------------------------
 
     

+ 1538 - 0
support/client/lib/vwf/view/lib/draggabilly.pkgd.js

@@ -0,0 +1,1538 @@
+/*!
+ * Draggabilly PACKAGED v2.1.1
+ * Make that shiz draggable
+ * http://draggabilly.desandro.com
+ * MIT license
+ */
+
+/**
+ * Bridget makes jQuery widgets
+ * v2.0.0
+ * MIT license
+ */
+
+/* jshint browser: true, strict: true, undef: true, unused: true */
+
+( function( window, factory ) {
+  
+  /* globals define: false, module: false, require: false */
+
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD
+    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
+      factory( window, jQuery );
+    });
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS
+    module.exports = factory(
+      window,
+      require('jquery')
+    );
+  } else {
+    // browser global
+    window.jQueryBridget = factory(
+      window,
+      window.jQuery
+    );
+  }
+
+}( window, function factory( window, jQuery ) {
+
+
+// ----- utils ----- //
+
+var arraySlice = Array.prototype.slice;
+
+// helper function for logging errors
+// $.error breaks jQuery chaining
+var console = window.console;
+var logError = typeof console == 'undefined' ? function() {} :
+  function( message ) {
+    console.error( message );
+  };
+
+// ----- jQueryBridget ----- //
+
+function jQueryBridget( namespace, PluginClass, $ ) {
+  $ = $ || jQuery || window.jQuery;
+  if ( !$ ) {
+    return;
+  }
+
+  // add option method -> $().plugin('option', {...})
+  if ( !PluginClass.prototype.option ) {
+    // option setter
+    PluginClass.prototype.option = function( opts ) {
+      // bail out if not an object
+      if ( !$.isPlainObject( opts ) ){
+        return;
+      }
+      this.options = $.extend( true, this.options, opts );
+    };
+  }
+
+  // make jQuery plugin
+  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
+    if ( typeof arg0 == 'string' ) {
+      // method call $().plugin( 'methodName', { options } )
+      // shift arguments by 1
+      var args = arraySlice.call( arguments, 1 );
+      return methodCall( this, arg0, args );
+    }
+    // just $().plugin({ options })
+    plainCall( this, arg0 );
+    return this;
+  };
+
+  // $().plugin('methodName')
+  function methodCall( $elems, methodName, args ) {
+    var returnValue;
+    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
+
+    $elems.each( function( i, elem ) {
+      // get instance
+      var instance = $.data( elem, namespace );
+      if ( !instance ) {
+        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
+          pluginMethodStr );
+        return;
+      }
+
+      var method = instance[ methodName ];
+      if ( !method || methodName.charAt(0) == '_' ) {
+        logError( pluginMethodStr + ' is not a valid method' );
+        return;
+      }
+
+      // apply method, get return value
+      var value = method.apply( instance, args );
+      // set return value if value is returned, use only first value
+      returnValue = returnValue === undefined ? value : returnValue;
+    });
+
+    return returnValue !== undefined ? returnValue : $elems;
+  }
+
+  function plainCall( $elems, options ) {
+    $elems.each( function( i, elem ) {
+      var instance = $.data( elem, namespace );
+      if ( instance ) {
+        // set options & init
+        instance.option( options );
+        instance._init();
+      } else {
+        // initialize new instance
+        instance = new PluginClass( elem, options );
+        $.data( elem, namespace, instance );
+      }
+    });
+  }
+
+  updateJQuery( $ );
+
+}
+
+// ----- updateJQuery ----- //
+
+// set $.bridget for v1 backwards compatibility
+function updateJQuery( $ ) {
+  if ( !$ || ( $ && $.bridget ) ) {
+    return;
+  }
+  $.bridget = jQueryBridget;
+}
+
+updateJQuery( jQuery || window.jQuery );
+
+// -----  ----- //
+
+return jQueryBridget;
+
+}));
+
+/*!
+ * getSize v2.0.2
+ * measure size of elements
+ * MIT license
+ */
+
+/*jshint browser: true, strict: true, undef: true, unused: true */
+/*global define: false, module: false, console: false */
+
+( function( window, factory ) {
+  
+
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD
+    define( 'get-size/get-size',[],function() {
+      return factory();
+    });
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS
+    module.exports = factory();
+  } else {
+    // browser global
+    window.getSize = factory();
+  }
+
+})( window, function factory() {
+
+
+// -------------------------- helpers -------------------------- //
+
+// get a number from a string, not a percentage
+function getStyleSize( value ) {
+  var num = parseFloat( value );
+  // not a percent like '100%', and a number
+  var isValid = value.indexOf('%') == -1 && !isNaN( num );
+  return isValid && num;
+}
+
+function noop() {}
+
+var logError = typeof console == 'undefined' ? noop :
+  function( message ) {
+    console.error( message );
+  };
+
+// -------------------------- measurements -------------------------- //
+
+var measurements = [
+  'paddingLeft',
+  'paddingRight',
+  'paddingTop',
+  'paddingBottom',
+  'marginLeft',
+  'marginRight',
+  'marginTop',
+  'marginBottom',
+  'borderLeftWidth',
+  'borderRightWidth',
+  'borderTopWidth',
+  'borderBottomWidth'
+];
+
+var measurementsLength = measurements.length;
+
+function getZeroSize() {
+  var size = {
+    width: 0,
+    height: 0,
+    innerWidth: 0,
+    innerHeight: 0,
+    outerWidth: 0,
+    outerHeight: 0
+  };
+  for ( var i=0; i < measurementsLength; i++ ) {
+    var measurement = measurements[i];
+    size[ measurement ] = 0;
+  }
+  return size;
+}
+
+// -------------------------- getStyle -------------------------- //
+
+/**
+ * getStyle, get style of element, check for Firefox bug
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
+ */
+function getStyle( elem ) {
+  var style = getComputedStyle( elem );
+  if ( !style ) {
+    logError( 'Style returned ' + style +
+      '. Are you running this code in a hidden iframe on Firefox? ' +
+      'See http://bit.ly/getsizebug1' );
+  }
+  return style;
+}
+
+// -------------------------- setup -------------------------- //
+
+var isSetup = false;
+
+var isBoxSizeOuter;
+
+/**
+ * setup
+ * check isBoxSizerOuter
+ * do on first getSize() rather than on page load for Firefox bug
+ */
+function setup() {
+  // setup once
+  if ( isSetup ) {
+    return;
+  }
+  isSetup = true;
+
+  // -------------------------- box sizing -------------------------- //
+
+  /**
+   * WebKit measures the outer-width on style.width on border-box elems
+   * IE & Firefox<29 measures the inner-width
+   */
+  var div = document.createElement('div');
+  div.style.width = '200px';
+  div.style.padding = '1px 2px 3px 4px';
+  div.style.borderStyle = 'solid';
+  div.style.borderWidth = '1px 2px 3px 4px';
+  div.style.boxSizing = 'border-box';
+
+  var body = document.body || document.documentElement;
+  body.appendChild( div );
+  var style = getStyle( div );
+
+  getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize( style.width ) == 200;
+  body.removeChild( div );
+
+}
+
+// -------------------------- getSize -------------------------- //
+
+function getSize( elem ) {
+  setup();
+
+  // use querySeletor if elem is string
+  if ( typeof elem == 'string' ) {
+    elem = document.querySelector( elem );
+  }
+
+  // do not proceed on non-objects
+  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
+    return;
+  }
+
+  var style = getStyle( elem );
+
+  // if hidden, everything is 0
+  if ( style.display == 'none' ) {
+    return getZeroSize();
+  }
+
+  var size = {};
+  size.width = elem.offsetWidth;
+  size.height = elem.offsetHeight;
+
+  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
+
+  // get all measurements
+  for ( var i=0; i < measurementsLength; i++ ) {
+    var measurement = measurements[i];
+    var value = style[ measurement ];
+    var num = parseFloat( value );
+    // any 'auto', 'medium' value will be 0
+    size[ measurement ] = !isNaN( num ) ? num : 0;
+  }
+
+  var paddingWidth = size.paddingLeft + size.paddingRight;
+  var paddingHeight = size.paddingTop + size.paddingBottom;
+  var marginWidth = size.marginLeft + size.marginRight;
+  var marginHeight = size.marginTop + size.marginBottom;
+  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
+  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
+
+  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
+
+  // overwrite width and height if we can get it from style
+  var styleWidth = getStyleSize( style.width );
+  if ( styleWidth !== false ) {
+    size.width = styleWidth +
+      // add padding and border unless it's already including it
+      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
+  }
+
+  var styleHeight = getStyleSize( style.height );
+  if ( styleHeight !== false ) {
+    size.height = styleHeight +
+      // add padding and border unless it's already including it
+      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
+  }
+
+  size.innerWidth = size.width - ( paddingWidth + borderWidth );
+  size.innerHeight = size.height - ( paddingHeight + borderHeight );
+
+  size.outerWidth = size.width + marginWidth;
+  size.outerHeight = size.height + marginHeight;
+
+  return size;
+}
+
+return getSize;
+
+});
+
+/**
+ * EvEmitter v1.0.3
+ * Lil' event emitter
+ * MIT License
+ */
+
+/* jshint unused: true, undef: true, strict: true */
+
+( function( global, factory ) {
+  // universal module definition
+  /* jshint strict: false */ /* globals define, module, window */
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD - RequireJS
+    define( 'ev-emitter/ev-emitter',factory );
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS - Browserify, Webpack
+    module.exports = factory();
+  } else {
+    // Browser globals
+    global.EvEmitter = factory();
+  }
+
+}( typeof window != 'undefined' ? window : this, function() {
+
+
+
+function EvEmitter() {}
+
+var proto = EvEmitter.prototype;
+
+proto.on = function( eventName, listener ) {
+  if ( !eventName || !listener ) {
+    return;
+  }
+  // set events hash
+  var events = this._events = this._events || {};
+  // set listeners array
+  var listeners = events[ eventName ] = events[ eventName ] || [];
+  // only add once
+  if ( listeners.indexOf( listener ) == -1 ) {
+    listeners.push( listener );
+  }
+
+  return this;
+};
+
+proto.once = function( eventName, listener ) {
+  if ( !eventName || !listener ) {
+    return;
+  }
+  // add event
+  this.on( eventName, listener );
+  // set once flag
+  // set onceEvents hash
+  var onceEvents = this._onceEvents = this._onceEvents || {};
+  // set onceListeners object
+  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
+  // set flag
+  onceListeners[ listener ] = true;
+
+  return this;
+};
+
+proto.off = function( eventName, listener ) {
+  var listeners = this._events && this._events[ eventName ];
+  if ( !listeners || !listeners.length ) {
+    return;
+  }
+  var index = listeners.indexOf( listener );
+  if ( index != -1 ) {
+    listeners.splice( index, 1 );
+  }
+
+  return this;
+};
+
+proto.emitEvent = function( eventName, args ) {
+  var listeners = this._events && this._events[ eventName ];
+  if ( !listeners || !listeners.length ) {
+    return;
+  }
+  var i = 0;
+  var listener = listeners[i];
+  args = args || [];
+  // once stuff
+  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
+
+  while ( listener ) {
+    var isOnce = onceListeners && onceListeners[ listener ];
+    if ( isOnce ) {
+      // remove listener
+      // remove before trigger to prevent recursion
+      this.off( eventName, listener );
+      // unset once flag
+      delete onceListeners[ listener ];
+    }
+    // trigger listener
+    listener.apply( this, args );
+    // get next listener
+    i += isOnce ? 0 : 1;
+    listener = listeners[i];
+  }
+
+  return this;
+};
+
+return EvEmitter;
+
+}));
+
+/*!
+ * Unipointer v2.1.0
+ * base class for doing one thing with pointer event
+ * MIT license
+ */
+
+/*jshint browser: true, undef: true, unused: true, strict: true */
+
+( function( window, factory ) {
+  // universal module definition
+  /* jshint strict: false */ /*global define, module, require */
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD
+    define( 'unipointer/unipointer',[
+      'ev-emitter/ev-emitter'
+    ], function( EvEmitter ) {
+      return factory( window, EvEmitter );
+    });
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS
+    module.exports = factory(
+      window,
+      require('ev-emitter')
+    );
+  } else {
+    // browser global
+    window.Unipointer = factory(
+      window,
+      window.EvEmitter
+    );
+  }
+
+}( window, function factory( window, EvEmitter ) {
+
+
+
+function noop() {}
+
+function Unipointer() {}
+
+// inherit EvEmitter
+var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
+
+proto.bindStartEvent = function( elem ) {
+  this._bindStartEvent( elem, true );
+};
+
+proto.unbindStartEvent = function( elem ) {
+  this._bindStartEvent( elem, false );
+};
+
+/**
+ * works as unbinder, as you can ._bindStart( false ) to unbind
+ * @param {Boolean} isBind - will unbind if falsey
+ */
+proto._bindStartEvent = function( elem, isBind ) {
+  // munge isBind, default to true
+  isBind = isBind === undefined ? true : !!isBind;
+  var bindMethod = isBind ? 'addEventListener' : 'removeEventListener';
+
+  if ( window.navigator.pointerEnabled ) {
+    // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca
+    elem[ bindMethod ]( 'pointerdown', this );
+  } else if ( window.navigator.msPointerEnabled ) {
+    // IE10 Pointer Events
+    elem[ bindMethod ]( 'MSPointerDown', this );
+  } else {
+    // listen for both, for devices like Chrome Pixel
+    elem[ bindMethod ]( 'mousedown', this );
+    elem[ bindMethod ]( 'touchstart', this );
+  }
+};
+
+// trigger handler methods for events
+proto.handleEvent = function( event ) {
+  var method = 'on' + event.type;
+  if ( this[ method ] ) {
+    this[ method ]( event );
+  }
+};
+
+// returns the touch that we're keeping track of
+proto.getTouch = function( touches ) {
+  for ( var i=0; i < touches.length; i++ ) {
+    var touch = touches[i];
+    if ( touch.identifier == this.pointerIdentifier ) {
+      return touch;
+    }
+  }
+};
+
+// ----- start event ----- //
+
+proto.onmousedown = function( event ) {
+  // dismiss clicks from right or middle buttons
+  var button = event.button;
+  if ( button && ( button !== 0 && button !== 1 ) ) {
+    return;
+  }
+  this._pointerDown( event, event );
+};
+
+proto.ontouchstart = function( event ) {
+  this._pointerDown( event, event.changedTouches[0] );
+};
+
+proto.onMSPointerDown =
+proto.onpointerdown = function( event ) {
+  this._pointerDown( event, event );
+};
+
+/**
+ * pointer start
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto._pointerDown = function( event, pointer ) {
+  // dismiss other pointers
+  if ( this.isPointerDown ) {
+    return;
+  }
+
+  this.isPointerDown = true;
+  // save pointer identifier to match up touch events
+  this.pointerIdentifier = pointer.pointerId !== undefined ?
+    // pointerId for pointer events, touch.indentifier for touch events
+    pointer.pointerId : pointer.identifier;
+
+  this.pointerDown( event, pointer );
+};
+
+proto.pointerDown = function( event, pointer ) {
+  this._bindPostStartEvents( event );
+  this.emitEvent( 'pointerDown', [ event, pointer ] );
+};
+
+// hash of events to be bound after start event
+var postStartEvents = {
+  mousedown: [ 'mousemove', 'mouseup' ],
+  touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
+  pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
+  MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ]
+};
+
+proto._bindPostStartEvents = function( event ) {
+  if ( !event ) {
+    return;
+  }
+  // get proper events to match start event
+  var events = postStartEvents[ event.type ];
+  // bind events to node
+  events.forEach( function( eventName ) {
+    window.addEventListener( eventName, this );
+  }, this );
+  // save these arguments
+  this._boundPointerEvents = events;
+};
+
+proto._unbindPostStartEvents = function() {
+  // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
+  if ( !this._boundPointerEvents ) {
+    return;
+  }
+  this._boundPointerEvents.forEach( function( eventName ) {
+    window.removeEventListener( eventName, this );
+  }, this );
+
+  delete this._boundPointerEvents;
+};
+
+// ----- move event ----- //
+
+proto.onmousemove = function( event ) {
+  this._pointerMove( event, event );
+};
+
+proto.onMSPointerMove =
+proto.onpointermove = function( event ) {
+  if ( event.pointerId == this.pointerIdentifier ) {
+    this._pointerMove( event, event );
+  }
+};
+
+proto.ontouchmove = function( event ) {
+  var touch = this.getTouch( event.changedTouches );
+  if ( touch ) {
+    this._pointerMove( event, touch );
+  }
+};
+
+/**
+ * pointer move
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ * @private
+ */
+proto._pointerMove = function( event, pointer ) {
+  this.pointerMove( event, pointer );
+};
+
+// public
+proto.pointerMove = function( event, pointer ) {
+  this.emitEvent( 'pointerMove', [ event, pointer ] );
+};
+
+// ----- end event ----- //
+
+
+proto.onmouseup = function( event ) {
+  this._pointerUp( event, event );
+};
+
+proto.onMSPointerUp =
+proto.onpointerup = function( event ) {
+  if ( event.pointerId == this.pointerIdentifier ) {
+    this._pointerUp( event, event );
+  }
+};
+
+proto.ontouchend = function( event ) {
+  var touch = this.getTouch( event.changedTouches );
+  if ( touch ) {
+    this._pointerUp( event, touch );
+  }
+};
+
+/**
+ * pointer up
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ * @private
+ */
+proto._pointerUp = function( event, pointer ) {
+  this._pointerDone();
+  this.pointerUp( event, pointer );
+};
+
+// public
+proto.pointerUp = function( event, pointer ) {
+  this.emitEvent( 'pointerUp', [ event, pointer ] );
+};
+
+// ----- pointer done ----- //
+
+// triggered on pointer up & pointer cancel
+proto._pointerDone = function() {
+  // reset properties
+  this.isPointerDown = false;
+  delete this.pointerIdentifier;
+  // remove events
+  this._unbindPostStartEvents();
+  this.pointerDone();
+};
+
+proto.pointerDone = noop;
+
+// ----- pointer cancel ----- //
+
+proto.onMSPointerCancel =
+proto.onpointercancel = function( event ) {
+  if ( event.pointerId == this.pointerIdentifier ) {
+    this._pointerCancel( event, event );
+  }
+};
+
+proto.ontouchcancel = function( event ) {
+  var touch = this.getTouch( event.changedTouches );
+  if ( touch ) {
+    this._pointerCancel( event, touch );
+  }
+};
+
+/**
+ * pointer cancel
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ * @private
+ */
+proto._pointerCancel = function( event, pointer ) {
+  this._pointerDone();
+  this.pointerCancel( event, pointer );
+};
+
+// public
+proto.pointerCancel = function( event, pointer ) {
+  this.emitEvent( 'pointerCancel', [ event, pointer ] );
+};
+
+// -----  ----- //
+
+// utility function for getting x/y coords from event
+Unipointer.getPointerPoint = function( pointer ) {
+  return {
+    x: pointer.pageX,
+    y: pointer.pageY
+  };
+};
+
+// -----  ----- //
+
+return Unipointer;
+
+}));
+
+/*!
+ * Unidragger v2.1.0
+ * Draggable base class
+ * MIT license
+ */
+
+/*jshint browser: true, unused: true, undef: true, strict: true */
+
+( function( window, factory ) {
+  // universal module definition
+  /*jshint strict: false */ /*globals define, module, require */
+
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD
+    define( 'unidragger/unidragger',[
+      'unipointer/unipointer'
+    ], function( Unipointer ) {
+      return factory( window, Unipointer );
+    });
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS
+    module.exports = factory(
+      window,
+      require('unipointer')
+    );
+  } else {
+    // browser global
+    window.Unidragger = factory(
+      window,
+      window.Unipointer
+    );
+  }
+
+}( window, function factory( window, Unipointer ) {
+
+
+
+// -----  ----- //
+
+function noop() {}
+
+// -------------------------- Unidragger -------------------------- //
+
+function Unidragger() {}
+
+// inherit Unipointer & EvEmitter
+var proto = Unidragger.prototype = Object.create( Unipointer.prototype );
+
+// ----- bind start ----- //
+
+proto.bindHandles = function() {
+  this._bindHandles( true );
+};
+
+proto.unbindHandles = function() {
+  this._bindHandles( false );
+};
+
+var navigator = window.navigator;
+/**
+ * works as unbinder, as you can .bindHandles( false ) to unbind
+ * @param {Boolean} isBind - will unbind if falsey
+ */
+proto._bindHandles = function( isBind ) {
+  // munge isBind, default to true
+  isBind = isBind === undefined ? true : !!isBind;
+  // extra bind logic
+  var binderExtra;
+  if ( navigator.pointerEnabled ) {
+    binderExtra = function( handle ) {
+      // disable scrolling on the element
+      handle.style.touchAction = isBind ? 'none' : '';
+    };
+  } else if ( navigator.msPointerEnabled ) {
+    binderExtra = function( handle ) {
+      // disable scrolling on the element
+      handle.style.msTouchAction = isBind ? 'none' : '';
+    };
+  } else {
+    binderExtra = noop;
+  }
+  // bind each handle
+  var bindMethod = isBind ? 'addEventListener' : 'removeEventListener';
+  for ( var i=0; i < this.handles.length; i++ ) {
+    var handle = this.handles[i];
+    this._bindStartEvent( handle, isBind );
+    binderExtra( handle );
+    handle[ bindMethod ]( 'click', this );
+  }
+};
+
+// ----- start event ----- //
+
+/**
+ * pointer start
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerDown = function( event, pointer ) {
+  // dismiss range sliders
+  if ( event.target.nodeName == 'INPUT' && event.target.type == 'range' ) {
+    // reset pointerDown logic
+    this.isPointerDown = false;
+    delete this.pointerIdentifier;
+    return;
+  }
+
+  this._dragPointerDown( event, pointer );
+  // kludge to blur focused inputs in dragger
+  var focused = document.activeElement;
+  if ( focused && focused.blur ) {
+    focused.blur();
+  }
+  // bind move and end events
+  this._bindPostStartEvents( event );
+  this.emitEvent( 'pointerDown', [ event, pointer ] );
+};
+
+// base pointer down logic
+proto._dragPointerDown = function( event, pointer ) {
+  // track to see when dragging starts
+  this.pointerDownPoint = Unipointer.getPointerPoint( pointer );
+
+  var canPreventDefault = this.canPreventDefaultOnPointerDown( event, pointer );
+  if ( canPreventDefault ) {
+    event.preventDefault();
+  }
+};
+
+// overwriteable method so Flickity can prevent for scrolling
+proto.canPreventDefaultOnPointerDown = function( event ) {
+  // prevent default, unless touchstart or <select>
+  return event.target.nodeName != 'SELECT';
+};
+
+// ----- move event ----- //
+
+/**
+ * drag move
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerMove = function( event, pointer ) {
+  var moveVector = this._dragPointerMove( event, pointer );
+  this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
+  this._dragMove( event, pointer, moveVector );
+};
+
+// base pointer move logic
+proto._dragPointerMove = function( event, pointer ) {
+  var movePoint = Unipointer.getPointerPoint( pointer );
+  var moveVector = {
+    x: movePoint.x - this.pointerDownPoint.x,
+    y: movePoint.y - this.pointerDownPoint.y
+  };
+  // start drag if pointer has moved far enough to start drag
+  if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {
+    this._dragStart( event, pointer );
+  }
+  return moveVector;
+};
+
+// condition if pointer has moved far enough to start drag
+proto.hasDragStarted = function( moveVector ) {
+  return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
+};
+
+
+// ----- end event ----- //
+
+/**
+ * pointer up
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerUp = function( event, pointer ) {
+  this.emitEvent( 'pointerUp', [ event, pointer ] );
+  this._dragPointerUp( event, pointer );
+};
+
+proto._dragPointerUp = function( event, pointer ) {
+  if ( this.isDragging ) {
+    this._dragEnd( event, pointer );
+  } else {
+    // pointer didn't move enough for drag to start
+    this._staticClick( event, pointer );
+  }
+};
+
+// -------------------------- drag -------------------------- //
+
+// dragStart
+proto._dragStart = function( event, pointer ) {
+  this.isDragging = true;
+  this.dragStartPoint = Unipointer.getPointerPoint( pointer );
+  // prevent clicks
+  this.isPreventingClicks = true;
+
+  this.dragStart( event, pointer );
+};
+
+proto.dragStart = function( event, pointer ) {
+  this.emitEvent( 'dragStart', [ event, pointer ] );
+};
+
+// dragMove
+proto._dragMove = function( event, pointer, moveVector ) {
+  // do not drag if not dragging yet
+  if ( !this.isDragging ) {
+    return;
+  }
+
+  this.dragMove( event, pointer, moveVector );
+};
+
+proto.dragMove = function( event, pointer, moveVector ) {
+  event.preventDefault();
+  this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
+};
+
+// dragEnd
+proto._dragEnd = function( event, pointer ) {
+  // set flags
+  this.isDragging = false;
+  // re-enable clicking async
+  setTimeout( function() {
+    delete this.isPreventingClicks;
+  }.bind( this ) );
+
+  this.dragEnd( event, pointer );
+};
+
+proto.dragEnd = function( event, pointer ) {
+  this.emitEvent( 'dragEnd', [ event, pointer ] );
+};
+
+// ----- onclick ----- //
+
+// handle all clicks and prevent clicks when dragging
+proto.onclick = function( event ) {
+  if ( this.isPreventingClicks ) {
+    event.preventDefault();
+  }
+};
+
+// ----- staticClick ----- //
+
+// triggered after pointer down & up with no/tiny movement
+proto._staticClick = function( event, pointer ) {
+  // ignore emulated mouse up clicks
+  if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
+    return;
+  }
+
+  // allow click in <input>s and <textarea>s
+  var nodeName = event.target.nodeName;
+  if ( nodeName == 'INPUT' || nodeName == 'TEXTAREA' ) {
+    event.target.focus();
+  }
+  this.staticClick( event, pointer );
+
+  // set flag for emulated clicks 300ms after touchend
+  if ( event.type != 'mouseup' ) {
+    this.isIgnoringMouseUp = true;
+    // reset flag after 300ms
+    setTimeout( function() {
+      delete this.isIgnoringMouseUp;
+    }.bind( this ), 400 );
+  }
+};
+
+proto.staticClick = function( event, pointer ) {
+  this.emitEvent( 'staticClick', [ event, pointer ] );
+};
+
+// ----- utils ----- //
+
+Unidragger.getPointerPoint = Unipointer.getPointerPoint;
+
+// -----  ----- //
+
+return Unidragger;
+
+}));
+
+/*!
+ * Draggabilly v2.1.1
+ * Make that shiz draggable
+ * http://draggabilly.desandro.com
+ * MIT license
+ */
+
+/*jshint browser: true, strict: true, undef: true, unused: true */
+
+( function( window, factory ) {
+  // universal module definition
+  /* jshint strict: false */ /*globals define, module, require */
+  if ( typeof define == 'function' && define.amd ) {
+    // AMD
+    define( [
+        'get-size/get-size',
+        'unidragger/unidragger'
+      ],
+      function( getSize, Unidragger ) {
+        return factory( window, getSize, Unidragger );
+      });
+  } else if ( typeof module == 'object' && module.exports ) {
+    // CommonJS
+    module.exports = factory(
+      window,
+      require('get-size'),
+      require('unidragger')
+    );
+  } else {
+    // browser global
+    window.Draggabilly = factory(
+      window,
+      window.getSize,
+      window.Unidragger
+    );
+  }
+
+}( window, function factory( window, getSize, Unidragger ) {
+
+
+
+// vars
+var document = window.document;
+
+function noop() {}
+
+// -------------------------- helpers -------------------------- //
+
+// extend objects
+function extend( a, b ) {
+  for ( var prop in b ) {
+    a[ prop ] = b[ prop ];
+  }
+  return a;
+}
+
+function isElement( obj ) {
+  return obj instanceof HTMLElement;
+}
+
+// -------------------------- requestAnimationFrame -------------------------- //
+
+// get rAF, prefixed, if present
+var requestAnimationFrame = window.requestAnimationFrame ||
+  window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
+
+// fallback to setTimeout
+var lastTime = 0;
+if ( !requestAnimationFrame )  {
+  requestAnimationFrame = function( callback ) {
+    var currTime = new Date().getTime();
+    var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
+    var id = setTimeout( callback, timeToCall );
+    lastTime = currTime + timeToCall;
+    return id;
+  };
+}
+
+// -------------------------- support -------------------------- //
+
+var docElem = document.documentElement;
+var transformProperty = typeof docElem.style.transform == 'string' ?
+  'transform' : 'WebkitTransform';
+
+var jQuery = window.jQuery;
+
+// --------------------------  -------------------------- //
+
+function Draggabilly( element, options ) {
+  // querySelector if string
+  this.element = typeof element == 'string' ?
+    document.querySelector( element ) : element;
+
+  if ( jQuery ) {
+    this.$element = jQuery( this.element );
+  }
+
+  // options
+  this.options = extend( {}, this.constructor.defaults );
+  this.option( options );
+
+  this._create();
+}
+
+// inherit Unidragger methods
+var proto = Draggabilly.prototype = Object.create( Unidragger.prototype );
+
+Draggabilly.defaults = {
+};
+
+/**
+ * set options
+ * @param {Object} opts
+ */
+proto.option = function( opts ) {
+  extend( this.options, opts );
+};
+
+// css position values that don't need to be set
+var positionValues = {
+  relative: true,
+  absolute: true,
+  fixed: true
+};
+
+proto._create = function() {
+
+  // properties
+  this.position = {};
+  this._getPosition();
+
+  this.startPoint = { x: 0, y: 0 };
+  this.dragPoint = { x: 0, y: 0 };
+
+  this.startPosition = extend( {}, this.position );
+
+  // set relative positioning
+  var style = getComputedStyle( this.element );
+  if ( !positionValues[ style.position ] ) {
+    this.element.style.position = 'fixed';
+  }
+
+  this.enable();
+  this.setHandles();
+
+};
+
+/**
+ * set this.handles and bind start events to 'em
+ */
+proto.setHandles = function() {
+  this.handles = this.options.handle ?
+    this.element.querySelectorAll( this.options.handle ) : [ this.element ];
+
+  this.bindHandles();
+};
+
+/**
+ * emits events via EvEmitter and jQuery events
+ * @param {String} type - name of event
+ * @param {Event} event - original event
+ * @param {Array} args - extra arguments
+ */
+proto.dispatchEvent = function( type, event, args ) {
+  var emitArgs = [ event ].concat( args );
+  this.emitEvent( type, emitArgs );
+  var jQuery = window.jQuery;
+  // trigger jQuery event
+  if ( jQuery && this.$element ) {
+    if ( event ) {
+      // create jQuery event
+      var $event = jQuery.Event( event );
+      $event.type = type;
+      this.$element.trigger( $event, args );
+    } else {
+      // just trigger with type if no event available
+      this.$element.trigger( type, args );
+    }
+  }
+};
+
+// -------------------------- position -------------------------- //
+
+// get x/y position from style
+proto._getPosition = function() {
+  var style = getComputedStyle( this.element );
+  var x = this._getPositionCoord( style.left, 'width' );
+  var y = this._getPositionCoord( style.top, 'height' );
+  // clean up 'auto' or other non-integer values
+  this.position.x = isNaN( x ) ? 0 : x;
+  this.position.y = isNaN( y ) ? 0 : y;
+
+  this._addTransformPosition( style );
+};
+
+proto._getPositionCoord = function( styleSide, measure ) {
+  if ( styleSide.indexOf('%') != -1 ) {
+    // convert percent into pixel for Safari, #75
+    var parentSize = getSize( this.element.parentNode );
+    // prevent not-in-DOM element throwing bug, #131
+    return !parentSize ? 0 :
+      ( parseFloat( styleSide ) / 100 ) * parentSize[ measure ];
+  }
+  return parseInt( styleSide, 10 );
+};
+
+// add transform: translate( x, y ) to position
+proto._addTransformPosition = function( style ) {
+  var transform = style[ transformProperty ];
+  // bail out if value is 'none'
+  if ( transform.indexOf('matrix') !== 0 ) {
+    return;
+  }
+  // split matrix(1, 0, 0, 1, x, y)
+  var matrixValues = transform.split(',');
+  // translate X value is in 12th or 4th position
+  var xIndex = transform.indexOf('matrix3d') === 0 ? 12 : 4;
+  var translateX = parseInt( matrixValues[ xIndex ], 10 );
+  // translate Y value is in 13th or 5th position
+  var translateY = parseInt( matrixValues[ xIndex + 1 ], 10 );
+  this.position.x += translateX;
+  this.position.y += translateY;
+};
+
+// -------------------------- events -------------------------- //
+
+/**
+ * pointer start
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerDown = function( event, pointer ) {
+  this._dragPointerDown( event, pointer );
+  // kludge to blur focused inputs in dragger
+  var focused = document.activeElement;
+  // do not blur body for IE10, metafizzy/flickity#117
+  if ( focused && focused.blur && focused != document.body ) {
+    focused.blur();
+  }
+  // bind move and end events
+  this._bindPostStartEvents( event );
+  this.element.classList.add('is-pointer-down');
+  this.dispatchEvent( 'pointerDown', event, [ pointer ] );
+};
+
+/**
+ * drag move
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerMove = function( event, pointer ) {
+  var moveVector = this._dragPointerMove( event, pointer );
+  this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );
+  this._dragMove( event, pointer, moveVector );
+};
+
+/**
+ * drag start
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.dragStart = function( event, pointer ) {
+  if ( !this.isEnabled ) {
+    return;
+  }
+  this._getPosition();
+  this.measureContainment();
+  // position _when_ drag began
+  this.startPosition.x = this.position.x;
+  this.startPosition.y = this.position.y;
+  // reset left/top style
+  this.setLeftTop();
+
+  this.dragPoint.x = 0;
+  this.dragPoint.y = 0;
+
+  this.element.classList.add('is-dragging');
+  this.dispatchEvent( 'dragStart', event, [ pointer ] );
+  // start animation
+  this.animate();
+};
+
+proto.measureContainment = function() {
+  var containment = this.options.containment;
+  if ( !containment ) {
+    return;
+  }
+
+  // use element if element
+  var container = isElement( containment ) ? containment :
+    // fallback to querySelector if string
+    typeof containment == 'string' ? document.querySelector( containment ) :
+    // otherwise just `true`, use the parent
+    this.element.parentNode;
+
+  var elemSize = getSize( this.element );
+  var containerSize = getSize( container );
+  var elemRect = this.element.getBoundingClientRect();
+  var containerRect = container.getBoundingClientRect();
+
+  var borderSizeX = containerSize.borderLeftWidth + containerSize.borderRightWidth;
+  var borderSizeY = containerSize.borderTopWidth + containerSize.borderBottomWidth;
+
+  var position = this.relativeStartPosition = {
+    x: elemRect.left - ( containerRect.left + containerSize.borderLeftWidth ),
+    y: elemRect.top - ( containerRect.top + containerSize.borderTopWidth )
+  };
+
+  this.containSize = {
+    width: ( containerSize.width - borderSizeX ) - position.x - elemSize.width,
+    height: ( containerSize.height - borderSizeY ) - position.y - elemSize.height
+  };
+};
+
+// ----- move event ----- //
+
+/**
+ * drag move
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.dragMove = function( event, pointer, moveVector ) {
+  if ( !this.isEnabled ) {
+    return;
+  }
+  var dragX = moveVector.x;
+  var dragY = moveVector.y;
+
+  var grid = this.options.grid;
+  var gridX = grid && grid[0];
+  var gridY = grid && grid[1];
+
+  dragX = applyGrid( dragX, gridX );
+  dragY = applyGrid( dragY, gridY );
+
+  dragX = this.containDrag( 'x', dragX, gridX );
+  dragY = this.containDrag( 'y', dragY, gridY );
+
+  // constrain to axis
+  dragX = this.options.axis == 'y' ? 0 : dragX;
+  dragY = this.options.axis == 'x' ? 0 : dragY;
+
+  this.position.x = this.startPosition.x + dragX;
+  this.position.y = this.startPosition.y + dragY;
+  // set dragPoint properties
+  this.dragPoint.x = dragX;
+  this.dragPoint.y = dragY;
+
+  this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );
+};
+
+function applyGrid( value, grid, method ) {
+  method = method || 'round';
+  return grid ? Math[ method ]( value / grid ) * grid : value;
+}
+
+proto.containDrag = function( axis, drag, grid ) {
+  if ( !this.options.containment ) {
+    return drag;
+  }
+  var measure = axis == 'x' ? 'width' : 'height';
+
+  var rel = this.relativeStartPosition[ axis ];
+  var min = applyGrid( -rel, grid, 'ceil' );
+  var max = this.containSize[ measure ];
+  max = applyGrid( max, grid, 'floor' );
+  return  Math.min( max, Math.max( min, drag ) );
+};
+
+// ----- end event ----- //
+
+/**
+ * pointer up
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.pointerUp = function( event, pointer ) {
+  this.element.classList.remove('is-pointer-down');
+  this.dispatchEvent( 'pointerUp', event, [ pointer ] );
+  this._dragPointerUp( event, pointer );
+};
+
+/**
+ * drag end
+ * @param {Event} event
+ * @param {Event or Touch} pointer
+ */
+proto.dragEnd = function( event, pointer ) {
+  if ( !this.isEnabled ) {
+    return;
+  }
+  // use top left position when complete
+  if ( transformProperty ) {
+    this.element.style[ transformProperty ] = '';
+    this.setLeftTop();
+  }
+  this.element.classList.remove('is-dragging');
+  this.dispatchEvent( 'dragEnd', event, [ pointer ] );
+};
+
+// -------------------------- animation -------------------------- //
+
+proto.animate = function() {
+  // only render and animate if dragging
+  if ( !this.isDragging ) {
+    return;
+  }
+
+  this.positionDrag();
+
+  var _this = this;
+  requestAnimationFrame( function animateFrame() {
+    _this.animate();
+  });
+
+};
+
+// left/top positioning
+proto.setLeftTop = function() {
+  this.element.style.left = this.position.x + 'px';
+  this.element.style.top  = this.position.y + 'px';
+};
+
+proto.positionDrag = function() {
+  this.element.style[ transformProperty ] = 'translate3d( ' + this.dragPoint.x +
+    'px, ' + this.dragPoint.y + 'px, 0)';
+};
+
+// ----- staticClick ----- //
+
+proto.staticClick = function( event, pointer ) {
+  this.dispatchEvent( 'staticClick', event, [ pointer ] );
+};
+
+// ----- methods ----- //
+
+proto.enable = function() {
+  this.isEnabled = true;
+};
+
+proto.disable = function() {
+  this.isEnabled = false;
+  if ( this.isDragging ) {
+    this.dragEnd();
+  }
+};
+
+proto.destroy = function() {
+  this.disable();
+  // reset styles
+  this.element.style[ transformProperty ] = '';
+  this.element.style.left = '';
+  this.element.style.top = '';
+  this.element.style.position = '';
+  // unbind handles
+  this.unbindHandles();
+  // remove jQuery data
+  if ( this.$element ) {
+    this.$element.removeData('draggabilly');
+  }
+};
+
+// ----- jQuery bridget ----- //
+
+// required for jQuery bridget
+proto._init = noop;
+
+if ( jQuery && jQuery.bridget ) {
+  jQuery.bridget( 'draggabilly', Draggabilly );
+}
+
+// -----  ----- //
+
+return Draggabilly;
+
+}));
+

+ 41 - 1
support/client/lib/vwf/view/lib/editorLive.css

@@ -38,4 +38,44 @@
 
   /* Support for IE. */
   font-feature-settings: 'liga';
-}
+}
+
+ /*
+.mdc-persistent-drawer--open {
+
+    width: 300px;  
+    
+}
+
+.mdc-persistent-drawer__drawer {
+
+  width: 300px;  
+
+}
+*/
+
+.mdc-theme--accent {
+
+  color: #2E7D32;
+
+}
+
+.draggable {
+  top: 200px;
+  left: 400px;
+    z-index: 4;
+    background-color: rgba(255, 255, 255, 1);
+  }
+  
+  .draggable.is-pointer-down {
+    background: #999FA4;
+  }
+  .draggable.is-dragging { opacity: 0.9; }
+  
+  .handle {
+    background: #555;
+    background: rgba(132, 141, 132, 0.80);
+    width: 100%;
+  }
+  
+