JAVASCRIPT   24

dnd

Guest on 6th August 2022 01:07:53 AM

  1. // webkitdragdrop.js v1.0,
  2. //
  3. // Copyright (c) Tommaso Buvoli (http://www.tommasobuvoli.com)
  4. // No Extra Libraries are required, simply download this file, add it to your pages!
  5. //
  6. // To See this library in action, grab an ipad and head over to http://www.gotproject.com
  7. // webkitdragdrop is freely distributable under the terms of an MIT-style license.
  8.  
  9.  
  10. //Description
  11. // Because this library was designed to run without requiring any other libraries, several basic helper functions were implemented
  12. // 6 helper functons in this webkit_tools class have been taked directly from Prototype 1.6.1 (http://prototypejs.org/) (c) 2005-2009 Sam Stephenson
  13.  
  14. var webkit_tools =
  15. {
  16.     //$ function - simply a more robust getElementById
  17.  
  18.     $:function(e)
  19.     {
  20.         if(typeof(e) == 'string')
  21.         {
  22.             return document.getElementById(e);
  23.         }
  24.         return e;
  25.     },
  26.  
  27.     //extend function - copies the values of b into a (Shallow copy)
  28.  
  29.     extend:function(a,b)
  30.     {
  31.         for (var key in b)
  32.         {
  33.             a[key] = b[key];
  34.         }
  35.         return a;
  36.     },
  37.  
  38.     //empty function - used as defaut for events
  39.  
  40.     empty:function()
  41.     {
  42.  
  43.     },
  44.  
  45.     //remove null values from an array
  46.  
  47.     compact:function(a)
  48.     {
  49.         var b = []
  50.         var l = a.length;
  51.         for(var i = 0; i < l; i ++)
  52.         {
  53.             if(a[i] !== null)
  54.             {
  55.                 b.push(a[i]);
  56.             }
  57.         }
  58.         return b;
  59.     },
  60.  
  61.     //DESCRIPTION
  62.     //    This function was taken from the internet (http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/) and returns
  63.     //    the computed style of an element independantly from the browser
  64.     //INPUT
  65.     //    oELM (DOM ELEMENT) element whose style should be extracted
  66.     //    strCssRule element
  67.  
  68.     getCalculatedStyle:function(oElm, strCssRule)
  69.     {
  70.         var strValue = "";
  71.         if(document.defaultView && document.defaultView.getComputedStyle){
  72.             strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
  73.         }
  74.         else if(oElm.currentStyle){
  75.             strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
  76.                 return p1.toUpperCase();
  77.             });
  78.             strValue = oElm.currentStyle[strCssRule];
  79.         }
  80.         return strValue;
  81.     },
  82.  
  83.     //bindAsEventListener function - used to bind events
  84.  
  85.     bindAsEventListener:function(f,object)
  86.     {
  87.         var __method = f;
  88.         return function(event) {
  89.             __method.call(object, event || window.event);
  90.         };
  91.     },
  92.  
  93.     //cumulative offset - courtesy of Prototype (http://www.prototypejs.org)
  94.  
  95.     cumulativeOffset:function(element)
  96.     {
  97.         var valueT = 0, valueL = 0;
  98.         do {
  99.           valueT += element.offsetTop  || 0;
  100.           valueL += element.offsetLeft || 0;
  101.           if (element.offsetParent == document.body)
  102.             if (element.style.position == 'absolute') break;
  103.  
  104.           element = element.offsetParent;
  105.         } while (element);
  106.  
  107.         return {left : valueL, top : valueT};
  108.       },
  109.  
  110.       //getDimensions - courtesy of Prototype (http://www.prototypejs.org)
  111.  
  112.     getDimensions: function(element)
  113.     {
  114.         var display = element.style.display;
  115.         if (display != 'none' && display != null) // Safari bug
  116.           return {width: element.offsetWidth, height: element.offsetHeight};
  117.  
  118.         var els = element.style;
  119.         var originalVisibility = els.visibility;
  120.         var originalPosition = els.position;
  121.         var originalDisplay = els.display;
  122.         els.visibility = 'hidden';
  123.         if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
  124.           els.position = 'absolute';
  125.         els.display = 'block';
  126.         var originalWidth = element.clientWidth;
  127.         var originalHeight = element.clientHeight;
  128.         els.display = originalDisplay;
  129.         els.position = originalPosition;
  130.         els.visibility = originalVisibility;
  131.         return {width: originalWidth, height: originalHeight};
  132.     },
  133.  
  134.     //hasClassName - courtesy of Prototype (http://www.prototypejs.org)
  135.  
  136.     hasClassName: function(element, className)
  137.     {
  138.         var elementClassName = element.className;
  139.         return (elementClassName.length > 0 && (elementClassName == className ||
  140.         new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
  141.       },
  142.  
  143.     //addClassName - courtesy of Prototype (http://www.prototypejs.org)
  144.  
  145.     addClassName: function(element, className)
  146.     {
  147.         if (!this.hasClassName(element, className))
  148.             element.className += (element.className ? ' ' : '') + className;
  149.         return element;
  150.     },
  151.  
  152.     //removeClassName - courtesy of Prototype (http://www.prototypejs.org)
  153.  
  154.     removeClassName: function(element, className)
  155.     {
  156.         element.className = this.strip(element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' '));
  157.         return element;
  158.     },
  159.  
  160.     //strip - courtesy of Prototype (http://www.prototypejs.org)
  161.  
  162.     strip:function(s)
  163.     {
  164.         return s.replace(/^\s+/, '').replace(/\s+$/, '');
  165.     }
  166.  
  167. }
  168.  
  169. //Description
  170. // Droppable fire events when a draggable is dropped on them
  171.  
  172. var webkit_droppables = function()
  173. {
  174.     this.initialize = function()
  175.     {
  176.         this.droppables = [];
  177.         this.droppableRegions = [];
  178.     }
  179.  
  180.     this.add = function(root, instance_props)
  181.     {
  182.         root = webkit_tools.$(root);
  183.         var default_props = {accept : [], hoverClass : null, onDrop : webkit_tools.empty, onOver : webkit_tools.empty, onOut : webkit_tools.empty};
  184.         default_props = webkit_tools.extend(default_props, instance_props || {});
  185.         this.droppables.push({r : root, p : default_props});
  186.     }
  187.  
  188.     this.remove = function(root)
  189.     {
  190.         root = webkit_tools.$(root);
  191.         var d = this.droppables;
  192.         var i = d.length;
  193.         while(i--)
  194.         {
  195.             if(d[i].r == root)
  196.             {
  197.                 d[i] = null;
  198.                 this.droppables = webkit_tools.compact(d);
  199.                 return true;
  200.             }
  201.         }
  202.         return false;
  203.     }
  204.  
  205.     //calculate position and size of all droppables
  206.  
  207.     this.prepare = function()
  208.     {
  209.         var d = this.droppables;
  210.         var i = d.length;
  211.         var dR = [];
  212.         var r = null;
  213.  
  214.         while(i--)
  215.         {
  216.             r = d[i].r;
  217.             if(r.style.display != 'none')
  218.             {
  219.                 dR.push({i : i, size : webkit_tools.getDimensions(r), offset : webkit_tools.cumulativeOffset(r)})
  220.             }
  221.         }
  222.  
  223.         this.droppableRegions = dR;
  224.     }
  225.  
  226.     this.finalize = function(x,y,r,e)
  227.     {
  228.         var indices = this.isOver(x,y);
  229.         var index = this.maxZIndex(indices);
  230.         var over = this.process(index,r);
  231.         if(over)
  232.         {
  233.             this.drop(index, r,e);
  234.         }
  235.         this.process(-1,r);
  236.         return over;
  237.     }
  238.  
  239.     this.check = function(x,y,r,e)
  240.     {
  241.         var indices = this.isOver(x,y);
  242.         var index = this.maxZIndex(indices);
  243.         return this.process(index,r, e);
  244.     }
  245.  
  246.     this.isOver = function(x, y)
  247.     {
  248.         var dR = this.droppableRegions;
  249.         var i = dR.length;
  250.         var active = [];
  251.         var r = 0;
  252.         var maxX = 0;
  253.         var minX = 0;
  254.         var maxY = 0;
  255.         var minY = 0;
  256.  
  257.         while(i--)
  258.         {
  259.             r = dR[i];
  260.  
  261.             minY = r.offset.top;
  262.             maxY = minY + r.size.height;
  263.  
  264.             if((y > minY) && (y < maxY))
  265.             {
  266.                 minX = r.offset.left;
  267.                 maxX = minX + r.size.width;
  268.  
  269.                 if((x > minX) && (x < maxX))
  270.                 {
  271.                     active.push(r.i);
  272.                 }
  273.             }
  274.         }
  275.  
  276.         return active;
  277.     }
  278.  
  279.     this.maxZIndex = function(indices)
  280.     {
  281.         var d = this.droppables;
  282.         var l = indices.length;
  283.         var index = -1;
  284.  
  285.         var maxZ = -100000000;
  286.         var curZ = 0;
  287.  
  288.         while(l--)
  289.         {
  290.             curZ = parseInt(d[indices[l]].r.style.zIndex || 0);
  291.             if(curZ > maxZ)
  292.             {
  293.                 maxZ = curZ;
  294.                 index = indices[l];
  295.             }
  296.         }
  297.  
  298.         return index;
  299.     }
  300.  
  301.     this.process = function(index, draggableRoot, e)
  302.     {
  303.         //only perform update if a change has occured
  304.         if(this.lastIndex != index)
  305.         {
  306.             //remove previous
  307.             if(this.lastIndex != null)
  308.             {
  309.                 var d = this.droppables[this.lastIndex]
  310.                 var p = d.p;
  311.                 var r = d.r;
  312.  
  313.                 if(p.hoverClass)
  314.                 {
  315.                     webkit_tools.removeClassName(r,p.hoverClass);
  316.                 }
  317.                 p.onOut(draggableRoot, e);
  318.                 this.lastIndex = null;
  319.                 this.lastOutput = false;
  320.             }
  321.  
  322.             //add new
  323.             if(index != -1)
  324.             {
  325.                 var d = this.droppables[index]
  326.                 var p = d.p;
  327.                 var r = d.r;
  328.  
  329.                 if(this.hasClassNames(draggableRoot, p.accept))
  330.                 {
  331.                     if(p.hoverClass)
  332.                     {
  333.                         webkit_tools.addClassName(r,p.hoverClass);
  334.                     }
  335.                     p.onOver(draggableRoot, e);
  336.                     this.lastIndex = index;
  337.                     this.lastOutput = true;
  338.                 }
  339.             }
  340.         }
  341.         return this.lastOutput;
  342.     }
  343.  
  344.     this.drop = function(index, r, e)
  345.     {
  346.         if(index != -1)
  347.         {
  348.             this.droppables[index].p.onDrop(r,e);
  349.         }
  350.     }
  351.  
  352.     this.hasClassNames = function(r, names)
  353.     {
  354.         var l = names.length;
  355.         if(l == 0){return true}
  356.         while(l--)
  357.         {
  358.             if(webkit_tools.hasClassName(r,names[l]))
  359.             {
  360.                 return true;
  361.             }
  362.         }
  363.         return false;
  364.     }
  365.  
  366.     this.initialize();
  367. }
  368.  
  369. webkit_drop = new webkit_droppables();
  370.  
  371. //Description
  372. //webkit draggable - allows users to drag elements with their hands
  373.  
  374. var webkit_draggable = function(r, ip)
  375. {
  376.     this.ready = false;
  377.     this.timeout = undefined;
  378.     this.initialize = function(root, instance_props)
  379.     {
  380.         this.root = webkit_tools.$(root);
  381.         var default_props = {scroll : false, revert : false, handle : this.root, zIndex : 1000, onStart : webkit_tools.empty, onEnd : webkit_tools.empty};
  382.  
  383.         this.p = webkit_tools.extend(default_props, instance_props || {});
  384.         default_props.handle = webkit_tools.$(default_props.handle);
  385.         this.prepare();
  386.         this.bindEvents();
  387.     }
  388.  
  389.     this.prepare = function()
  390.     {
  391.         var rs = this.root.style;
  392.  
  393.         //set position
  394.         if(webkit_tools.getCalculatedStyle(this.root,'position') != 'absolute')
  395.         {
  396.             rs.position = 'relative';
  397.         }
  398.  
  399.         //set top, right, bottom, left
  400.         rs.top = rs.top || '0px';
  401.         rs.left = rs.left || '0px';
  402.         rs.right = "";
  403.         rs.bottom = "";
  404.  
  405.         //set zindex;
  406.         rs.zIndex = rs.zIndex || '0';
  407.     }
  408.  
  409.     this.bindEvents = function()
  410.     {
  411.         var handle = this.p.handle;
  412.  
  413.         this.ts = webkit_tools.bindAsEventListener(this.touchStart, this);
  414.         this.tm = webkit_tools.bindAsEventListener(this.touchMove, this);
  415.         this.te = webkit_tools.bindAsEventListener(this.touchEnd, this);
  416.  
  417.         handle.addEventListener("touchstart", this.ts, false);
  418.         handle.addEventListener("touchmove", this.tm, false);
  419.         handle.addEventListener("touchend", this.te, false);
  420.     }
  421.  
  422.     this.destroy = function()
  423.     {
  424.         var handle = this.p.handle;
  425.  
  426.         handle.removeEventListener("touchstart", this.ts);
  427.         handle.removeEventListener("touchmove", this.tm);
  428.         handle.removeEventListener("touchend", this.te);
  429.     }
  430.  
  431.     this.set = function(key, value)
  432.     {
  433.         this.p[key] = value;
  434.     }
  435.  
  436.     this.touchStart = function(event)
  437.     {
  438.         this.timeout = setTimeout(function () {
  439.             //prepare needed variables
  440.             var p = this.p;
  441.             var r = this.root;
  442.             var rs = r.style;
  443.             var t = event.targetTouches[0];
  444.  
  445.             //get position of touch
  446.             touchX = t.pageX;
  447.             touchY = t.pageY;
  448.  
  449.             //set base values for position of root
  450.             rs.top = this.root.style.top || '0px';
  451.             rs.left = this.root.style.left || '0px';
  452.             rs.bottom = null;
  453.             rs.right = null;
  454.  
  455.             var rootP = webkit_tools.cumulativeOffset(r);
  456.             var cp = this.getPosition();
  457.  
  458.             //save event properties
  459.             p.rx = cp.x;
  460.             p.ry = cp.y;
  461.             p.tx = touchX;
  462.             p.ty = touchY;
  463.             p.z = parseInt(this.root.style.zIndex);
  464.  
  465.             //boost zIndex
  466.             rs.zIndex = p.zIndex;
  467.             webkit_drop.prepare();
  468.             p.onStart(r, event);
  469.            
  470.             this.ready = true;
  471.            
  472.         }.bind(this), 500);
  473.     }
  474.  
  475.     this.touchMove = function(event)
  476.     {
  477.         if ( this.ready ) {
  478.             event.preventDefault();
  479.             event.stopPropagation();
  480.  
  481.             //prepare needed variables
  482.             var p = this.p;
  483.             var r = this.root;
  484.             var rs = r.style;
  485.             var t = event.targetTouches[0];
  486.             if(t == null){return}
  487.  
  488.             var curX = t.pageX;
  489.             var curY = t.pageY;
  490.  
  491.             var delX = curX - p.tx;
  492.             var delY = curY - p.ty;
  493.  
  494.             rs.webkitTransform = 'translate3d(' + (p.rx + delX) + 'px,' + (p.ry + delY) + 'px, 1px)';
  495.  
  496.             //scroll window
  497.             if(p.scroll)
  498.             {
  499.                 s = this.getScroll(curX, curY);
  500.                 if((s[0] != 0) || (s[1] != 0))
  501.                 {
  502.                     window.scrollTo(window.scrollX + s[0], window.scrollY + s[1]);
  503.                 }
  504.             }
  505.  
  506.             //check droppables
  507.             webkit_drop.check(curX, curY, r, event);
  508.  
  509.             //save position for touchEnd
  510.             this.lastCurX = curX;
  511.             this.lastCurY = curY;
  512.         }
  513.     }
  514.  
  515.     this.touchEnd = function(event)
  516.     {
  517.         clearTimeout(this.timeout);
  518.         if ( this.ready ) {
  519.             event.preventSwipe = true;
  520.             var r = this.root;
  521.             var p = this.p;
  522.             var dropped = webkit_drop.finalize(this.lastCurX, this.lastCurY, r, event);
  523.  
  524.             if(((p.revert) && (!dropped)) || (p.revert === 'always'))
  525.             {
  526.                 //revert root
  527.                 var rs = r.style;
  528.                 rs.webkitTransform = 'translate3d(' + p.rx + 'px,' + p.ry + 'px, 1px)';
  529.                 //rs.top = (p.ry + 'px');
  530.                 //rs.left = (p.rx + 'px');
  531.             }
  532.  
  533.             r.style.zIndex = this.p.z;
  534.             this.p.onEnd(r, event);
  535.             this.ready = false;
  536.         }
  537.     }
  538.  
  539.     this.getPosition = function()
  540.     {
  541.         var rs = this.root.style;
  542.         return {x : parseInt(rs.left || 0), y : parseInt(rs.top  || 0)}
  543.     }
  544.  
  545.     this.getScroll = function(pX, pY)
  546.     {
  547.         //read window variables
  548.         var sX = window.scrollX;
  549.         var sY = window.scrollY;
  550.  
  551.         var wX = window.innerWidth;
  552.         var wY = window.innerHeight;
  553.  
  554.         //set contants
  555.         var scroll_amount = 10; //how many pixels to scroll
  556.         var scroll_sensitivity = 100; //how many pixels from border to start scrolling from.
  557.  
  558.         var delX = 0;
  559.         var delY = 0;
  560.  
  561.         //process vertical y scroll
  562.         if(pY - sY < scroll_sensitivity)
  563.         {
  564.             delY = -scroll_amount;
  565.         }
  566.         else
  567.         if((sY + wY) - pY < scroll_sensitivity)
  568.         {
  569.             delY = scroll_amount;
  570.         }
  571.  
  572.         //process horizontal x scroll
  573.         if(pX - sX < scroll_sensitivity)
  574.         {
  575.             delX = -scroll_amount;
  576.         }
  577.         else
  578.         if((sX + wX) - pX < scroll_sensitivity)
  579.         {
  580.             delX = scroll_amount;
  581.         }
  582.  
  583.         return [delX, delY]
  584.     }
  585.  
  586.     //contructor
  587.     this.initialize(r, ip);
  588. }
  589.  
  590. //Description
  591. //webkit_click class. manages click events for draggables
  592.  
  593. var webkit_click = function(r, ip)
  594. {
  595.     this.initialize = function(root, instance_props)
  596.     {
  597.         var default_props = {onClick : webkit_tools.empty};
  598.  
  599.         this.root = webkit_tools.$(root);
  600.         this.p = webkit_tools.extend(default_props, instance_props || {});
  601.         this.bindEvents();
  602.     }
  603.  
  604.     this.bindEvents = function()
  605.     {
  606.         var root = this.root;
  607.  
  608.         //bind events to local scope
  609.         this.ts = webkit_tools.bindAsEventListener(this.touchStart,this);
  610.         this.tm = webkit_tools.bindAsEventListener(this.touchMove,this);
  611.         this.te = webkit_tools.bindAsEventListener(this.touchEnd,this);
  612.  
  613.         //add Listeners
  614.         root.addEventListener("touchstart", this.ts, false);
  615.         root.addEventListener("touchmove", this.tm, false);
  616.         root.addEventListener("touchend", this.te, false);
  617.  
  618.         this.bound = true;
  619.     }
  620.  
  621.     this.touchStart = function()
  622.     {
  623.         this.moved = false;
  624.         if(this.bound == false)
  625.         {
  626.             this.root.addEventListener("touchmove", this.tm, false);
  627.             this.bound = true;
  628.         }
  629.     }
  630.  
  631.     this.touchMove = function()
  632.     {
  633.         this.moved = true;
  634.         this.root.removeEventListener("touchmove", this.tm);
  635.         this.bound = false;
  636.     }
  637.  
  638.     this.touchEnd = function()
  639.     {e.preventSwipe = true;
  640.         if(this.moved == false)
  641.         {
  642.             this.p.onClick();
  643.         }
  644.     }
  645.  
  646.     this.setEvent = function(f)
  647.     {
  648.         if(typeof(f) == 'function')
  649.         {
  650.             this.p.onClick = f;
  651.         }
  652.     }
  653.  
  654.     this.unbind = function()
  655.     {
  656.         var root = this.root;
  657.         root.removeEventListener("touchstart", this.ts);
  658.         root.removeEventListener("touchmove", this.tm);
  659.         root.removeEventListener("touchend", this.te);
  660.     }
  661.  
  662.     //call constructor
  663.     this.initialize(r, ip);
  664. }

Raw Paste


Login or Register to edit or fork this paste. It's free.