Igor Zhukov
11 years ago
24 changed files with 2386 additions and 796 deletions
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 321 B |
@ -0,0 +1,990 @@
@@ -0,0 +1,990 @@
|
||||
/* |
||||
* angular-ui-bootstrap |
||||
* http://angular-ui.github.io/bootstrap/
|
||||
|
||||
* Version: 0.10.0 - 2014-01-28 |
||||
* License: MIT |
||||
*/ |
||||
angular.module("ui.bootstrap", ["ui.bootstrap.dropdownToggle","ui.bootstrap.transition","ui.bootstrap.modal","ui.bootstrap.position","ui.bootstrap.bindHtml","ui.bootstrap.tooltip"]); |
||||
/* |
||||
* dropdownToggle - Provides dropdown menu functionality in place of bootstrap js |
||||
* @restrict class or attribute |
||||
* @example: |
||||
<li class="dropdown"> |
||||
<a class="dropdown-toggle">My Dropdown Menu</a> |
||||
<ul class="dropdown-menu"> |
||||
<li ng-repeat="choice in dropChoices"> |
||||
<a ng-href="{{choice.href}}">{{choice.text}}</a> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
*/ |
||||
|
||||
angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) { |
||||
var openElement = null, |
||||
closeMenu = angular.noop; |
||||
return { |
||||
restrict: 'CA', |
||||
link: function(scope, element, attrs) { |
||||
scope.$watch('$location.path', function() { closeMenu(); }); |
||||
element.parent().bind('click', function() { closeMenu(); }); |
||||
element.bind('click', function (event) { |
||||
|
||||
var elementWasOpen = (element === openElement); |
||||
|
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
|
||||
if (!!openElement) { |
||||
closeMenu(); |
||||
} |
||||
|
||||
if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { |
||||
element.parent().addClass('open'); |
||||
openElement = element; |
||||
closeMenu = function (event) { |
||||
if (event) { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
} |
||||
$document.unbind('click', closeMenu); |
||||
element.parent().removeClass('open'); |
||||
closeMenu = angular.noop; |
||||
openElement = null; |
||||
}; |
||||
$document.bind('click', closeMenu); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
}]); |
||||
|
||||
angular.module('ui.bootstrap.transition', []) |
||||
|
||||
/** |
||||
* $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete. |
||||
* @param {DOMElement} element The DOMElement that will be animated. |
||||
* @param {string|object|function} trigger The thing that will cause the transition to start: |
||||
* - As a string, it represents the css class to be added to the element. |
||||
* - As an object, it represents a hash of style attributes to be applied to the element. |
||||
* - As a function, it represents a function to be called that will cause the transition to occur. |
||||
* @return {Promise} A promise that is resolved when the transition finishes. |
||||
*/ |
||||
.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) { |
||||
|
||||
var $transition = function(element, trigger, options) { |
||||
options = options || {}; |
||||
var deferred = $q.defer(); |
||||
var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"]; |
||||
|
||||
var transitionEndHandler = function(event) { |
||||
$rootScope.$apply(function() { |
||||
element.unbind(endEventName, transitionEndHandler); |
||||
deferred.resolve(element); |
||||
}); |
||||
}; |
||||
|
||||
if (endEventName) { |
||||
element.bind(endEventName, transitionEndHandler); |
||||
} |
||||
|
||||
// Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
|
||||
$timeout(function() { |
||||
if ( angular.isString(trigger) ) { |
||||
element.addClass(trigger); |
||||
} else if ( angular.isFunction(trigger) ) { |
||||
trigger(element); |
||||
} else if ( angular.isObject(trigger) ) { |
||||
element.css(trigger); |
||||
} |
||||
//If browser does not support transitions, instantly resolve
|
||||
if ( !endEventName ) { |
||||
deferred.resolve(element); |
||||
} |
||||
}); |
||||
|
||||
// Add our custom cancel function to the promise that is returned
|
||||
// We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
|
||||
// i.e. it will therefore never raise a transitionEnd event for that transition
|
||||
deferred.promise.cancel = function() { |
||||
if ( endEventName ) { |
||||
element.unbind(endEventName, transitionEndHandler); |
||||
} |
||||
deferred.reject('Transition cancelled'); |
||||
}; |
||||
|
||||
return deferred.promise; |
||||
}; |
||||
|
||||
// Work out the name of the transitionEnd event
|
||||
var transElement = document.createElement('trans'); |
||||
var transitionEndEventNames = { |
||||
'WebkitTransition': 'webkitTransitionEnd', |
||||
'MozTransition': 'transitionend', |
||||
'OTransition': 'oTransitionEnd', |
||||
'transition': 'transitionend' |
||||
}; |
||||
var animationEndEventNames = { |
||||
'WebkitTransition': 'webkitAnimationEnd', |
||||
'MozTransition': 'animationend', |
||||
'OTransition': 'oAnimationEnd', |
||||
'transition': 'animationend' |
||||
}; |
||||
function findEndEventName(endEventNames) { |
||||
for (var name in endEventNames){ |
||||
if (transElement.style[name] !== undefined) { |
||||
return endEventNames[name]; |
||||
} |
||||
} |
||||
} |
||||
$transition.transitionEndEventName = findEndEventName(transitionEndEventNames); |
||||
$transition.animationEndEventName = findEndEventName(animationEndEventNames); |
||||
return $transition; |
||||
}]); |
||||
|
||||
angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) |
||||
|
||||
/** |
||||
* A helper, internal data structure that acts as a map but also allows getting / removing |
||||
* elements in the LIFO order |
||||
*/ |
||||
.factory('$$stackedMap', function () { |
||||
return { |
||||
createNew: function () { |
||||
var stack = []; |
||||
|
||||
return { |
||||
add: function (key, value) { |
||||
stack.push({ |
||||
key: key, |
||||
value: value |
||||
}); |
||||
}, |
||||
get: function (key) { |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
return stack[i]; |
||||
} |
||||
} |
||||
}, |
||||
keys: function() { |
||||
var keys = []; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
keys.push(stack[i].key); |
||||
} |
||||
return keys; |
||||
}, |
||||
top: function () { |
||||
return stack[stack.length - 1]; |
||||
}, |
||||
remove: function (key) { |
||||
var idx = -1; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
idx = i; |
||||
break; |
||||
} |
||||
} |
||||
return stack.splice(idx, 1)[0]; |
||||
}, |
||||
removeTop: function () { |
||||
return stack.splice(stack.length - 1, 1)[0]; |
||||
}, |
||||
length: function () { |
||||
return stack.length; |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}) |
||||
|
||||
/** |
||||
* A helper directive for the $modal service. It creates a backdrop element. |
||||
*/ |
||||
.directive('modalBackdrop', ['$timeout', function ($timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
templateUrl: 'template/modal/backdrop.html', |
||||
link: function (scope) { |
||||
|
||||
scope.animate = false; |
||||
|
||||
//trigger CSS transitions
|
||||
$timeout(function () { |
||||
scope.animate = true; |
||||
}); |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
scope: { |
||||
index: '@', |
||||
animate: '=' |
||||
}, |
||||
replace: true, |
||||
transclude: true, |
||||
templateUrl: 'template/modal/window.html', |
||||
link: function (scope, element, attrs) { |
||||
scope.windowClass = attrs.windowClass || ''; |
||||
|
||||
$timeout(function () { |
||||
// trigger CSS transitions
|
||||
scope.animate = true; |
||||
// focus a freshly-opened modal
|
||||
element[0].focus(); |
||||
}); |
||||
|
||||
scope.close = function (evt) { |
||||
var modal = $modalStack.getTop(); |
||||
if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
$modalStack.dismiss(modal.key, 'backdrop click'); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap', |
||||
function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) { |
||||
|
||||
var OPENED_MODAL_CLASS = 'modal-open'; |
||||
|
||||
var backdropDomEl, backdropScope; |
||||
var openedWindows = $$stackedMap.createNew(); |
||||
var $modalStack = {}; |
||||
|
||||
function backdropIndex() { |
||||
var topBackdropIndex = -1; |
||||
var opened = openedWindows.keys(); |
||||
for (var i = 0; i < opened.length; i++) { |
||||
if (openedWindows.get(opened[i]).value.backdrop) { |
||||
topBackdropIndex = i; |
||||
} |
||||
} |
||||
return topBackdropIndex; |
||||
} |
||||
|
||||
$rootScope.$watch(backdropIndex, function(newBackdropIndex){ |
||||
if (backdropScope) { |
||||
backdropScope.index = newBackdropIndex; |
||||
} |
||||
}); |
||||
|
||||
function removeModalWindow(modalInstance) { |
||||
|
||||
var body = $document.find('body').eq(0); |
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
|
||||
//clean up the stack
|
||||
openedWindows.remove(modalInstance); |
||||
|
||||
//remove window DOM element
|
||||
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop); |
||||
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); |
||||
} |
||||
|
||||
function checkRemoveBackdrop() { |
||||
//remove backdrop if no longer needed
|
||||
if (backdropDomEl && backdropIndex() == -1) { |
||||
var backdropScopeRef = backdropScope; |
||||
removeAfterAnimate(backdropDomEl, backdropScope, 150, function () { |
||||
backdropScopeRef.$destroy(); |
||||
backdropScopeRef = null; |
||||
}); |
||||
backdropDomEl = undefined; |
||||
backdropScope = undefined; |
||||
} |
||||
} |
||||
|
||||
function removeAfterAnimate(domEl, scope, emulateTime, done) { |
||||
// Closing animation
|
||||
scope.animate = false; |
||||
|
||||
var transitionEndEventName = $transition.transitionEndEventName; |
||||
if (transitionEndEventName) { |
||||
// transition out
|
||||
var timeout = $timeout(afterAnimating, emulateTime); |
||||
|
||||
domEl.bind(transitionEndEventName, function () { |
||||
$timeout.cancel(timeout); |
||||
afterAnimating(); |
||||
scope.$apply(); |
||||
}); |
||||
} else { |
||||
// Ensure this call is async
|
||||
$timeout(afterAnimating, 0); |
||||
} |
||||
|
||||
function afterAnimating() { |
||||
if (afterAnimating.done) { |
||||
return; |
||||
} |
||||
afterAnimating.done = true; |
||||
|
||||
domEl.remove(); |
||||
if (done) { |
||||
done(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$document.bind('keydown', function (evt) { |
||||
var modal; |
||||
|
||||
if (evt.which === 27) { |
||||
modal = openedWindows.top(); |
||||
if (modal && modal.value.keyboard) { |
||||
$rootScope.$apply(function () { |
||||
$modalStack.dismiss(modal.key); |
||||
}); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
$modalStack.open = function (modalInstance, modal) { |
||||
|
||||
openedWindows.add(modalInstance, { |
||||
deferred: modal.deferred, |
||||
modalScope: modal.scope, |
||||
backdrop: modal.backdrop, |
||||
keyboard: modal.keyboard |
||||
}); |
||||
|
||||
var body = $document.find('body').eq(0), |
||||
currBackdropIndex = backdropIndex(); |
||||
|
||||
if (currBackdropIndex >= 0 && !backdropDomEl) { |
||||
backdropScope = $rootScope.$new(true); |
||||
backdropScope.index = currBackdropIndex; |
||||
backdropDomEl = $compile('<div modal-backdrop></div>')(backdropScope); |
||||
body.append(backdropDomEl); |
||||
} |
||||
|
||||
var angularDomEl = angular.element('<div modal-window></div>'); |
||||
angularDomEl.attr('window-class', modal.windowClass); |
||||
angularDomEl.attr('index', openedWindows.length() - 1); |
||||
angularDomEl.attr('animate', 'animate'); |
||||
angularDomEl.html(modal.content); |
||||
|
||||
var modalDomEl = $compile(angularDomEl)(modal.scope); |
||||
openedWindows.top().value.modalDomEl = modalDomEl; |
||||
body.append(modalDomEl); |
||||
body.addClass(OPENED_MODAL_CLASS); |
||||
}; |
||||
|
||||
$modalStack.close = function (modalInstance, result) { |
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
if (modalWindow) { |
||||
modalWindow.deferred.resolve(result); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.dismiss = function (modalInstance, reason) { |
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
if (modalWindow) { |
||||
modalWindow.deferred.reject(reason); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.dismissAll = function (reason) { |
||||
var topModal = this.getTop(); |
||||
while (topModal) { |
||||
this.dismiss(topModal.key, reason); |
||||
topModal = this.getTop(); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.getTop = function () { |
||||
return openedWindows.top(); |
||||
}; |
||||
|
||||
return $modalStack; |
||||
}]) |
||||
|
||||
.provider('$modal', function () { |
||||
|
||||
var $modalProvider = { |
||||
options: { |
||||
backdrop: true, //can be also false or 'static'
|
||||
keyboard: true |
||||
}, |
||||
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', |
||||
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { |
||||
|
||||
var $modal = {}; |
||||
|
||||
function getTemplatePromise(options) { |
||||
return options.template ? $q.when(options.template) : |
||||
$http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { |
||||
return result.data; |
||||
}); |
||||
} |
||||
|
||||
function getResolvePromises(resolves) { |
||||
var promisesArr = []; |
||||
angular.forEach(resolves, function (value, key) { |
||||
if (angular.isFunction(value) || angular.isArray(value)) { |
||||
promisesArr.push($q.when($injector.invoke(value))); |
||||
} |
||||
}); |
||||
return promisesArr; |
||||
} |
||||
|
||||
$modal.open = function (modalOptions) { |
||||
|
||||
var modalResultDeferred = $q.defer(); |
||||
var modalOpenedDeferred = $q.defer(); |
||||
|
||||
//prepare an instance of a modal to be injected into controllers and returned to a caller
|
||||
var modalInstance = { |
||||
result: modalResultDeferred.promise, |
||||
opened: modalOpenedDeferred.promise, |
||||
close: function (result) { |
||||
$modalStack.close(modalInstance, result); |
||||
}, |
||||
dismiss: function (reason) { |
||||
$modalStack.dismiss(modalInstance, reason); |
||||
} |
||||
}; |
||||
|
||||
//merge and clean up options
|
||||
modalOptions = angular.extend({}, $modalProvider.options, modalOptions); |
||||
modalOptions.resolve = modalOptions.resolve || {}; |
||||
|
||||
//verify options
|
||||
if (!modalOptions.template && !modalOptions.templateUrl) { |
||||
throw new Error('One of template or templateUrl options is required.'); |
||||
} |
||||
|
||||
var templateAndResolvePromise = |
||||
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); |
||||
|
||||
|
||||
templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { |
||||
|
||||
var modalScope = (modalOptions.scope || $rootScope).$new(); |
||||
modalScope.$close = modalInstance.close; |
||||
modalScope.$dismiss = modalInstance.dismiss; |
||||
|
||||
var ctrlInstance, ctrlLocals = {}; |
||||
var resolveIter = 1; |
||||
|
||||
//controllers
|
||||
if (modalOptions.controller) { |
||||
ctrlLocals.$scope = modalScope; |
||||
ctrlLocals.$modalInstance = modalInstance; |
||||
angular.forEach(modalOptions.resolve, function (value, key) { |
||||
ctrlLocals[key] = tplAndVars[resolveIter++]; |
||||
}); |
||||
|
||||
ctrlInstance = $controller(modalOptions.controller, ctrlLocals); |
||||
} |
||||
|
||||
$modalStack.open(modalInstance, { |
||||
scope: modalScope, |
||||
deferred: modalResultDeferred, |
||||
content: tplAndVars[0], |
||||
backdrop: modalOptions.backdrop, |
||||
keyboard: modalOptions.keyboard, |
||||
windowClass: modalOptions.windowClass |
||||
}); |
||||
|
||||
}, function resolveError(reason) { |
||||
modalResultDeferred.reject(reason); |
||||
}); |
||||
|
||||
templateAndResolvePromise.then(function () { |
||||
modalOpenedDeferred.resolve(true); |
||||
}, function () { |
||||
modalOpenedDeferred.reject(false); |
||||
}); |
||||
|
||||
return modalInstance; |
||||
}; |
||||
|
||||
return $modal; |
||||
}] |
||||
}; |
||||
|
||||
return $modalProvider; |
||||
}); |
||||
|
||||
angular.module('ui.bootstrap.position', []) |
||||
|
||||
/** |
||||
* A set of utility methods that can be use to retrieve position of DOM elements. |
||||
* It is meant to be used where we need to absolute-position DOM elements in |
||||
* relation to other, existing elements (this is the case for tooltips, popovers, |
||||
* typeahead suggestions etc.). |
||||
*/ |
||||
.factory('$position', ['$document', '$window', function ($document, $window) { |
||||
|
||||
function getStyle(el, cssprop) { |
||||
if (el.currentStyle) { //IE
|
||||
return el.currentStyle[cssprop]; |
||||
} else if ($window.getComputedStyle) { |
||||
return $window.getComputedStyle(el)[cssprop]; |
||||
} |
||||
// finally try and get inline style
|
||||
return el.style[cssprop]; |
||||
} |
||||
|
||||
/** |
||||
* Checks if a given element is statically positioned |
||||
* @param element - raw DOM element |
||||
*/ |
||||
function isStaticPositioned(element) { |
||||
return (getStyle(element, "position") || 'static' ) === 'static'; |
||||
} |
||||
|
||||
/** |
||||
* returns the closest, non-statically positioned parentOffset of a given element |
||||
* @param element |
||||
*/ |
||||
var parentOffsetEl = function (element) { |
||||
var docDomEl = $document[0]; |
||||
var offsetParent = element.offsetParent || docDomEl; |
||||
while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { |
||||
offsetParent = offsetParent.offsetParent; |
||||
} |
||||
return offsetParent || docDomEl; |
||||
}; |
||||
|
||||
return { |
||||
/** |
||||
* Provides read-only equivalent of jQuery's position function: |
||||
* http://api.jquery.com/position/
|
||||
*/ |
||||
position: function (element) { |
||||
var elBCR = this.offset(element); |
||||
var offsetParentBCR = { top: 0, left: 0 }; |
||||
var offsetParentEl = parentOffsetEl(element[0]); |
||||
if (offsetParentEl != $document[0]) { |
||||
offsetParentBCR = this.offset(angular.element(offsetParentEl)); |
||||
offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; |
||||
offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; |
||||
} |
||||
|
||||
var boundingClientRect = element[0].getBoundingClientRect(); |
||||
return { |
||||
width: boundingClientRect.width || element.prop('offsetWidth'), |
||||
height: boundingClientRect.height || element.prop('offsetHeight'), |
||||
top: elBCR.top - offsetParentBCR.top, |
||||
left: elBCR.left - offsetParentBCR.left |
||||
}; |
||||
}, |
||||
|
||||
/** |
||||
* Provides read-only equivalent of jQuery's offset function: |
||||
* http://api.jquery.com/offset/
|
||||
*/ |
||||
offset: function (element) { |
||||
var boundingClientRect = element[0].getBoundingClientRect(); |
||||
return { |
||||
width: boundingClientRect.width || element.prop('offsetWidth'), |
||||
height: boundingClientRect.height || element.prop('offsetHeight'), |
||||
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop), |
||||
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft) |
||||
}; |
||||
} |
||||
}; |
||||
}]); |
||||
|
||||
angular.module('ui.bootstrap.bindHtml', []) |
||||
|
||||
.directive('bindHtmlUnsafe', function () { |
||||
return function (scope, element, attr) { |
||||
element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); |
||||
scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { |
||||
element.html(value || ''); |
||||
}); |
||||
}; |
||||
}); |
||||
/** |
||||
* The following features are still outstanding: animation as a |
||||
* function, placement as a function, inside, support for more triggers than |
||||
* just mouse enter/leave, html tooltips, and selector delegation. |
||||
*/ |
||||
angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) |
||||
|
||||
/** |
||||
* The $tooltip service creates tooltip- and popover-like directives as well as |
||||
* houses global options for them. |
||||
*/ |
||||
.provider( '$tooltip', function () { |
||||
// The default options tooltip and popover.
|
||||
var defaultOptions = { |
||||
placement: 'top', |
||||
animation: true, |
||||
popupDelay: 0 |
||||
}; |
||||
|
||||
// Default hide triggers for each show trigger
|
||||
var triggerMap = { |
||||
'mouseenter': 'mouseleave', |
||||
'click': 'click', |
||||
'focus': 'blur' |
||||
}; |
||||
|
||||
// The options specified to the provider globally.
|
||||
var globalOptions = {}; |
||||
|
||||
/** |
||||
* `options({})` allows global configuration of all tooltips in the |
||||
* application. |
||||
* |
||||
* var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { |
||||
* // place tooltips left instead of top by default
|
||||
* $tooltipProvider.options( { placement: 'left' } ); |
||||
* }); |
||||
*/ |
||||
this.options = function( value ) { |
||||
angular.extend( globalOptions, value ); |
||||
}; |
||||
|
||||
/** |
||||
* This allows you to extend the set of trigger mappings available. E.g.: |
||||
* |
||||
* $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); |
||||
*/ |
||||
this.setTriggers = function setTriggers ( triggers ) { |
||||
angular.extend( triggerMap, triggers ); |
||||
}; |
||||
|
||||
/** |
||||
* This is a helper function for translating camel-case to snake-case. |
||||
*/ |
||||
function snake_case(name){ |
||||
var regexp = /[A-Z]/g; |
||||
var separator = '-'; |
||||
return name.replace(regexp, function(letter, pos) { |
||||
return (pos ? separator : '') + letter.toLowerCase(); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Returns the actual instance of the $tooltip service. |
||||
* TODO support multiple triggers |
||||
*/ |
||||
this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { |
||||
return function $tooltip ( type, prefix, defaultTriggerShow ) { |
||||
var options = angular.extend( {}, defaultOptions, globalOptions ); |
||||
|
||||
/** |
||||
* Returns an object of show and hide triggers. |
||||
* |
||||
* If a trigger is supplied, |
||||
* it is used to show the tooltip; otherwise, it will use the `trigger` |
||||
* option passed to the `$tooltipProvider.options` method; else it will |
||||
* default to the trigger supplied to this directive factory. |
||||
* |
||||
* The hide trigger is based on the show trigger. If the `trigger` option |
||||
* was passed to the `$tooltipProvider.options` method, it will use the |
||||
* mapped trigger from `triggerMap` or the passed trigger if the map is |
||||
* undefined; otherwise, it uses the `triggerMap` value of the show |
||||
* trigger; else it will just use the show trigger. |
||||
*/ |
||||
function getTriggers ( trigger ) { |
||||
var show = trigger || options.trigger || defaultTriggerShow; |
||||
var hide = triggerMap[show] || show; |
||||
return { |
||||
show: show, |
||||
hide: hide |
||||
}; |
||||
} |
||||
|
||||
var directiveName = snake_case( type ); |
||||
|
||||
var startSym = $interpolate.startSymbol(); |
||||
var endSym = $interpolate.endSymbol(); |
||||
var template = |
||||
'<div '+ directiveName +'-popup '+ |
||||
'title="'+startSym+'tt_title'+endSym+'" '+ |
||||
'content="'+startSym+'tt_content'+endSym+'" '+ |
||||
'placement="'+startSym+'tt_placement'+endSym+'" '+ |
||||
'animation="tt_animation" '+ |
||||
'is-open="tt_isOpen"'+ |
||||
'>'+ |
||||
'</div>'; |
||||
|
||||
return { |
||||
restrict: 'EA', |
||||
scope: true, |
||||
compile: function (tElem, tAttrs) { |
||||
var tooltipLinker = $compile( template ); |
||||
|
||||
return function link ( scope, element, attrs ) { |
||||
var tooltip; |
||||
var transitionTimeout; |
||||
var popupTimeout; |
||||
var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; |
||||
var triggers = getTriggers( undefined ); |
||||
var hasRegisteredTriggers = false; |
||||
var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); |
||||
|
||||
var positionTooltip = function (){ |
||||
var position, |
||||
ttWidth, |
||||
ttHeight, |
||||
ttPosition; |
||||
// Get the position of the directive element.
|
||||
position = appendToBody ? $position.offset( element ) : $position.position( element ); |
||||
|
||||
// Get the height and width of the tooltip so we can center it.
|
||||
ttWidth = tooltip.prop( 'offsetWidth' ); |
||||
ttHeight = tooltip.prop( 'offsetHeight' ); |
||||
|
||||
// Calculate the tooltip's top and left coordinates to center it with
|
||||
// this directive.
|
||||
switch ( scope.tt_placement ) { |
||||
case 'right': |
||||
ttPosition = { |
||||
top: position.top + position.height / 2 - ttHeight / 2, |
||||
left: position.left + position.width |
||||
}; |
||||
break; |
||||
case 'bottom': |
||||
ttPosition = { |
||||
top: position.top + position.height, |
||||
left: position.left + position.width / 2 - ttWidth / 2 |
||||
}; |
||||
break; |
||||
case 'left': |
||||
ttPosition = { |
||||
top: position.top + position.height / 2 - ttHeight / 2, |
||||
left: position.left - ttWidth |
||||
}; |
||||
break; |
||||
default: |
||||
ttPosition = { |
||||
top: position.top - ttHeight, |
||||
left: position.left + position.width / 2 - ttWidth / 2 |
||||
}; |
||||
break; |
||||
} |
||||
|
||||
ttPosition.top += 'px'; |
||||
ttPosition.left += 'px'; |
||||
|
||||
// Now set the calculated positioning.
|
||||
tooltip.css( ttPosition ); |
||||
|
||||
}; |
||||
|
||||
// By default, the tooltip is not open.
|
||||
// TODO add ability to start tooltip opened
|
||||
scope.tt_isOpen = false; |
||||
|
||||
function toggleTooltipBind () { |
||||
if ( ! scope.tt_isOpen ) { |
||||
showTooltipBind(); |
||||
} else { |
||||
hideTooltipBind(); |
||||
} |
||||
} |
||||
|
||||
// Show the tooltip with delay if specified, otherwise show it immediately
|
||||
function showTooltipBind() { |
||||
if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { |
||||
return; |
||||
} |
||||
if ( scope.tt_popupDelay ) { |
||||
popupTimeout = $timeout( show, scope.tt_popupDelay, false ); |
||||
popupTimeout.then(function(reposition){reposition();}); |
||||
} else { |
||||
show()(); |
||||
} |
||||
} |
||||
|
||||
function hideTooltipBind () { |
||||
scope.$apply(function () { |
||||
hide(); |
||||
}); |
||||
} |
||||
|
||||
// Show the tooltip popup element.
|
||||
function show() { |
||||
|
||||
|
||||
// Don't show empty tooltips.
|
||||
if ( ! scope.tt_content ) { |
||||
return angular.noop; |
||||
} |
||||
|
||||
createTooltip(); |
||||
|
||||
// If there is a pending remove transition, we must cancel it, lest the
|
||||
// tooltip be mysteriously removed.
|
||||
if ( transitionTimeout ) { |
||||
$timeout.cancel( transitionTimeout ); |
||||
} |
||||
|
||||
// Set the initial positioning.
|
||||
tooltip.css({ top: 0, left: 0, display: 'block' }); |
||||
|
||||
// Now we add it to the DOM because need some info about it. But it's not
|
||||
// visible yet anyway.
|
||||
if ( appendToBody ) { |
||||
$document.find( 'body' ).append( tooltip ); |
||||
} else { |
||||
element.after( tooltip ); |
||||
} |
||||
|
||||
positionTooltip(); |
||||
|
||||
// And show the tooltip.
|
||||
scope.tt_isOpen = true; |
||||
scope.$digest(); // digest required as $apply is not called
|
||||
|
||||
// Return positioning function as promise callback for correct
|
||||
// positioning after draw.
|
||||
return positionTooltip; |
||||
} |
||||
|
||||
// Hide the tooltip popup element.
|
||||
function hide() { |
||||
// First things first: we don't show it anymore.
|
||||
scope.tt_isOpen = false; |
||||
|
||||
//if tooltip is going to be shown after delay, we must cancel this
|
||||
$timeout.cancel( popupTimeout ); |
||||
|
||||
// And now we remove it from the DOM. However, if we have animation, we
|
||||
// need to wait for it to expire beforehand.
|
||||
// FIXME: this is a placeholder for a port of the transitions library.
|
||||
if ( scope.tt_animation ) { |
||||
transitionTimeout = $timeout(removeTooltip, 500); |
||||
} else { |
||||
removeTooltip(); |
||||
} |
||||
} |
||||
|
||||
function createTooltip() { |
||||
// There can only be one tooltip element per directive shown at once.
|
||||
if (tooltip) { |
||||
removeTooltip(); |
||||
} |
||||
tooltip = tooltipLinker(scope, function () {}); |
||||
|
||||
// Get contents rendered into the tooltip
|
||||
scope.$digest(); |
||||
} |
||||
|
||||
function removeTooltip() { |
||||
if (tooltip) { |
||||
tooltip.remove(); |
||||
tooltip = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Observe the relevant attributes. |
||||
*/ |
||||
attrs.$observe( type, function ( val ) { |
||||
scope.tt_content = val; |
||||
|
||||
if (!val && scope.tt_isOpen ) { |
||||
hide(); |
||||
} |
||||
}); |
||||
|
||||
attrs.$observe( prefix+'Title', function ( val ) { |
||||
scope.tt_title = val; |
||||
}); |
||||
|
||||
attrs.$observe( prefix+'Placement', function ( val ) { |
||||
scope.tt_placement = angular.isDefined( val ) ? val : options.placement; |
||||
}); |
||||
|
||||
attrs.$observe( prefix+'PopupDelay', function ( val ) { |
||||
var delay = parseInt( val, 10 ); |
||||
scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay; |
||||
}); |
||||
|
||||
var unregisterTriggers = function() { |
||||
if (hasRegisteredTriggers) { |
||||
element.unbind( triggers.show, showTooltipBind ); |
||||
element.unbind( triggers.hide, hideTooltipBind ); |
||||
} |
||||
}; |
||||
|
||||
attrs.$observe( prefix+'Trigger', function ( val ) { |
||||
unregisterTriggers(); |
||||
|
||||
triggers = getTriggers( val ); |
||||
|
||||
if ( triggers.show === triggers.hide ) { |
||||
element.bind( triggers.show, toggleTooltipBind ); |
||||
} else { |
||||
element.bind( triggers.show, showTooltipBind ); |
||||
element.bind( triggers.hide, hideTooltipBind ); |
||||
} |
||||
|
||||
hasRegisteredTriggers = true; |
||||
}); |
||||
|
||||
var animation = scope.$eval(attrs[prefix + 'Animation']); |
||||
scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation; |
||||
|
||||
attrs.$observe( prefix+'AppendToBody', function ( val ) { |
||||
appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody; |
||||
}); |
||||
|
||||
// if a tooltip is attached to <body> we need to remove it on
|
||||
// location change as its parent scope will probably not be destroyed
|
||||
// by the change.
|
||||
if ( appendToBody ) { |
||||
scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { |
||||
if ( scope.tt_isOpen ) { |
||||
hide(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// Make sure tooltip is destroyed and removed.
|
||||
scope.$on('$destroy', function onDestroyTooltip() { |
||||
$timeout.cancel( transitionTimeout ); |
||||
$timeout.cancel( popupTimeout ); |
||||
unregisterTriggers(); |
||||
removeTooltip(); |
||||
}); |
||||
}; |
||||
} |
||||
}; |
||||
}; |
||||
}]; |
||||
}) |
||||
|
||||
.directive( 'tooltipPopup', function () { |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, |
||||
templateUrl: 'template/tooltip/tooltip-popup.html' |
||||
}; |
||||
}) |
||||
|
||||
.directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { |
||||
return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); |
||||
}]) |
||||
|
||||
.directive( 'tooltipHtmlUnsafePopup', function () { |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, |
||||
templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' |
||||
}; |
||||
}) |
||||
|
||||
.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { |
||||
return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); |
||||
}]); |
File diff suppressed because one or more lines are too long
@ -1,332 +0,0 @@
@@ -1,332 +0,0 @@
|
||||
angular.module("ui.bootstrap", ["ui.bootstrap.modal"]); |
||||
angular.module('ui.bootstrap.modal', []) |
||||
|
||||
/** |
||||
* A helper, internal data structure that acts as a map but also allows getting / removing |
||||
* elements in the LIFO order |
||||
*/ |
||||
.factory('$$stackedMap', function () { |
||||
return { |
||||
createNew: function () { |
||||
var stack = []; |
||||
|
||||
return { |
||||
add: function (key, value) { |
||||
stack.push({ |
||||
key: key, |
||||
value: value |
||||
}); |
||||
}, |
||||
get: function (key) { |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
return stack[i]; |
||||
} |
||||
} |
||||
}, |
||||
keys: function() { |
||||
var keys = []; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
keys.push(stack[i].key); |
||||
} |
||||
return keys; |
||||
}, |
||||
top: function () { |
||||
return stack[stack.length - 1]; |
||||
}, |
||||
remove: function (key) { |
||||
var idx = -1; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
idx = i; |
||||
break; |
||||
} |
||||
} |
||||
return stack.splice(idx, 1)[0]; |
||||
}, |
||||
removeTop: function () { |
||||
return stack.splice(stack.length - 1, 1)[0]; |
||||
}, |
||||
length: function () { |
||||
return stack.length; |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}) |
||||
|
||||
/** |
||||
* A helper directive for the $modal service. It creates a backdrop element. |
||||
*/ |
||||
.directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
templateUrl: 'template/modal/backdrop.html', |
||||
link: function (scope, element, attrs) { |
||||
|
||||
//trigger CSS transitions
|
||||
$timeout(function () { |
||||
scope.animate = true; |
||||
}); |
||||
|
||||
scope.close = function (evt) { |
||||
var modal = $modalStack.getTop(); |
||||
if (modal && modal.value.backdrop && modal.value.backdrop != 'static') { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
$modalStack.dismiss(modal.key, 'backdrop click'); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.directive('modalWindow', ['$timeout', function ($timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
scope: { |
||||
index: '@' |
||||
}, |
||||
replace: true, |
||||
transclude: true, |
||||
templateUrl: 'template/modal/window.html', |
||||
link: function (scope, element, attrs) { |
||||
scope.windowClass = attrs.windowClass || ''; |
||||
|
||||
//trigger CSS transitions
|
||||
$timeout(function () { |
||||
scope.animate = true; |
||||
}); |
||||
|
||||
scope.close = function (evt) { |
||||
var modal = $modalStack.getTop(); |
||||
if (modal) { |
||||
$modalStack.dismiss(modal.key, 'close click'); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', |
||||
function ($document, $compile, $rootScope, $$stackedMap) { |
||||
|
||||
var backdropjqLiteEl, backdropDomEl; |
||||
var backdropScope = $rootScope.$new(true); |
||||
var body = $document.find('body').eq(0); |
||||
var openedWindows = $$stackedMap.createNew(); |
||||
var $modalStack = {}; |
||||
|
||||
function backdropIndex() { |
||||
var topBackdropIndex = -1; |
||||
var opened = openedWindows.keys(); |
||||
for (var i = 0; i < opened.length; i++) { |
||||
if (openedWindows.get(opened[i]).value.backdrop) { |
||||
topBackdropIndex = i; |
||||
} |
||||
} |
||||
return topBackdropIndex; |
||||
} |
||||
|
||||
$rootScope.$watch(backdropIndex, function(newBackdropIndex){ |
||||
backdropScope.index = newBackdropIndex; |
||||
}); |
||||
|
||||
function removeModalWindow(modalInstance) { |
||||
|
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
|
||||
//clean up the stack
|
||||
openedWindows.remove(modalInstance); |
||||
|
||||
//remove window DOM element
|
||||
modalWindow.modalDomEl.remove(); |
||||
|
||||
//remove backdrop if no longer needed
|
||||
if (backdropDomEl && backdropIndex() == -1) { |
||||
backdropDomEl.remove(); |
||||
backdropDomEl = undefined; |
||||
} |
||||
|
||||
//destroy scope
|
||||
modalWindow.modalScope.$destroy(); |
||||
} |
||||
|
||||
$document.bind('keydown', function (evt) { |
||||
var modal; |
||||
|
||||
if (evt.which === 27) { |
||||
modal = openedWindows.top(); |
||||
if (modal && modal.value.keyboard) { |
||||
$rootScope.$apply(function () { |
||||
$modalStack.dismiss(modal.key); |
||||
}); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
$modalStack.open = function (modalInstance, modal) { |
||||
openedWindows.add(modalInstance, { |
||||
deferred: modal.deferred, |
||||
modalScope: modal.scope, |
||||
backdrop: modal.backdrop, |
||||
keyboard: modal.keyboard |
||||
}); |
||||
|
||||
var angularDomEl = angular.element('<div modal-window></div>'); |
||||
angularDomEl.attr('window-class', modal.windowClass); |
||||
angularDomEl.attr('index', openedWindows.length() - 1); |
||||
angularDomEl.html(modal.content); |
||||
|
||||
var modalDomEl = $compile(angularDomEl)(modal.scope); |
||||
openedWindows.top().value.modalDomEl = modalDomEl; |
||||
body.append(modalDomEl); |
||||
|
||||
if (backdropIndex() >= 0 && !backdropDomEl) { |
||||
backdropjqLiteEl = angular.element('<div modal-backdrop></div>'); |
||||
backdropDomEl = $compile(backdropjqLiteEl)(backdropScope); |
||||
body.append(backdropDomEl); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.close = function (modalInstance, result) { |
||||
var modal = openedWindows.get(modalInstance); |
||||
if (modal) { |
||||
modal.value.deferred.resolve(result); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.dismiss = function (modalInstance, reason) { |
||||
console.trace(); |
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
if (modalWindow) { |
||||
modalWindow.deferred.reject(reason); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.getTop = function () { |
||||
return openedWindows.top(); |
||||
}; |
||||
|
||||
$modalStack.dismissAll = function () { |
||||
var modal; |
||||
while (modal = openedWindows.top()) { |
||||
$rootScope.$apply(function () { |
||||
$modalStack.dismiss(modal.key); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
return $modalStack; |
||||
}]) |
||||
|
||||
.provider('$modal', function () { |
||||
|
||||
var $modalProvider = { |
||||
options: { |
||||
backdrop: true, //can be also false or 'static'
|
||||
keyboard: true |
||||
}, |
||||
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', |
||||
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { |
||||
|
||||
var $modal = {}; |
||||
|
||||
function getTemplatePromise(options) { |
||||
return options.template ? $q.when(options.template) : |
||||
$http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { |
||||
return result.data; |
||||
}); |
||||
} |
||||
|
||||
function getResolvePromises(resolves) { |
||||
var promisesArr = []; |
||||
angular.forEach(resolves, function (value, key) { |
||||
if (angular.isFunction(value) || angular.isArray(value)) { |
||||
promisesArr.push($q.when($injector.invoke(value))); |
||||
} |
||||
}); |
||||
return promisesArr; |
||||
} |
||||
|
||||
$modal.open = function (modalOptions) { |
||||
|
||||
var modalResultDeferred = $q.defer(); |
||||
var modalOpenedDeferred = $q.defer(); |
||||
|
||||
//prepare an instance of a modal to be injected into controllers and returned to a caller
|
||||
var modalInstance = { |
||||
result: modalResultDeferred.promise, |
||||
opened: modalOpenedDeferred.promise, |
||||
close: function (result) { |
||||
$modalStack.close(modalInstance, result); |
||||
}, |
||||
dismiss: function (reason) { |
||||
$modalStack.dismiss(modalInstance, reason); |
||||
} |
||||
}; |
||||
|
||||
//merge and clean up options
|
||||
modalOptions = angular.extend({}, $modalProvider.options, modalOptions); |
||||
modalOptions.resolve = modalOptions.resolve || {}; |
||||
|
||||
//verify options
|
||||
if (!modalOptions.template && !modalOptions.templateUrl) { |
||||
throw new Error('One of template or templateUrl options is required.'); |
||||
} |
||||
|
||||
var templateAndResolvePromise = |
||||
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); |
||||
|
||||
|
||||
templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { |
||||
|
||||
var modalScope = (modalOptions.scope || $rootScope).$new(); |
||||
modalScope.$close = modalInstance.close; |
||||
modalScope.$dismiss = modalInstance.dismiss; |
||||
|
||||
var ctrlInstance, ctrlLocals = {}; |
||||
var resolveIter = 1; |
||||
|
||||
//controllers
|
||||
if (modalOptions.controller) { |
||||
ctrlLocals.$scope = modalScope; |
||||
ctrlLocals.$modalInstance = modalInstance; |
||||
angular.forEach(modalOptions.resolve, function (value, key) { |
||||
ctrlLocals[key] = tplAndVars[resolveIter++]; |
||||
}); |
||||
|
||||
ctrlInstance = $controller(modalOptions.controller, ctrlLocals); |
||||
} |
||||
|
||||
$modalStack.open(modalInstance, { |
||||
scope: modalScope, |
||||
deferred: modalResultDeferred, |
||||
content: tplAndVars[0], |
||||
backdrop: modalOptions.backdrop, |
||||
keyboard: modalOptions.keyboard, |
||||
windowClass: modalOptions.windowClass |
||||
}); |
||||
|
||||
}, function resolveError(reason) { |
||||
modalResultDeferred.reject(reason); |
||||
}); |
||||
|
||||
templateAndResolvePromise.then(function () { |
||||
modalOpenedDeferred.resolve(true); |
||||
}, function () { |
||||
modalOpenedDeferred.reject(false); |
||||
}); |
||||
|
||||
return modalInstance; |
||||
}; |
||||
|
||||
return $modal; |
||||
}] |
||||
}; |
||||
|
||||
return $modalProvider; |
||||
}); |
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
angular.module("ui.bootstrap",["ui.bootstrap.modal"]),angular.module("ui.bootstrap.modal",[]).factory("$$stackedMap",function(){return{createNew:function(){var a=[];return{add:function(b,c){a.push({key:b,value:c})},get:function(b){for(var c=0;c<a.length;c++)if(b==a[c].key)return a[c]},keys:function(){for(var b=[],c=0;c<a.length;c++)b.push(a[c].key);return b},top:function(){return a[a.length-1]},remove:function(b){for(var c=-1,d=0;d<a.length;d++)if(b==a[d].key){c=d;break}return a.splice(c,1)[0]},removeTop:function(){return a.splice(a.length-1,1)[0]},length:function(){return a.length}}}}}).directive("modalBackdrop",["$modalStack","$timeout",function(a,b){return{restrict:"EA",replace:!0,templateUrl:"template/modal/backdrop.html",link:function(c){b(function(){c.animate=!0}),c.close=function(b){var c=a.getTop();c&&c.value.backdrop&&"static"!=c.value.backdrop&&(b.preventDefault(),b.stopPropagation(),a.dismiss(c.key,"backdrop click"))}}}}]).directive("modalWindow",["$timeout",function(a){return{restrict:"EA",scope:{index:"@"},replace:!0,transclude:!0,templateUrl:"template/modal/window.html",link:function(b,c,d){b.windowClass=d.windowClass||"",a(function(){b.animate=!0})}}}]).factory("$modalStack",["$document","$compile","$rootScope","$$stackedMap",function(a,b,c,d){function e(){for(var a=-1,b=k.keys(),c=0;c<b.length;c++)k.get(b[c]).value.backdrop&&(a=c);return a}function f(a){var b=k.get(a).value;k.remove(a),b.modalDomEl.remove(),h&&-1==e()&&(h.remove(),h=void 0),b.modalScope.$destroy()}var g,h,i=c.$new(!0),j=a.find("body").eq(0),k=d.createNew(),l={};return c.$watch(e,function(a){i.index=a}),a.bind("keydown",function(a){var b;27===a.which&&(b=k.top(),b&&b.value.keyboard&&c.$apply(function(){l.dismiss(b.key)}))}),l.open=function(a,c){k.add(a,{deferred:c.deferred,modalScope:c.scope,backdrop:c.backdrop,keyboard:c.keyboard});var d=angular.element("<div modal-window></div>");d.attr("window-class",c.windowClass),d.attr("index",k.length()-1),d.html(c.content);var f=b(d)(c.scope);k.top().value.modalDomEl=f,j.append(f),e()>=0&&!h&&(g=angular.element("<div modal-backdrop></div>"),h=b(g)(i),j.append(h))},l.close=function(a,b){var c=k.get(a);c&&(c.value.deferred.resolve(b),f(a))},l.dismiss=function(a,b){var c=k.get(a).value;c&&(c.deferred.reject(b),f(a))},l.getTop=function(){return k.top()},l}]).provider("$modal",function(){var a={options:{backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$http","$templateCache","$controller","$modalStack",function(b,c,d,e,f,g,h){function i(a){return a.template?d.when(a.template):e.get(a.templateUrl,{cache:f}).then(function(a){return a.data})}function j(a){var c=[];return angular.forEach(a,function(a){(angular.isFunction(a)||angular.isArray(a))&&c.push(d.when(b.invoke(a)))}),c}var k={};return k.open=function(b){var e=d.defer(),f=d.defer(),k={result:e.promise,opened:f.promise,close:function(a){h.close(k,a)},dismiss:function(a){h.dismiss(k,a)}};if(b=angular.extend({},a.options,b),b.resolve=b.resolve||{},!b.template&&!b.templateUrl)throw new Error("One of template or templateUrl options is required.");var l=d.all([i(b)].concat(j(b.resolve)));return l.then(function(a){var d=(b.scope||c).$new();d.$close=k.close,d.$dismiss=k.dismiss;var f,i={},j=1;b.controller&&(i.$scope=d,i.$modalInstance=k,angular.forEach(b.resolve,function(b,c){i[c]=a[j++]}),f=g(b.controller,i)),h.open(k,{scope:d,deferred:e,content:a[0],backdrop:b.backdrop,keyboard:b.keyboard,windowClass:b.windowClass})},function(a){e.reject(a)}),l.then(function(){f.resolve(!0)},function(){f.reject(!1)}),k},k}]};return a}); |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,353 +0,0 @@
@@ -1,353 +0,0 @@
|
||||
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.modal"]); |
||||
angular.module("ui.bootstrap.tpls", ["template/modal/backdrop.html","template/modal/window.html"]); |
||||
angular.module('ui.bootstrap.modal', []) |
||||
|
||||
/** |
||||
* A helper, internal data structure that acts as a map but also allows getting / removing |
||||
* elements in the LIFO order |
||||
*/ |
||||
.factory('$$stackedMap', function () { |
||||
return { |
||||
createNew: function () { |
||||
var stack = []; |
||||
|
||||
return { |
||||
add: function (key, value) { |
||||
stack.push({ |
||||
key: key, |
||||
value: value |
||||
}); |
||||
}, |
||||
get: function (key) { |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
return stack[i]; |
||||
} |
||||
} |
||||
}, |
||||
keys: function() { |
||||
var keys = []; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
keys.push(stack[i].key); |
||||
} |
||||
return keys; |
||||
}, |
||||
top: function () { |
||||
return stack[stack.length - 1]; |
||||
}, |
||||
remove: function (key) { |
||||
var idx = -1; |
||||
for (var i = 0; i < stack.length; i++) { |
||||
if (key == stack[i].key) { |
||||
idx = i; |
||||
break; |
||||
} |
||||
} |
||||
return stack.splice(idx, 1)[0]; |
||||
}, |
||||
removeTop: function () { |
||||
return stack.splice(stack.length - 1, 1)[0]; |
||||
}, |
||||
length: function () { |
||||
return stack.length; |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}) |
||||
|
||||
/** |
||||
* A helper directive for the $modal service. It creates a backdrop element. |
||||
*/ |
||||
.directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
templateUrl: 'template/modal/backdrop.html', |
||||
link: function (scope, element, attrs) { |
||||
|
||||
//trigger CSS transitions
|
||||
$timeout(function () { |
||||
scope.animate = true; |
||||
}); |
||||
|
||||
scope.close = function (evt) { |
||||
var modal = $modalStack.getTop(); |
||||
if (modal && modal.value.backdrop && modal.value.backdrop != 'static') { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
$modalStack.dismiss(modal.key, 'backdrop click'); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { |
||||
return { |
||||
restrict: 'EA', |
||||
scope: { |
||||
index: '@' |
||||
}, |
||||
replace: true, |
||||
transclude: true, |
||||
templateUrl: 'template/modal/window.html', |
||||
link: function (scope, element, attrs) { |
||||
scope.windowClass = attrs.windowClass || ''; |
||||
|
||||
//trigger CSS transitions
|
||||
$timeout(function () { |
||||
scope.animate = true; |
||||
}); |
||||
|
||||
scope.close = function (evt) { |
||||
var modal = $modalStack.getTop(); |
||||
if (modal) { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
$modalStack.dismiss(modal.key, 'backdrop click'); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
}]) |
||||
|
||||
.factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', |
||||
function ($document, $compile, $rootScope, $$stackedMap) { |
||||
|
||||
var backdropjqLiteEl, backdropDomEl; |
||||
var backdropScope = $rootScope.$new(true); |
||||
var body = $document.find('body').eq(0); |
||||
var openedWindows = $$stackedMap.createNew(); |
||||
var $modalStack = {}; |
||||
|
||||
function backdropIndex() { |
||||
var topBackdropIndex = -1; |
||||
var opened = openedWindows.keys(); |
||||
for (var i = 0; i < opened.length; i++) { |
||||
if (openedWindows.get(opened[i]).value.backdrop) { |
||||
topBackdropIndex = i; |
||||
} |
||||
} |
||||
return topBackdropIndex; |
||||
} |
||||
|
||||
$rootScope.$watch(backdropIndex, function(newBackdropIndex){ |
||||
backdropScope.index = newBackdropIndex; |
||||
}); |
||||
|
||||
function removeModalWindow(modalInstance) { |
||||
|
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
|
||||
//clean up the stack
|
||||
openedWindows.remove(modalInstance); |
||||
|
||||
//remove window DOM element
|
||||
modalWindow.modalDomEl.remove(); |
||||
|
||||
//remove backdrop if no longer needed
|
||||
if (backdropDomEl && backdropIndex() == -1) { |
||||
backdropDomEl.remove(); |
||||
backdropDomEl = undefined; |
||||
} |
||||
|
||||
//destroy scope
|
||||
modalWindow.modalScope.$destroy(); |
||||
} |
||||
|
||||
$document.bind('keydown', function (evt) { |
||||
var modal; |
||||
|
||||
if (evt.which === 27) { |
||||
modal = openedWindows.top(); |
||||
if (modal && modal.value.keyboard) { |
||||
$rootScope.$apply(function () { |
||||
$modalStack.dismiss(modal.key); |
||||
}); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
$modalStack.open = function (modalInstance, modal) { |
||||
|
||||
openedWindows.add(modalInstance, { |
||||
deferred: modal.deferred, |
||||
modalScope: modal.scope, |
||||
backdrop: modal.backdrop, |
||||
keyboard: modal.keyboard |
||||
}); |
||||
|
||||
var angularDomEl = angular.element('<div modal-window></div>'); |
||||
angularDomEl.attr('window-class', modal.windowClass); |
||||
angularDomEl.attr('index', openedWindows.length() - 1); |
||||
angularDomEl.html(modal.content); |
||||
|
||||
var modalDomEl = $compile(angularDomEl)(modal.scope); |
||||
openedWindows.top().value.modalDomEl = modalDomEl; |
||||
body.append(modalDomEl); |
||||
|
||||
if (backdropIndex() >= 0 && !backdropDomEl) { |
||||
backdropjqLiteEl = angular.element('<div modal-backdrop></div>'); |
||||
backdropDomEl = $compile(backdropjqLiteEl)(backdropScope); |
||||
body.append(backdropDomEl); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.close = function (modalInstance, result) { |
||||
var modal = openedWindows.get(modalInstance); |
||||
if (modal) { |
||||
modal.value.deferred.resolve(result); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.dismiss = function (modalInstance, reason) { |
||||
var modalWindow = openedWindows.get(modalInstance).value; |
||||
if (modalWindow) { |
||||
modalWindow.deferred.reject(reason); |
||||
removeModalWindow(modalInstance); |
||||
} |
||||
}; |
||||
|
||||
$modalStack.dismissAll = function () { |
||||
var modal; |
||||
while (openedWindows.length()) { |
||||
if (modal = openedWindows.top()) { |
||||
$modalStack.dismiss(modal.key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$modalStack.getTop = function () { |
||||
return openedWindows.top(); |
||||
}; |
||||
|
||||
return $modalStack; |
||||
}]) |
||||
|
||||
.provider('$modal', function () { |
||||
|
||||
var $modalProvider = { |
||||
options: { |
||||
backdrop: true, //can be also false or 'static'
|
||||
keyboard: true |
||||
}, |
||||
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', |
||||
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { |
||||
|
||||
var $modal = {}; |
||||
|
||||
function getTemplatePromise(options) { |
||||
return options.template ? $q.when(options.template) : |
||||
$http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { |
||||
return result.data; |
||||
}); |
||||
} |
||||
|
||||
function getResolvePromises(resolves) { |
||||
var promisesArr = []; |
||||
angular.forEach(resolves, function (value, key) { |
||||
if (angular.isFunction(value) || angular.isArray(value)) { |
||||
promisesArr.push($q.when($injector.invoke(value))); |
||||
} |
||||
}); |
||||
return promisesArr; |
||||
} |
||||
|
||||
$modal.open = function (modalOptions) { |
||||
|
||||
var modalResultDeferred = $q.defer(); |
||||
var modalOpenedDeferred = $q.defer(); |
||||
|
||||
//prepare an instance of a modal to be injected into controllers and returned to a caller
|
||||
var modalInstance = { |
||||
result: modalResultDeferred.promise, |
||||
opened: modalOpenedDeferred.promise, |
||||
close: function (result) { |
||||
$modalStack.close(modalInstance, result); |
||||
}, |
||||
dismiss: function (reason) { |
||||
$modalStack.dismiss(modalInstance, reason); |
||||
} |
||||
}; |
||||
|
||||
//merge and clean up options
|
||||
modalOptions = angular.extend({}, $modalProvider.options, modalOptions); |
||||
modalOptions.resolve = modalOptions.resolve || {}; |
||||
|
||||
//verify options
|
||||
if (!modalOptions.template && !modalOptions.templateUrl) { |
||||
throw new Error('One of template or templateUrl options is required.'); |
||||
} |
||||
|
||||
var templateAndResolvePromise = |
||||
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); |
||||
|
||||
|
||||
templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { |
||||
|
||||
var modalScope = (modalOptions.scope || $rootScope).$new(); |
||||
modalScope.$close = modalInstance.close; |
||||
modalScope.$dismiss = modalInstance.dismiss; |
||||
|
||||
var ctrlInstance, ctrlLocals = {}; |
||||
var resolveIter = 1; |
||||
|
||||
//controllers
|
||||
if (modalOptions.controller) { |
||||
ctrlLocals.$scope = modalScope; |
||||
ctrlLocals.$modalInstance = modalInstance; |
||||
angular.forEach(modalOptions.resolve, function (value, key) { |
||||
ctrlLocals[key] = tplAndVars[resolveIter++]; |
||||
}); |
||||
|
||||
ctrlInstance = $controller(modalOptions.controller, ctrlLocals); |
||||
} |
||||
|
||||
$modalStack.open(modalInstance, { |
||||
scope: modalScope, |
||||
deferred: modalResultDeferred, |
||||
content: tplAndVars[0], |
||||
backdrop: modalOptions.backdrop, |
||||
keyboard: modalOptions.keyboard, |
||||
windowClass: modalOptions.windowClass |
||||
}); |
||||
|
||||
}, function resolveError(reason) { |
||||
modalResultDeferred.reject(reason); |
||||
}); |
||||
|
||||
templateAndResolvePromise.then(function () { |
||||
modalOpenedDeferred.resolve(true); |
||||
}, function () { |
||||
modalOpenedDeferred.reject(false); |
||||
}); |
||||
|
||||
return modalInstance; |
||||
}; |
||||
|
||||
return $modal; |
||||
}] |
||||
}; |
||||
|
||||
return $modalProvider; |
||||
}); |
||||
|
||||
angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) { |
||||
$templateCache.put("template/modal/backdrop.html", |
||||
"<div class=\"modal-backdrop fade\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1040 + index*10}\" ng-click=\"close($event)\"></div>"); |
||||
}]); |
||||
|
||||
angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { |
||||
$templateCache.put("template/modal/window.html", |
||||
"<div class=\"modal fade {{ windowClass }}\" tabindex=\"-1\" role=\"dialog\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\">\ |
||||
<div class=\"modal_close_wrap\" ng-click=\"close($event)\">\ |
||||
<div class=\"modal_close\"></div>\ |
||||
</div>\ |
||||
<div class=\"modal-dialog\">\ |
||||
<div class=\"modal-content\" ng-transclude>\ |
||||
</div>\ |
||||
</div>\ |
||||
</div>"); |
||||
}]); |
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
angular.module("ui.bootstrap",["ui.bootstrap.tpls","ui.bootstrap.modal"]),angular.module("ui.bootstrap.tpls",["template/modal/backdrop.html","template/modal/window.html"]),angular.module("ui.bootstrap.modal",[]).factory("$$stackedMap",function(){return{createNew:function(){var a=[];return{add:function(b,c){a.push({key:b,value:c})},get:function(b){for(var c=0;c<a.length;c++)if(b==a[c].key)return a[c]},keys:function(){for(var b=[],c=0;c<a.length;c++)b.push(a[c].key);return b},top:function(){return a[a.length-1]},remove:function(b){for(var c=-1,d=0;d<a.length;d++)if(b==a[d].key){c=d;break}return a.splice(c,1)[0]},removeTop:function(){return a.splice(a.length-1,1)[0]},length:function(){return a.length}}}}}).directive("modalBackdrop",["$modalStack","$timeout",function(a,b){return{restrict:"EA",replace:!0,templateUrl:"template/modal/backdrop.html",link:function(c){b(function(){c.animate=!0}),c.close=function(b){var c=a.getTop();c&&c.value.backdrop&&"static"!=c.value.backdrop&&(b.preventDefault(),b.stopPropagation(),a.dismiss(c.key,"backdrop click"))}}}}]).directive("modalWindow",["$timeout",function(a){return{restrict:"EA",scope:{index:"@"},replace:!0,transclude:!0,templateUrl:"template/modal/window.html",link:function(b,c,d){b.windowClass=d.windowClass||"",a(function(){b.animate=!0})}}}]).factory("$modalStack",["$document","$compile","$rootScope","$$stackedMap",function(a,b,c,d){function e(){for(var a=-1,b=k.keys(),c=0;c<b.length;c++)k.get(b[c]).value.backdrop&&(a=c);return a}function f(a){var b=k.get(a).value;k.remove(a),b.modalDomEl.remove(),h&&-1==e()&&(h.remove(),h=void 0),b.modalScope.$destroy()}var g,h,i=c.$new(!0),j=a.find("body").eq(0),k=d.createNew(),l={};return c.$watch(e,function(a){i.index=a}),a.bind("keydown",function(a){var b;27===a.which&&(b=k.top(),b&&b.value.keyboard&&c.$apply(function(){l.dismiss(b.key)}))}),l.open=function(a,c){k.add(a,{deferred:c.deferred,modalScope:c.scope,backdrop:c.backdrop,keyboard:c.keyboard});var d=angular.element("<div modal-window></div>");d.attr("window-class",c.windowClass),d.attr("index",k.length()-1),d.html(c.content);var f=b(d)(c.scope);k.top().value.modalDomEl=f,j.append(f),e()>=0&&!h&&(g=angular.element("<div modal-backdrop></div>"),h=b(g)(i),j.append(h))},l.close=function(a,b){var c=k.get(a);c&&(c.value.deferred.resolve(b),f(a))},l.dismiss=function(a,b){var c=k.get(a).value;c&&(c.deferred.reject(b),f(a))},l.getTop=function(){return k.top()},l}]).provider("$modal",function(){var a={options:{backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$http","$templateCache","$controller","$modalStack",function(b,c,d,e,f,g,h){function i(a){return a.template?d.when(a.template):e.get(a.templateUrl,{cache:f}).then(function(a){return a.data})}function j(a){var c=[];return angular.forEach(a,function(a){(angular.isFunction(a)||angular.isArray(a))&&c.push(d.when(b.invoke(a)))}),c}var k={};return k.open=function(b){var e=d.defer(),f=d.defer(),k={result:e.promise,opened:f.promise,close:function(a){h.close(k,a)},dismiss:function(a){h.dismiss(k,a)}};if(b=angular.extend({},a.options,b),b.resolve=b.resolve||{},!b.template&&!b.templateUrl)throw new Error("One of template or templateUrl options is required.");var l=d.all([i(b)].concat(j(b.resolve)));return l.then(function(a){var d=(b.scope||c).$new();d.$close=k.close,d.$dismiss=k.dismiss;var f,i={},j=1;b.controller&&(i.$scope=d,i.$modalInstance=k,angular.forEach(b.resolve,function(b,c){i[c]=a[j++]}),f=g(b.controller,i)),h.open(k,{scope:d,deferred:e,content:a[0],backdrop:b.backdrop,keyboard:b.keyboard,windowClass:b.windowClass})},function(a){e.reject(a)}),l.then(function(){f.resolve(!0)},function(){f.reject(!1)}),k},k}]};return a}),angular.module("template/modal/backdrop.html",[]).run(["$templateCache",function(a){a.put("template/modal/backdrop.html",'<div class="modal-backdrop fade" ng-class="{in: animate}" ng-style="{\'z-index\': 1040 + index*10}" ng-click="close($event)"></div>')}]),angular.module("template/modal/window.html",[]).run(["$templateCache",function(a){a.put("template/modal/window.html",'<div class="modal fade {{ windowClass }}" ng-class="{in: animate}" ng-style="{\'z-index\': 1050 + index*10}" ng-transclude></div>')}]); |
Loading…
Reference in new issue