AngularJS:窗口服务和指令

时间:2014-07-21 15:13:22

标签: angularjs angularjs-directive angularjs-service

我正在学习AngularJS,我想创建一个自定义服务和指令来显示我可以关闭,最小化,最大化,拖动和调整大小的窗口视图。我写了一些东西,但我不确定这是否正确,尤其是当我在改变路线时使用ng-view我必须添加

scope.$on('$routeChangeStart', function (next, current) {

});

到我的代码和ngRoute到dependecies列表以查看视图,但我没有添加任何内容来回应它,我不确定它是如何工作的。

我想在esc上添加关闭窗口的可能性,但是当我添加此功能关闭窗口时动画停止工作。

有人可以查看代码并告诉我错误或遗漏或解释一些事情吗?

(function (window, angular) {
'use strict';

var module = angular.module('bbWindow', []);

module.provider('bbWindow', function () {
    var defaults = this.defaults = {
        id: null,
        controller: null,
        scope: null,
        windowTitle: null,
        windowContent: null,
        className: 'bbwindow-theme-default',
        position: 'top', // position of the window: 'top', 'center', 'bottom'
        size: 'medium', // size of the window: 'small', 'medium', 'large'
        showButtons: true,
        showCloseButton: true,
        showMinimizeButton: true,
        showMaximizeButton: true,
        showBackdrop: false,
        closeByBackdropClick: false,
        closeByEscape: true,
        onClose: null,
        praventClosing: false,
        animation: 'am-fade-and-scale', // use animations from angular-motion, eg. am-slide-top, am-fade-and-scale, am-flip-x
        backdropAnimation: 'am-fade',
        template: 'common/bbwindow/bbwindow.tpl.html',
        plainTemplate: false,
        contentTemplate: null,
        plainContentTemplate: false,
        draggable: true,
        dragOpacity: 0.35,
        resizable: true,
        resizeMinHeight: 150,
        resizeMinWidth: 330
    };

    var openedWindows = [],
        globalId = 0,
        zIndex = 1000,
        minimizedWindowPositions = [],
        topId = 0,
        defers = []; // used to resolve when window is closed

    this.$get = ['$rootScope',
        '$document',
        '$compile',
        '$q',
        '$templateCache',
        '$http',
        '$timeout',
        '$sce',
        '$animate',
        '$route',
        '$log',
        function ($rootScope, $document, $compile, $q, $templateCache, $http, $timeout, $sce, $animate, $route, $log) {

            var body = $document.find('body');

            // private methods
            function onKeyUp(event) {
                event.stopPropagation();

                if (event.keyCode === 27) {
                    if (topId) {
                        bbwindow.close(topId);
                    }
                }
            }

            function fetchTemplate(template, plain) {
                if (plain) {
                    return $q.when(template);
                }

                return $q.when($templateCache.get(template) || $http.get(template))
                    .then(function (res) {
                        if (angular.isObject(res)) {
                            $templateCache.put(template, res.data);
                            return res.data;
                        }

                        return res;
                    });
            }

            // find elements in element or document for specified selectors
            function findElement(selectors, element) {
                return angular.element((element || document).querySelectorAll(selectors));
            }

            // get height of the screen
            function getDocHeight() {
                var D = document;

                return Math.max(
                    D.body.scrollHeight, D.documentElement.scrollHeight,
                    D.body.offsetHeight, D.documentElement.offsetHeight,
                    D.body.clientHeight, D.documentElement.clientHeight
                );
            }

            function getElementPositionObject(element) {
                return {
                    width: element.css('width'),
                    height: element.css('height'),
                    top: element.css('top'),
                    left: element.css('left'),
                    margin: element.css('margin')
                };
            }

            // find the minimized window position in the array and remove it
            function removeMinimizedWindowPosition(windowElement) {
                var left = parseInt(windowElement.css('left')),
                    top = parseInt(windowElement.css('top')),
                    i,
                    position = -1;

                for (i = 0; i < minimizedWindowPositions.length; i++) {
                    if (minimizedWindowPositions[i][0] == left && minimizedWindowPositions[i][1] == top) {
                        position = i;
                        break;
                    }
                }

                if (position > -1) {
                    minimizedWindowPositions.splice(position, 1);
                }
            }

            // public object returned from service
            var bbwindow = {

                open: function (config) {
                    var self = this,
                        options = angular.copy(defaults);

                    config = config || {};
                    angular.extend(options, config);

                    globalId += 1;
                    var id = options.id || 'bbwindow' + globalId;
                    topId = id;
                    var defer = $q.defer();
                    defers[id] = defer;
                    var scope = options.scope && angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();

                    // Support scope as string options
                    angular.forEach(['windowTitle', 'windowContent'], function (key) {
                        if (options[key]) {
                            scope[key] = $sce.trustAsHtml(options[key]);
                        }
                    });

                    scope.showButtons = options.showButtons;
                    scope.showCloseButton = options.showCloseButton;
                    scope.showMinimizeButton = options.showMinimizeButton;
                    scope.showMaximizeButton = options.showMaximizeButton;

                    scope.close = function () {
                        scope.$$postDigest(function () {
                            if (!options.preventClosing) {
                                bbwindow.close(id);
                            }

                            if (options.onClose && $.isFunction(options.onClose)) {
                                options.onClose();
                            }
                        });
                    };

                    scope.maximize = function () {
                        scope.$$postDigest(function () {
                            bbwindow.maximize(id);
                        });
                    };

                    scope.minimize = function () {
                        scope.$$postDigest(function () {
                            bbwindow.minimize(id);
                        });
                    };

                    scope.$on('$routeChangeStart', function (next, current) {

                    });

                    // featch main window template
                    var templatePromise = fetchTemplate(options.template, options.plainTemplate);

                    // check if the user provided template for content and fetch it
                    if (options.contentTemplate) {
                        templatePromise = templatePromise.then(function (template) {
                            var templateElement = angular.element(template);

                            if (templateElement) {
                                // fetch content template
                                return fetchTemplate(options.contentTemplate, options.plainContentTemplate).then(function (contentTemplate) {
                                    var contentElement = findElement('[data-ng-bind="windowContent"]', templateElement[0]);

                                    if (contentElement) {
                                        contentElement.removeAttr('data-ng-bind').html(contentTemplate);

                                        return templateElement[0].outerHTML;
                                    }
                                });
                            }
                        });
                    }

                    templatePromise.then(function (template) {
                        if (template) {
                            var windowElement = $compile(template)(scope);

                            scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();

                            windowElement.attr('id', id);

                            if (options.controller && angular.isString(options.controller)) {
                                windowElement.attr('data-ng-controller', options.controller);
                            }

                            // set default theme class
                            windowElement.addClass(options.className);

                            // set initial positioning
                            windowElement.addClass(options.position);

                            // set initial size of the window
                            windowElement.addClass(options.size);

                            // add drag option if enabled
                            if (options.draggable) {
                                $(windowElement).draggable({
                                    addClasses: false,
                                    cancel: "input,textarea,button,select,option,.bbwindow-content,.bbwindow-header-buttons",
                                    opacity: options.dragOpacity
                                });

                                // jquery draggable plugin sets position to relative and then there is
                                // problem while resizing element, so change position to absolute
                                $(windowElement).css('position', 'absolute');
                            } else {
                                // if the window won't be draggable, then find h4 element in the header
                                // and change cursor from move to normal
                                $(windowElement).find('.bbwindow-header h4').css('cursor', 'default');
                            }

                            // add resize option if enabled
                            if (options.resizable) {
                                $(windowElement).resizable({
                                    handles: "all",
                                    minHeight: options.resizeMinHeight,
                                    minWidth: options.resizeMinWidth
                                });

                                if (options.position == 'center') {
                                    $(windowElement).css('transform', 'inherit');
                                }
                            }

                            if (options.closeByEscape) {
                                //body.off('keyup');
                                //windowElement.on('keyup', onKeyUp);
                            }

                            if (options.animation) {
                                windowElement.addClass(options.animation);
                            }

                            windowElement.on('mousedown', function () {
                                topId = id;
                                windowElement.css('z-index', zIndex++);
                            });

                            $animate.enter(windowElement, body, null, function () {
                            });
                        }
                    });

                    return {
                        id: id,
                        closePromise: defer.promise,
                        close: function() {
                            bbwindow.close(id);
                        }
                    };
                },

                confirm: function(config) {
                    var defer = $q.defer();

                    var options = {
                        closeByBackdropClick: false,
                        closeByEscape: false
                    };

                    angular.extend(options, config);

                    options.scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();

                    options.scope.confirm = function(value) {
                        defer.resolve(value);
                        window.close();
                    };

                    var window = bbwindow.open(options);
                    window.closePromise.then(function () {
                        defer.reject();
                    });

                    return defer.promise;
                },

                close: function (id) {
                    var windowElement = angular.element(document.getElementById(id));

                    if (windowElement) {
                        var isMinimized = windowElement.scope().isMinimized || false;

                        if (isMinimized) {
                            removeMinimizedWindowPosition(windowElement);
                        }

                        if (defers[id]) {
                            defers[id].resolve({
                                id: id,
                                window: windowElement
                            });

                            delete defers[id];
                        }

                        windowElement.scope().$destroy();
                        $animate.leave(windowElement, function () {
                        });
                    }
                },

                maximize: function (id) {
                    var windowElement = angular.element(document.getElementById(id));

                    if (windowElement) {
                        var isMinimized = windowElement.scope().isMinimized || false;

                        if (isMinimized) {
                            return;
                        }

                        var bodyWidth = $('body').width(),
                            bodyHeight = getDocHeight(),
                            elementWidth = parseInt(windowElement.css('width')),
                            elementHeight = parseInt(windowElement.css('height'));

                        if (windowElement.scope().lastPosition && elementWidth == bodyWidth && elementHeight == bodyHeight) {
                            var lastPosition = windowElement.scope().lastPosition;

                            $(windowElement).animate({
                                position: 'absolute',
                                width: lastPosition.width,
                                height: lastPosition.height,
                                top: lastPosition.top,
                                left: lastPosition.left,
                                margin: lastPosition.margin
                            }, 200);

                            windowElement.scope().lastPosition = null;
                        } else {
                            windowElement.scope().lastPosition = getElementPositionObject(windowElement);

                            $(windowElement).animate({
                                position: 'fixed',
                                width: '100%',
                                height: '100%',
                                top: '0',
                                left: '0',
                                margin: '0'
                            }, 200);
                        }
                    }
                },

                minimize: function (id) {
                    var windowElement = angular.element(document.getElementById(id));

                    if (windowElement) {
                        var bodyWidth = $('body').width(),
                            bodyHeight = getDocHeight(),
                            isMinimized = windowElement.scope().isMinimized || false;

                        if (isMinimized) {
                            var lastPosition = windowElement.scope().lastPositionForMinimizedElement;

                            removeMinimizedWindowPosition(windowElement);

                            $(windowElement).animate({
                                width: lastPosition.width,
                                height: lastPosition.height,
                                top: lastPosition.top,
                                left: lastPosition.left,
                                margin: lastPosition.margin
                            }, 200);

                            windowElement.scope().isMinimized = false;
                            windowElement.scope().lastPositionForMinimizedElement = null;

                            $(windowElement).draggable('enable');
                            $(windowElement).resizable('enable');
                        } else {
                            windowElement.scope().lastPositionForMinimizedElement = getElementPositionObject(windowElement);

                            var headerHeight = $(windowElement).find('.bbwindow-header').css('height');
                            var top = bodyHeight - parseInt(headerHeight);
                            var width = 200;
                            var left = 0;
                            var i = 0;
                            var found = false;

                            // find position for minimized window
                            do {
                                i++;

                                if (minimizedWindowPositions.length == 0) {
                                    found = true;
                                    break;
                                }

                                var positions = minimizedWindowPositions.filter(function (pos) {
                                    return pos[0] == left && pos[1] == top;
                                });

                                if (positions.length > 0) {
                                    left = i * width;

                                    if (left + width >= bodyWidth) {
                                        i = 0;
                                        left = 0;
                                        top -= parseInt(headerHeight);
                                    }
                                } else {
                                    found = true;
                                }
                            } while (!found);

                            minimizedWindowPositions.push([left, top]);

                            $(windowElement).animate({
                                height: headerHeight,
                                left: left + 'px',
                                top: top + 'px',
                                margin: '0',
                                width: width + 'px'
                            }, 200);

                            windowElement.scope().isMinimized = true;

                            $(windowElement).draggable('disable');
                            $(windowElement).resizable('disable');
                        }
                    }
                }
            };

            return bbwindow;
        }];
});

module.directive('bbWindowMain', ['$sce', 'bbWindow', function ($sce, bbWindow) {
    return {
        restrict: 'E',
        scope: true,
        link: function (scope, element, attr, transclusion) {
            var options = {scope: scope};
            angular.forEach(['id', 'className', 'position', 'size', 'animation', 'template', 'contentTemplate'], function (key) {
                if (angular.isDefined(attr[key])) {
                    options[key] = attr[key];
                }
            });

            angular.forEach(['windowTitle', 'windowContent'], function (key) {
                attr[key] && attr.$observe(key, function (newValue, oldValue) {
                    scope[key] = $sce.trustAsHtml(newValue);
                });
            });

            bbWindow.open(options);
        }
    };
}]);
})(window, window.angular);

0 个答案:

没有答案