JAVASCRIPT   79

floating quickmenu js

Guest on 21st June 2022 02:09:11 AM

  1. var floatingMenu =
  2. {
  3.     hasInner: typeof(window.innerWidth) == 'number',
  4.     hasElement: typeof(document.documentElement) == 'object'
  5.         && typeof(document.documentElement.clientWidth) == 'number'};
  6.  
  7. var floatingArray =
  8. [
  9. ];
  10.  
  11. floatingMenu.add = function(obj, options)
  12. {
  13.     var name;
  14.     var menu;
  15.  
  16.     if (typeof(obj) === "string")
  17.         name = obj;
  18.     else
  19.         menu = obj;
  20.        
  21.  
  22.     if (options == undefined)
  23.     {
  24.         floatingArray.push(
  25.             {
  26.                 id: name,
  27.                 menu: menu,
  28.  
  29.                 targetLeft: 0,
  30.                 targetTop: 0,
  31.  
  32.                 distance: .07,
  33.                 snap: true,
  34.                 updateParentHeight: false
  35.             });
  36.     }
  37.     else
  38.     {
  39.         floatingArray.push(
  40.             {
  41.                 id: name,
  42.                 menu: menu,
  43.  
  44.                 targetLeft: options.targetLeft,
  45.                 targetRight: options.targetRight,
  46.                 targetTop: options.targetTop,
  47.                 targetBottom: options.targetBottom,
  48.  
  49.                 centerX: options.centerX,
  50.                 centerY: options.centerY,
  51.  
  52.                 prohibitXMovement: options.prohibitXMovement,
  53.                 prohibitYMovement: options.prohibitYMovement,
  54.  
  55.                 distance: options.distance != undefined ? options.distance : .07,
  56.                 snap: options.snap,
  57.                 ignoreParentDimensions: options.ignoreParentDimensions,
  58.                 updateParentHeight:
  59.                     options.updateParentHeight == undefined
  60.                     ? false
  61.                     : options.updateParentHeight,
  62.  
  63.                 scrollContainer: options.scrollContainer,
  64.                 scrollContainerId: options.scrollContainerId,
  65.  
  66.                 confinementArea: options.confinementArea,
  67.  
  68.                 confinementAreaId:
  69.                     options.confinementArea != undefined
  70.                     && options.confinementArea.substring(0, 1) == '#'
  71.                     ? options.confinementArea.substring(1)
  72.                     : undefined,
  73.  
  74.                 confinementAreaClassRegexp:
  75.                     options.confinementArea != undefined
  76.                     && options.confinementArea.substring(0, 1) == '.'
  77.                     ? new RegExp("(^|\\s)" + options.confinementArea.substring(1) + "(\\s|$)")
  78.                     : undefined
  79.             });
  80.     }
  81. };
  82.  
  83. floatingMenu.findSingle = function(item)
  84. {
  85.     if (item.id)
  86.         item.menu = document.getElementById(item.id);
  87.  
  88.     if (item.scrollContainerId)
  89.         item.scrollContainer = document.getElementById(item.scrollContainerId);
  90. };
  91.  
  92. floatingMenu.move = function (item)
  93. {
  94.     if (!item.prohibitXMovement)
  95.     {
  96.         item.menu.style.left = item.nextX + 'px';
  97.         item.menu.style.right = '';
  98.     }
  99.  
  100.     if (!item.prohibitYMovement)
  101.     {
  102.         item.menu.style.top = item.nextY + 'px';
  103.         item.menu.style.bottom = '';
  104.     }
  105. };
  106.  
  107. floatingMenu.scrollLeft = function(item)
  108. {
  109.     // If floating within scrollable container use it's scrollLeft
  110.     if (item.scrollContainer)
  111.         return item.scrollContainer.scrollLeft;
  112.  
  113.     var w = window.top;
  114.  
  115.     return this.hasInner
  116.         ? w.pageXOffset  
  117.         : this.hasElement  
  118.           ? w.document.documentElement.scrollLeft  
  119.           : w.document.body.scrollLeft;
  120. };
  121.  
  122. floatingMenu.scrollTop = function(item)
  123. {
  124.     // If floating within scrollable container use it's scrollTop
  125.     if (item.scrollContainer)
  126.         return item.scrollContainer.scrollTop;
  127.  
  128.     var w = window.top;
  129.  
  130.     return this.hasInner
  131.         ? w.pageYOffset
  132.         : this.hasElement
  133.           ? w.document.documentElement.scrollTop
  134.           : w.document.body.scrollTop;
  135. };
  136.  
  137. floatingMenu.windowWidth = function()
  138. {
  139.     return this.hasElement
  140.         ? document.documentElement.clientWidth
  141.         : document.body.clientWidth;
  142. };
  143.  
  144. floatingMenu.windowHeight = function()
  145. {
  146.     if (floatingMenu.hasElement && floatingMenu.hasInner)
  147.     {
  148.         // Handle Opera 8 problems
  149.         return document.documentElement.clientHeight > window.innerHeight
  150.             ? window.innerHeight
  151.             : document.documentElement.clientHeight
  152.     }
  153.     else
  154.     {
  155.         return floatingMenu.hasElement
  156.             ? document.documentElement.clientHeight
  157.             : document.body.clientHeight;
  158.     }
  159. };
  160.  
  161. floatingMenu.documentHeight = function()
  162. {
  163.     var innerHeight = this.hasInner
  164.         ? window.innerHeight
  165.         : 0;
  166.  
  167.     var body = document.body,
  168.         html = document.documentElement;
  169.  
  170.     return Math.max(
  171.         body.scrollHeight,
  172.         body.offsetHeight,
  173.         html.clientHeight,
  174.         html.scrollHeight,
  175.         html.offsetHeight,
  176.         innerHeight);
  177. };
  178.  
  179. floatingMenu.documentWidth = function()
  180. {
  181.     var innerWidth = this.hasInner
  182.         ? window.innerWidth
  183.         : 0;
  184.  
  185.     var body = document.body,
  186.         html = document.documentElement;
  187.  
  188.     return Math.max(
  189.         body.scrollWidth,
  190.         body.offsetWidth,
  191.         html.clientWidth,
  192.         html.scrollWidth,
  193.         html.offsetWidth,
  194.         innerWidth);
  195. };
  196.  
  197. floatingMenu.calculateCornerX = function(item)
  198. {
  199.     var offsetWidth = item.menu.offsetWidth;
  200.  
  201.     var result = this.scrollLeft(item) - item.parentLeft;
  202.  
  203.     if (item.centerX)
  204.     {
  205.         result += (this.windowWidth() - offsetWidth)/2;
  206.     }
  207.     else if (item.targetLeft == undefined)
  208.     {
  209.         result += this.windowWidth() - item.targetRight - offsetWidth;
  210.     }
  211.     else
  212.     {
  213.         result += item.targetLeft;
  214.     }
  215.        
  216.     if (document.body != item.menu.parentNode
  217.         && result + offsetWidth >= item.confinedWidthReserve)
  218.     {
  219.         result = item.confinedWidthReserve - offsetWidth;
  220.     }
  221.  
  222.     if (result < 0)
  223.         result = 0;
  224.  
  225.     return result;
  226. };
  227.  
  228. floatingMenu.calculateCornerY = function(item)
  229. {
  230.     var offsetHeight = item.menu.offsetHeight;
  231.  
  232.     var result = this.scrollTop(item) - item.parentTop;
  233.  
  234.     if (item.centerY)
  235.     {
  236.         result += (this.windowHeight() - offsetHeight)/2;
  237.     }
  238.     else if (item.targetTop === undefined)
  239.     {
  240.         result += this.windowHeight() - item.targetBottom - offsetHeight;
  241.     }
  242.     else
  243.     {
  244.         result += item.targetTop;
  245.     }
  246.  
  247.     if (document.body != item.menu.parentNode
  248.         && result + offsetHeight >= item.confinedHeightReserve)
  249.     {
  250.         result = item.confinedHeightReserve - offsetHeight;
  251.     }
  252.  
  253.     if (result < 0)
  254.         result = 0;
  255.        
  256.     return result;
  257. };
  258.  
  259. floatingMenu.isConfinementArea = function(item, area)
  260. {
  261.     return item.confinementAreaId != undefined
  262.         && area.id == item.confinementAreaId
  263.         || item.confinementAreaClassRegexp != undefined
  264.         && area.className
  265.         && item.confinementAreaClassRegexp.test(area.className);
  266. };
  267.  
  268. floatingMenu.computeParent = function(item)
  269. {
  270.     if (item.ignoreParentDimensions)
  271.     {
  272.         item.confinedHeightReserve = this.documentHeight();
  273.         item.confinedWidthReserver = this.documentWidth();
  274.         item.parentLeft = 0;  
  275.         item.parentTop = 0;  
  276.         return;
  277.     }
  278.  
  279.     var parentNode = item.menu.parentNode;
  280.     var parentOffsets = this.offsets(parentNode, item);
  281.     item.parentLeft = parentOffsets.left;
  282.     item.parentTop = parentOffsets.top;
  283.  
  284.     item.confinedWidthReserve = parentNode.clientWidth;
  285.  
  286.     // We could have absolutely-positioned DIV wrapped
  287.     // inside relatively-positioned. Then parent might not
  288.     // have any height. Try to find parent that has
  289.     // and try to find whats left of its height for us.
  290.     var obj = parentNode;
  291.     var objOffsets = this.offsets(obj, item);
  292.  
  293.     if (item.confinementArea == undefined)
  294.     {
  295.         while (obj.clientHeight + objOffsets.top
  296.                    < item.menu.scrollHeight + parentOffsets.top
  297.                || item.menu.parentNode == obj
  298.                && item.updateParentHeight
  299.                && obj.clientHeight + objOffsets.top
  300.                    == item.menu.scrollHeight + parentOffsets.top)
  301.         {
  302.             obj = obj.parentNode;
  303.             objOffsets = this.offsets(obj, item);
  304.         }
  305.     }
  306.     else
  307.     {
  308.         while (obj.parentNode != undefined
  309.                && !this.isConfinementArea(item, obj))
  310.         {
  311.             obj = obj.parentNode;
  312.             objOffsets = this.offsets(obj, item);
  313.         }
  314.     }
  315.  
  316.     item.confinedHeightReserve = obj.clientHeight
  317.         - (parentOffsets.top - objOffsets.top);
  318. };
  319.  
  320. floatingMenu.offsets = function(obj, item)
  321. {
  322.     var result =
  323.     {
  324.         left: 0,
  325.         top: 0
  326.     };
  327.  
  328.     if (obj === item.scrollContainer)
  329.         return;
  330.  
  331.     while (obj.offsetParent && obj.offsetParent != item.scrollContainer)
  332.     {  
  333.         result.left += obj.offsetLeft;  
  334.         result.top += obj.offsetTop;  
  335.         obj = obj.offsetParent;
  336.     }  
  337.  
  338.     if (window == window.top)
  339.         return result;
  340.  
  341.     // we're IFRAMEd
  342.     var iframes = window.top.document.body.getElementsByTagName("IFRAME");
  343.     for (var i = 0; i < iframes.length; i++)
  344.     {
  345.         if (iframes[i].contentWindow != window)
  346.            continue;
  347.  
  348.         obj = iframes[i];
  349.         while (obj.offsetParent)  
  350.         {  
  351.             result.left += obj.offsetLeft;  
  352.             result.top += obj.offsetTop;  
  353.             obj = obj.offsetParent;
  354.         }  
  355.     }
  356.  
  357.     return result;
  358. };
  359.  
  360. floatingMenu.doFloatSingle = function(item)
  361. {
  362.     this.findSingle(item);
  363.  
  364.     if (item.updateParentHeight)
  365.     {
  366.         item.menu.parentNode.style.minHeight =
  367.             item.menu.scrollHeight + 'px';
  368.     }
  369.  
  370.     var stepX, stepY;
  371.  
  372.     this.computeParent(item);
  373.  
  374.     var cornerX = this.calculateCornerX(item);
  375.  
  376.     var stepX = (cornerX - item.nextX) * item.distance;
  377.     if (Math.abs(stepX) < .5 && item.snap
  378.         || Math.abs(cornerX - item.nextX) <= 1)
  379.     {
  380.         stepX = cornerX - item.nextX;
  381.     }
  382.  
  383.     var cornerY = this.calculateCornerY(item);
  384.  
  385.     var stepY = (cornerY - item.nextY) * item.distance;
  386.     if (Math.abs(stepY) < .5 && item.snap
  387.         || Math.abs(cornerY - item.nextY) <= 1)
  388.     {
  389.         stepY = cornerY - item.nextY;
  390.     }
  391.  
  392.     if (Math.abs(stepX) > 0 ||
  393.         Math.abs(stepY) > 0)
  394.     {
  395.         item.nextX += stepX;
  396.         item.nextY += stepY;
  397.         this.move(item);
  398.     }
  399. };
  400.  
  401. floatingMenu.fixTargets = function()
  402. {
  403. };
  404.  
  405. floatingMenu.fixTarget = function(item)
  406. {
  407. };
  408.  
  409. floatingMenu.doFloat = function()
  410. {
  411.     this.fixTargets();
  412.     for (var i=0; i < floatingArray.length; i++)
  413.     {
  414.         this.fixTarget(floatingArray[i]);
  415.         this.doFloatSingle(floatingArray[i]);
  416.     }
  417.     setTimeout('floatingMenu.doFloat()', 20);
  418. };
  419.  
  420. floatingMenu.insertEvent = function(element, event, handler)
  421. {
  422.     // W3C
  423.     if (element.addEventListener != undefined)
  424.     {
  425.         element.addEventListener(event, handler, false);
  426.         return;
  427.     }
  428.  
  429.     var listener = 'on' + event;
  430.  
  431.     // MS
  432.     if (element.attachEvent != undefined)
  433.     {
  434.         element.attachEvent(listener, handler);
  435.         return;
  436.     }
  437.  
  438.     // Fallback
  439.     var oldHandler = element[listener];
  440.     element[listener] = function (e)
  441.         {
  442.             e = (e) ? e : window.event;
  443.             var result = handler(e);
  444.             return (oldHandler != undefined)
  445.                 && (oldHandler(e) == true)
  446.                 && (result == true);
  447.         };
  448. };
  449.  
  450. floatingMenu.init = function()
  451. {
  452.     floatingMenu.fixTargets();
  453.  
  454.     for (var i=0; i < floatingArray.length; i++)
  455.     {
  456.         floatingMenu.initSingleMenu(floatingArray[i]);
  457.     }
  458.  
  459.     setTimeout('floatingMenu.doFloat()', 100);
  460. };
  461.  
  462. // Some browsers init scrollbars only after
  463. // full document load.
  464. floatingMenu.initSingleMenu = function(item)
  465. {
  466.     this.findSingle(item);
  467.     this.computeParent(item);
  468.     this.fixTarget(item);
  469.     item.nextX = this.calculateCornerX(item);
  470.     item.nextY = this.calculateCornerY(item);
  471.     this.move(item);
  472. };
  473.  
  474. floatingMenu.insertEvent(window, 'load', floatingMenu.init);
  475.  
  476.  
  477. // Register ourselves as jQuery plugin if jQuery is present
  478. if (typeof(jQuery) !== 'undefined')
  479. {
  480.     (function ($)
  481.     {
  482.         $.fn.addFloating = function(options)
  483.         {
  484.             return this.each(function()
  485.             {
  486.                 floatingMenu.add(this, options);
  487.             });
  488.         };
  489.     }) (jQuery);
  490. }
  491. ;

Raw Paste


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