Built motion from commit 54a160d.|0.0.140
[motion.git] / public / bower_components / angular-bootstrap-contextmenu / contextMenu.js
index 9ff195b..c921c79 100644 (file)
 angular.module('ui.bootstrap.contextMenu', [])
 
-.directive('contextMenu', ["$parse", function ($parse) {
-    var renderContextMenu = function ($scope, event, options, model) {
+.service('CustomService', function () {
+    "use strict";
+
+    return {
+        initialize: function (item) {
+            console.log("got here", item);
+        }
+    }
+
+})
+.directive('contextMenu', ["$parse", "$q", "CustomService", "$sce", function ($parse, $q, custom, $sce) {
+
+    var contextMenus = [];
+    var $currentContextMenu = null;
+    var defaultItemText = "New Item";
+
+    var removeContextMenus = function (level) {
+        /// <summary>Remove context menu.</summary>
+        while (contextMenus.length && (!level || contextMenus.length > level)) {
+            contextMenus.pop().remove();
+        }
+        if (contextMenus.length == 0 && $currentContextMenu) {
+            $currentContextMenu.remove();
+        }
+    };
+
+
+    var processTextItem = function ($scope, item, text, event, model, $promises, nestedMenu, $) {
+        "use strict";
+
+        var $a = $('<a>');
+        $a.css("padding-right", "8px");
+        $a.attr({ tabindex: '-1', href: '#' });
+
+        if (typeof item[0] === 'string') {
+            text = item[0];
+        }
+        else if (typeof item[0] === "function") {
+            item[0].call($scope, $scope, event, model);
+        } else if (typeof item.text !== "undefined") {
+            text = item.text;
+        }
+
+        var $promise = $q.when(text);
+        $promises.push($promise);
+        $promise.then(function (text) {
+            $a.text(text);
+            if (nestedMenu) {
+                $a.css("cursor", "default");
+                $a.append($('<strong style="font-family:monospace;font-weight:bold;float:right;">&gt;</strong>'));
+            }
+        });
+
+        return $a;
+
+    };
+
+    var processItem = function ($scope, event, model, item, $ul, $li, $promises, $q, $, level) {
+        /// <summary>Process individual item</summary>
+        "use strict";
+        var nestedMenu = angular.isArray(item[1])
+            ? item[1] : angular.isArray(item[2])
+            ? item[2] : angular.isArray(item[3])
+            ? item[3] : null;
+
+        // if html property is not defined, fallback to text, otherwise use default text
+        // if first item in the item array is a function then invoke .call()
+        // if first item is a string, then text should be the string.
+
+        var text = defaultItemText;
+        if (typeof item[0] === 'string' || typeof item.text !== "undefined") {
+            text = processTextItem($scope, item, text, event, model, $promises, nestedMenu, $);
+        }
+        else if (typeof item.html !== "undefined") {
+            // leave styling open to dev
+            text = item.html
+        }
+
+        $li.append(text);
+
+
+
+
+        // if item is object, and has enabled prop invoke the prop
+        // els if fallback to item[2]
+
+        var isEnabled = function () {
+            if (typeof item.enabled !== "undefined") {
+                return item.enabled.call($scope, $scope, event, model, text);
+            } else if (typeof item[2] === "function") {
+                return item[2].call($scope, $scope, event, model, text);
+            } else {
+                return true;
+            }
+        };
+
+        registerEnabledEvents($scope, isEnabled(), item, $ul, $li, nestedMenu, model, text, event, $, level);
+    };
+
+    var handlePromises = function ($ul, level, event, $promises) {
+        /// <summary>
+        /// calculate if drop down menu would go out of screen at left or bottom
+        /// calculation need to be done after element has been added (and all texts are set; thus thepromises)
+        /// to the DOM the get the actual height
+        /// </summary>
+        "use strict";
+        $q.all($promises).then(function () {
+            if (level === 0) {
+                var topCoordinate = event.pageY;
+                var menuHeight = angular.element($ul[0]).prop('offsetHeight');
+                var winHeight = event.view.innerHeight;
+                if (topCoordinate > menuHeight && winHeight - topCoordinate < menuHeight) {
+                    topCoordinate = event.pageY - menuHeight;
+                }
+
+                var leftCoordinate = event.pageX;
+                var menuWidth = angular.element($ul[0]).prop('offsetWidth');
+                var winWidth = event.view.innerWidth;
+                if (leftCoordinate > menuWidth && winWidth - leftCoordinate < menuWidth) {
+                    leftCoordinate = event.pageX - menuWidth;
+                }
+
+                $ul.css({
+                    display: 'block',
+                    position: 'absolute',
+                    left: leftCoordinate + 'px',
+                    top: topCoordinate + 'px'
+                });
+            }
+        });
+
+    };
+
+    var registerEnabledEvents = function ($scope, enabled, item, $ul, $li, nestedMenu, model, text, event, $, level) {
+        /// <summary>If item is enabled, register various mouse events.</summary>
+        if (enabled) {
+            var openNestedMenu = function ($event) {
+                removeContextMenus(level + 1);
+                var ev = {
+                    pageX: event.pageX + $ul[0].offsetWidth - 1,
+                    pageY: $ul[0].offsetTop + $li[0].offsetTop - 3
+                };
+                renderContextMenu($scope, ev, nestedMenu, model, level + 1);
+            };
+
+            $li.on('click', function ($event) {
+                $event.preventDefault();
+                $scope.$apply(function () {
+                    if (nestedMenu) {
+                        openNestedMenu($event);
+                    } else {
+                        $(event.currentTarget).removeClass('context');
+                        removeContextMenus();
+
+                        if (angular.isFunction(item[1])) {
+                            item[1].call($scope, $scope, event, model, text)
+                        } else {
+                            item.click.call($scope, $scope, event, model, text);
+                        }
+                    }
+                });
+            });
+
+            $li.on('mouseover', function ($event) {
+                $scope.$apply(function () {
+                    if (nestedMenu) {
+                        openNestedMenu($event);
+                    }
+                });
+            });
+        } else {
+            $li.on('click', function ($event) {
+                $event.preventDefault();
+            });
+            $li.addClass('disabled');
+        }
+
+    };
+
+
+    var renderContextMenu = function ($scope, event, options, model, level) {
+        /// <summary>Render context menu recursively.</summary>
+        if (!level) { level = 0; }
         if (!$) { var $ = angular.element; }
         $(event.currentTarget).addClass('context');
         var $contextMenu = $('<div>');
+        if ($currentContextMenu) {
+            $contextMenu = $currentContextMenu;
+        } else {
+            $currentContextMenu = $contextMenu;
+        }
         $contextMenu.addClass('dropdown clearfix');
         var $ul = $('<ul>');
         $ul.addClass('dropdown-menu');
@@ -13,34 +199,21 @@ angular.module('ui.bootstrap.contextMenu', [])
             display: 'block',
             position: 'absolute',
             left: event.pageX + 'px',
-            top: event.pageY + 'px'
+            top: event.pageY + 'px',
+            "z-index": 10000
         });
-        angular.forEach(options, function (item, i) {
+
+        var $promises = [];
+
+        angular.forEach(options, function (item) {
+
             var $li = $('<li>');
             if (item === null) {
                 $li.addClass('divider');
+            } else if (typeof item[0] === "object") {
+                custom.initialize($li, item);
             } else {
-                var $a = $('<a>');
-                $a.attr({ tabindex: '-1', href: '#' });
-                var text = typeof item[0] == 'string' ? item[0] : item[0].call($scope, $scope, event, model);
-                $a.text(text);
-                $li.append($a);
-                var enabled = angular.isDefined(item[2]) ? item[2].call($scope, $scope, event, text, model) : true;
-                if (enabled) {
-                    $li.on('click', function ($event) {
-                        $event.preventDefault();
-                        $scope.$apply(function () {
-                            $(event.currentTarget).removeClass('context');
-                            $contextMenu.remove();
-                            item[1].call($scope, $scope, event, model);
-                        });
-                    });
-                } else {
-                    $li.on('click', function ($event) {
-                        $event.preventDefault();
-                    });
-                    $li.addClass('disabled');
-                }
+                processItem($scope, event, model, item, $ul, $li, $promises, $q, $, level);
             }
             $ul.append($li);
         });
@@ -59,16 +232,25 @@ angular.module('ui.bootstrap.contextMenu', [])
             zIndex: 9999
         });
         $(document).find('body').append($contextMenu);
+
+        handlePromises($ul, level, event, $promises);
+
         $contextMenu.on("mousedown", function (e) {
             if ($(e.target).hasClass('dropdown')) {
                 $(event.currentTarget).removeClass('context');
-                $contextMenu.remove();
+                removeContextMenus();
             }
         }).on('contextmenu', function (event) {
             $(event.currentTarget).removeClass('context');
             event.preventDefault();
-            $contextMenu.remove();
+            removeContextMenus(level);
         });
+
+        $scope.$on("$destroy", function () {
+            removeContextMenus();
+        });
+
+        contextMenus.push($ul);
     };
     return function ($scope, element, attrs) {
         element.on('contextmenu', function (event) {