我正在学习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);