rails-angular-strap 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +21 -0
- data/lib/rails-angular-strap.rb +11 -0
- data/lib/rails-angular-strap/engine.rb +4 -0
- data/lib/rails-angular-strap/version.rb +4 -0
- data/vendor/assets/javascripts/angular-strap.js +2 -0
- data/vendor/assets/javascripts/angular-strap.min.js +2 -0
- data/vendor/assets/javascripts/angular-strap/angular-strap.js +5014 -0
- data/vendor/assets/javascripts/angular-strap/angular-strap.min.js +11 -0
- data/vendor/assets/javascripts/angular-strap/angular-strap.tpl.js +89 -0
- data/vendor/assets/javascripts/angular-strap/angular-strap.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/affix.js +249 -0
- data/vendor/assets/javascripts/angular-strap/modules/affix.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/affix.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/alert.js +120 -0
- data/vendor/assets/javascripts/angular-strap/modules/alert.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/alert.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/alert.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/alert.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/aside.js +96 -0
- data/vendor/assets/javascripts/angular-strap/modules/aside.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/aside.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/aside.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/aside.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/button.js +177 -0
- data/vendor/assets/javascripts/angular-strap/modules/button.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/button.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/collapse.js +273 -0
- data/vendor/assets/javascripts/angular-strap/modules/collapse.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/collapse.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-formatter.js +61 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-formatter.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-formatter.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-parser.js +273 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-parser.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/date-parser.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/datepicker.js +640 -0
- data/vendor/assets/javascripts/angular-strap/modules/datepicker.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/datepicker.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/datepicker.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/datepicker.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/debounce.js +62 -0
- data/vendor/assets/javascripts/angular-strap/modules/debounce.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/debounce.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/dimensions.js +156 -0
- data/vendor/assets/javascripts/angular-strap/modules/dimensions.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/dimensions.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/dropdown.js +149 -0
- data/vendor/assets/javascripts/angular-strap/modules/dropdown.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/dropdown.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/dropdown.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/dropdown.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/modal.js +349 -0
- data/vendor/assets/javascripts/angular-strap/modules/modal.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/modal.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/modal.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/modal.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/navbar.js +72 -0
- data/vendor/assets/javascripts/angular-strap/modules/navbar.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/navbar.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/parse-options.js +76 -0
- data/vendor/assets/javascripts/angular-strap/modules/parse-options.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/parse-options.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/popover.js +112 -0
- data/vendor/assets/javascripts/angular-strap/modules/popover.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/popover.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/popover.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/popover.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/raf.js +61 -0
- data/vendor/assets/javascripts/angular-strap/modules/raf.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/raf.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/scrollspy.js +261 -0
- data/vendor/assets/javascripts/angular-strap/modules/scrollspy.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/scrollspy.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/select.js +325 -0
- data/vendor/assets/javascripts/angular-strap/modules/select.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/select.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/select.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/select.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/tab.js +186 -0
- data/vendor/assets/javascripts/angular-strap/modules/tab.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/tab.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/tab.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/tab.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/timepicker.js +485 -0
- data/vendor/assets/javascripts/angular-strap/modules/timepicker.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/timepicker.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/timepicker.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/timepicker.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/tooltip.js +690 -0
- data/vendor/assets/javascripts/angular-strap/modules/tooltip.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/tooltip.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/tooltip.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/tooltip.tpl.min.js +8 -0
- data/vendor/assets/javascripts/angular-strap/modules/typeahead.js +266 -0
- data/vendor/assets/javascripts/angular-strap/modules/typeahead.min.js +9 -0
- data/vendor/assets/javascripts/angular-strap/modules/typeahead.min.js.map +1 -0
- data/vendor/assets/javascripts/angular-strap/modules/typeahead.tpl.js +14 -0
- data/vendor/assets/javascripts/angular-strap/modules/typeahead.tpl.min.js +8 -0
- metadata +143 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.1.6 - 2015-01-11
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
"use strict";angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,a,n,i,o,r,u){function s(t,a,n){function i(e,a){if(t[0].createTextRange){var n=t[0].createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",a),n.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function s(){t[0].focus()}var m=r(t,angular.extend({},e,n)),c=n.scope,g=m.$options,p=m.$scope,$=g.lang,f=function(e,t){return o.formatDate(e,t,$)},h=0,w=a.$dateValue||new Date,v={hour:w.getHours(),meridian:w.getHours()<12,minute:w.getMinutes(),second:w.getSeconds(),millisecond:w.getMilliseconds()},y=o.getDatetimeFormat(g.timeFormat,$),T=o.hoursFormat(y),D=o.timeSeparator(y),S=o.minutesFormat(y),V=o.showAM(y);p.$iconUp=g.iconUp,p.$iconDown=g.iconDown,p.$select=function(e,t){m.select(e,t)},p.$moveIndex=function(e,t){m.$moveIndex(e,t)},p.$switchMeridian=function(e){m.switchMeridian(e)},m.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(m.$date=e,angular.extend(v,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),m.$build()):m.$isBuilt||m.$build()},m.select=function(e,t,n){(!a.$dateValue||isNaN(a.$dateValue.getTime()))&&(a.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?a.$dateValue.setHours(e.getHours()):1===t&&a.$dateValue.setMinutes(e.getMinutes()),a.$setViewValue(angular.copy(a.$dateValue)),a.$render(),g.autoclose&&!n&&u(function(){m.hide(!0)})},m.switchMeridian=function(e){if(a.$dateValue&&!isNaN(a.$dateValue.getTime())){var t=(e||a.$dateValue).getHours();a.$dateValue.setHours(12>t?t+12:t-12),a.$setViewValue(angular.copy(a.$dateValue)),a.$render()}},m.$build=function(){var e,t,a=p.midIndex=parseInt(g.length/2,10),n=[];for(e=0;e<g.length;e++)t=new Date(1970,0,1,v.hour-(a-e)*g.hourStep),n.push({date:t,label:f(t,T),selected:m.$date&&m.$isSelected(t,0),disabled:m.$isDisabled(t,0)});var i,o=[];for(e=0;e<g.length;e++)i=new Date(1970,0,1,0,v.minute-(a-e)*g.minuteStep),o.push({date:i,label:f(i,S),selected:m.$date&&m.$isSelected(i,1),disabled:m.$isDisabled(i,1)});var r=[];for(e=0;e<g.length;e++)r.push([n[e],o[e]]);p.rows=r,p.showAM=V,p.isAM=(m.$date||n[a].date).getHours()<12,p.timeSeparator=D,m.$isBuilt=!0},m.$isSelected=function(e,t){return m.$date?0===t?e.getHours()===m.$date.getHours():1===t?e.getMinutes()===m.$date.getMinutes():void 0:!1},m.$isDisabled=function(e,t){var a;return 0===t?a=e.getTime()+6e4*v.minute:1===t&&(a=e.getTime()+36e5*v.hour),a<1*g.minTime||a>1*g.maxTime},p.$arrowAction=function(e,t){"picker"===g.arrowBehavior?m.$setTimeByStep(e,t):m.$moveIndex(e,t)},m.$setTimeByStep=function(e,t){{var a=new Date(m.$date),n=a.getHours(),i=(f(a,T).length,a.getMinutes());f(a,S).length}0===t?a.setHours(n-parseInt(g.hourStep,10)*e):a.setMinutes(i-parseInt(g.minuteStep,10)*e),m.select(a,t,!0)},m.$moveIndex=function(e,t){var a;0===t?(a=new Date(1970,0,1,v.hour+e*g.length,v.minute),angular.extend(v,{hour:a.getHours()})):1===t&&(a=new Date(1970,0,1,v.hour,v.minute+e*g.length*g.minuteStep),angular.extend(v,{minute:a.getMinutes()})),m.$build()},m.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},m.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return m.hide(!0);var t=new Date(m.$date),a=t.getHours(),n=f(t,T).length,o=t.getMinutes(),r=f(t,S).length,u=/(37|39)/.test(e.keyCode),s=2+1*V;u&&(37===e.keyCode?h=1>h?s-1:h-1:39===e.keyCode&&(h=s-1>h?h+1:0));var l=[0,n];0===h?(38===e.keyCode?t.setHours(a-parseInt(g.hourStep,10)):40===e.keyCode&&t.setHours(a+parseInt(g.hourStep,10)),n=f(t,T).length,l=[0,n]):1===h?(38===e.keyCode?t.setMinutes(o-parseInt(g.minuteStep,10)):40===e.keyCode&&t.setMinutes(o+parseInt(g.minuteStep,10)),r=f(t,S).length,l=[n+1,n+1+r]):2===h&&(u||m.switchMeridian(),l=[n+1+r+1,n+1+r+3]),m.select(t,h,!0),i(l[0],l[1]),c.$digest()}};var k=m.init;m.init=function(){return l&&g.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",s)),void k())};var b=m.destroy;m.destroy=function(){l&&g.useNative&&t.off("click",s),b()};var M=m.show;m.show=function(){M(),u(function(){m.$element.on(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.on("keydown",m.$onKeyDown)},0,!1)};var N=m.hide;return m.hide=function(e){m.$isShown&&(m.$element.off(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.off("keydown",m.$onKeyDown),N(e))},m}var l=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&l;return e.lang||(e.lang=o.getDefaultLocale()),s.defaults=e,s}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,a,n,i,o){{var r=o.defaults,u=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,a,s){function l(e){if(angular.isDate(e)){var t=isNaN(m.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=m.minTime,a=isNaN(m.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=m.maxTime,n=t&&a;s.$setValidity("date",n),s.$setValidity("min",t),s.$setValidity("max",a),n&&(s.$dateValue=e)}}function d(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":p(s.$dateValue,m.timeFormat)}var m={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown","id"],function(e){angular.isDefined(a[e])&&(m[e]=a[e])}),a.bsShow&&e.$watch(a.bsShow,function(e){c&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?c.show():c.hide())}),u&&(m.useNative||r.useNative)&&(m.timeFormat="HH:mm");var c=o(t,s,m);m=c.$options;var g=m.lang,p=function(e,t){return n.formatDate(e,t,g)},$=i({format:m.timeFormat,lang:g});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){c.$options[e]=$.getTimeForAttribute(e,t),!isNaN(c.$options[e])&&c.$build(),l(s.$dateValue)})}),e.$watch(a.ngModel,function(){c.update(s.$dateValue)},!0),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=angular.isDate(e)?e:$.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(l(t),"string"===m.timeType?p(t,m.modelTimeFormat||m.timeFormat):"number"===m.timeType?s.$dateValue.getTime():"unix"===m.timeType?s.$dateValue.getTime()/1e3:"iso"===m.timeType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===m.timeType?$.parse(e,null,m.modelTimeFormat):new Date("unix"===m.timeType?1e3*e:e),s.$dateValue=t,d()}),s.$render=function(){t.val(d())},e.$on("$destroy",function(){c&&c.destroy(),m=null,c=null})}}}]);
|
|
9
|
+
//# sourceMappingURL=timepicker.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["timepicker/timepicker.js"],"names":[],"mappings":"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","file":"timepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.1.6 - 2015-01-11
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) {
|
|
11
|
+
|
|
12
|
+
$templateCache.put('timepicker/timepicker.tpl.html', '<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)"><i class="{{ $iconUp }}"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)"><i class="{{ $iconUp }}"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td ng-if="showAM"> </td><td ng-if="showAM"><button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button> <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)"><i class="{{ $iconDown }}"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)"><i class="{{ $iconDown }}"></i></button></th></tr></tfoot></table></div>');
|
|
13
|
+
|
|
14
|
+
}]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.1.6 - 2015-01-11
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
"use strict";angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)"><i class="{{ $iconUp }}"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)"><i class="{{ $iconUp }}"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td ng-if="showAM"> </td><td ng-if="showAM"><button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button> <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)"><i class="{{ $iconDown }}"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)"><i class="{{ $iconDown }}"></i></button></th></tr></tfoot></table></div>')}]);
|
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.1.6 - 2015-01-11
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
|
|
11
|
+
|
|
12
|
+
.provider('$tooltip', function() {
|
|
13
|
+
|
|
14
|
+
var defaults = this.defaults = {
|
|
15
|
+
animation: 'am-fade',
|
|
16
|
+
customClass: '',
|
|
17
|
+
prefixClass: 'tooltip',
|
|
18
|
+
prefixEvent: 'tooltip',
|
|
19
|
+
container: false,
|
|
20
|
+
target: false,
|
|
21
|
+
placement: 'top',
|
|
22
|
+
template: 'tooltip/tooltip.tpl.html',
|
|
23
|
+
contentTemplate: false,
|
|
24
|
+
trigger: 'hover focus',
|
|
25
|
+
keyboard: false,
|
|
26
|
+
html: false,
|
|
27
|
+
show: false,
|
|
28
|
+
title: '',
|
|
29
|
+
type: '',
|
|
30
|
+
delay: 0,
|
|
31
|
+
autoClose: false,
|
|
32
|
+
bsEnabled: true
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
|
|
36
|
+
|
|
37
|
+
var trim = String.prototype.trim;
|
|
38
|
+
var isTouch = 'createTouch' in $window.document;
|
|
39
|
+
var htmlReplaceRegExp = /ng-bind="/ig;
|
|
40
|
+
var $body = angular.element($window.document);
|
|
41
|
+
|
|
42
|
+
function TooltipFactory(element, config) {
|
|
43
|
+
|
|
44
|
+
var $tooltip = {};
|
|
45
|
+
|
|
46
|
+
// Common vars
|
|
47
|
+
var nodeName = element[0].nodeName.toLowerCase();
|
|
48
|
+
var options = $tooltip.$options = angular.extend({}, defaults, config);
|
|
49
|
+
$tooltip.$promise = fetchTemplate(options.template);
|
|
50
|
+
var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
|
|
51
|
+
if(options.delay && angular.isString(options.delay)) {
|
|
52
|
+
var split = options.delay.split(',').map(parseFloat);
|
|
53
|
+
options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// store $id to identify the triggering element in events
|
|
57
|
+
// give priority to options.id, otherwise, try to use
|
|
58
|
+
// element id if defined
|
|
59
|
+
$tooltip.$id = options.id || element.attr('id') || '';
|
|
60
|
+
|
|
61
|
+
// Support scope as string options
|
|
62
|
+
if(options.title) {
|
|
63
|
+
scope.title = $sce.trustAsHtml(options.title);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Provide scope helpers
|
|
67
|
+
scope.$setEnabled = function(isEnabled) {
|
|
68
|
+
scope.$$postDigest(function() {
|
|
69
|
+
$tooltip.setEnabled(isEnabled);
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
scope.$hide = function() {
|
|
73
|
+
scope.$$postDigest(function() {
|
|
74
|
+
$tooltip.hide();
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
scope.$show = function() {
|
|
78
|
+
scope.$$postDigest(function() {
|
|
79
|
+
$tooltip.show();
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
scope.$toggle = function() {
|
|
83
|
+
scope.$$postDigest(function() {
|
|
84
|
+
$tooltip.toggle();
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
// Publish isShown as a protected var on scope
|
|
88
|
+
$tooltip.$isShown = scope.$isShown = false;
|
|
89
|
+
|
|
90
|
+
// Private vars
|
|
91
|
+
var timeout, hoverState;
|
|
92
|
+
|
|
93
|
+
// Support contentTemplate option
|
|
94
|
+
if(options.contentTemplate) {
|
|
95
|
+
$tooltip.$promise = $tooltip.$promise.then(function(template) {
|
|
96
|
+
var templateEl = angular.element(template);
|
|
97
|
+
return fetchTemplate(options.contentTemplate)
|
|
98
|
+
.then(function(contentTemplate) {
|
|
99
|
+
var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
|
|
100
|
+
if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]);
|
|
101
|
+
contentEl.removeAttr('ng-bind').html(contentTemplate);
|
|
102
|
+
return templateEl[0].outerHTML;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Fetch, compile then initialize tooltip
|
|
108
|
+
var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;
|
|
109
|
+
$tooltip.$promise.then(function(template) {
|
|
110
|
+
if(angular.isObject(template)) template = template.data;
|
|
111
|
+
if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
|
|
112
|
+
template = trim.apply(template);
|
|
113
|
+
tipTemplate = template;
|
|
114
|
+
tipLinker = $compile(template);
|
|
115
|
+
$tooltip.init();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
$tooltip.init = function() {
|
|
119
|
+
|
|
120
|
+
// Options: delay
|
|
121
|
+
if (options.delay && angular.isNumber(options.delay)) {
|
|
122
|
+
options.delay = {
|
|
123
|
+
show: options.delay,
|
|
124
|
+
hide: options.delay
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Replace trigger on touch devices ?
|
|
129
|
+
// if(isTouch && options.trigger === defaults.trigger) {
|
|
130
|
+
// options.trigger.replace(/hover/g, 'click');
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
// Options : container
|
|
134
|
+
if(options.container === 'self') {
|
|
135
|
+
tipContainer = element;
|
|
136
|
+
} else if(angular.isElement(options.container)) {
|
|
137
|
+
tipContainer = options.container;
|
|
138
|
+
} else if(options.container) {
|
|
139
|
+
tipContainer = findElement(options.container);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Options: trigger
|
|
143
|
+
bindTriggerEvents();
|
|
144
|
+
|
|
145
|
+
// Options: target
|
|
146
|
+
if(options.target) {
|
|
147
|
+
options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Options: show
|
|
151
|
+
if(options.show) {
|
|
152
|
+
scope.$$postDigest(function() {
|
|
153
|
+
options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
$tooltip.destroy = function() {
|
|
160
|
+
|
|
161
|
+
// Unbind events
|
|
162
|
+
unbindTriggerEvents();
|
|
163
|
+
|
|
164
|
+
// Remove element
|
|
165
|
+
destroyTipElement();
|
|
166
|
+
|
|
167
|
+
// Destroy scope
|
|
168
|
+
scope.$destroy();
|
|
169
|
+
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
$tooltip.enter = function() {
|
|
173
|
+
|
|
174
|
+
clearTimeout(timeout);
|
|
175
|
+
hoverState = 'in';
|
|
176
|
+
if (!options.delay || !options.delay.show) {
|
|
177
|
+
return $tooltip.show();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
timeout = setTimeout(function() {
|
|
181
|
+
if (hoverState ==='in') $tooltip.show();
|
|
182
|
+
}, options.delay.show);
|
|
183
|
+
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
$tooltip.show = function() {
|
|
187
|
+
if (!options.bsEnabled || $tooltip.$isShown) return;
|
|
188
|
+
|
|
189
|
+
scope.$emit(options.prefixEvent + '.show.before', $tooltip);
|
|
190
|
+
var parent, after;
|
|
191
|
+
if (options.container) {
|
|
192
|
+
parent = tipContainer;
|
|
193
|
+
if (tipContainer[0].lastChild) {
|
|
194
|
+
after = angular.element(tipContainer[0].lastChild);
|
|
195
|
+
} else {
|
|
196
|
+
after = null;
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
parent = null;
|
|
200
|
+
after = element;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
// Hide any existing tipElement
|
|
205
|
+
if(tipElement) destroyTipElement();
|
|
206
|
+
// Fetch a cloned element linked from template
|
|
207
|
+
tipScope = $tooltip.$scope.$new();
|
|
208
|
+
tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});
|
|
209
|
+
|
|
210
|
+
// Set the initial positioning. Make the tooltip invisible
|
|
211
|
+
// so IE doesn't try to focus on it off screen.
|
|
212
|
+
tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});
|
|
213
|
+
|
|
214
|
+
// Options: animation
|
|
215
|
+
if(options.animation) tipElement.addClass(options.animation);
|
|
216
|
+
// Options: type
|
|
217
|
+
if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
|
|
218
|
+
// Options: custom classes
|
|
219
|
+
if(options.customClass) tipElement.addClass(options.customClass);
|
|
220
|
+
|
|
221
|
+
// Support v1.3+ $animate
|
|
222
|
+
// https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
|
|
223
|
+
var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);
|
|
224
|
+
if(promise && promise.then) promise.then(enterAnimateCallback);
|
|
225
|
+
|
|
226
|
+
$tooltip.$isShown = scope.$isShown = true;
|
|
227
|
+
safeDigest(scope);
|
|
228
|
+
$$rAF(function () {
|
|
229
|
+
$tooltip.$applyPlacement();
|
|
230
|
+
|
|
231
|
+
// Once placed, make the tooltip visible
|
|
232
|
+
if(tipElement) tipElement.css({visibility: 'visible'});
|
|
233
|
+
}); // var a = bodyEl.offsetWidth + 1; ?
|
|
234
|
+
|
|
235
|
+
// Bind events
|
|
236
|
+
if(options.keyboard) {
|
|
237
|
+
if(options.trigger !== 'focus') {
|
|
238
|
+
$tooltip.focus();
|
|
239
|
+
}
|
|
240
|
+
bindKeyboardEvents();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if(options.autoClose) {
|
|
244
|
+
bindAutoCloseEvents();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
function enterAnimateCallback() {
|
|
250
|
+
scope.$emit(options.prefixEvent + '.show', $tooltip);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
$tooltip.leave = function() {
|
|
254
|
+
|
|
255
|
+
clearTimeout(timeout);
|
|
256
|
+
hoverState = 'out';
|
|
257
|
+
if (!options.delay || !options.delay.hide) {
|
|
258
|
+
return $tooltip.hide();
|
|
259
|
+
}
|
|
260
|
+
timeout = setTimeout(function () {
|
|
261
|
+
if (hoverState === 'out') {
|
|
262
|
+
$tooltip.hide();
|
|
263
|
+
}
|
|
264
|
+
}, options.delay.hide);
|
|
265
|
+
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
var _blur;
|
|
269
|
+
var _tipToHide;
|
|
270
|
+
$tooltip.hide = function(blur) {
|
|
271
|
+
|
|
272
|
+
if(!$tooltip.$isShown) return;
|
|
273
|
+
scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
|
|
274
|
+
|
|
275
|
+
// store blur value for leaveAnimateCallback to use
|
|
276
|
+
_blur = blur;
|
|
277
|
+
|
|
278
|
+
// store current tipElement reference to use
|
|
279
|
+
// in leaveAnimateCallback
|
|
280
|
+
_tipToHide = tipElement;
|
|
281
|
+
|
|
282
|
+
// Support v1.3+ $animate
|
|
283
|
+
// https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
|
|
284
|
+
var promise = $animate.leave(tipElement, leaveAnimateCallback);
|
|
285
|
+
if(promise && promise.then) promise.then(leaveAnimateCallback);
|
|
286
|
+
|
|
287
|
+
$tooltip.$isShown = scope.$isShown = false;
|
|
288
|
+
safeDigest(scope);
|
|
289
|
+
|
|
290
|
+
// Unbind events
|
|
291
|
+
if(options.keyboard && tipElement !== null) {
|
|
292
|
+
unbindKeyboardEvents();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if(options.autoClose && tipElement !== null) {
|
|
296
|
+
unbindAutoCloseEvents();
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
function leaveAnimateCallback() {
|
|
301
|
+
scope.$emit(options.prefixEvent + '.hide', $tooltip);
|
|
302
|
+
|
|
303
|
+
// check if current tipElement still references
|
|
304
|
+
// the same element when hide was called
|
|
305
|
+
if (tipElement === _tipToHide) {
|
|
306
|
+
// Allow to blur the input when hidden, like when pressing enter key
|
|
307
|
+
if(_blur && options.trigger === 'focus') {
|
|
308
|
+
return element[0].blur();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// clean up child scopes
|
|
312
|
+
destroyTipElement();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
$tooltip.toggle = function() {
|
|
317
|
+
$tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
$tooltip.focus = function() {
|
|
321
|
+
tipElement[0].focus();
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
$tooltip.setEnabled = function(isEnabled) {
|
|
325
|
+
options.bsEnabled = isEnabled;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// Protected methods
|
|
329
|
+
|
|
330
|
+
$tooltip.$applyPlacement = function() {
|
|
331
|
+
if(!tipElement) return;
|
|
332
|
+
|
|
333
|
+
// Determine if we're doing an auto or normal placement
|
|
334
|
+
var placement = options.placement,
|
|
335
|
+
autoToken = /\s?auto?\s?/i,
|
|
336
|
+
autoPlace = autoToken.test(placement);
|
|
337
|
+
|
|
338
|
+
if (autoPlace) {
|
|
339
|
+
placement = placement.replace(autoToken, '') || defaults.placement;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Need to add the position class before we get
|
|
343
|
+
// the offsets
|
|
344
|
+
tipElement.addClass(options.placement);
|
|
345
|
+
|
|
346
|
+
// Get the position of the target element
|
|
347
|
+
// and the height and width of the tooltip so we can center it.
|
|
348
|
+
var elementPosition = getPosition(),
|
|
349
|
+
tipWidth = tipElement.prop('offsetWidth'),
|
|
350
|
+
tipHeight = tipElement.prop('offsetHeight');
|
|
351
|
+
|
|
352
|
+
// If we're auto placing, we need to check the positioning
|
|
353
|
+
if (autoPlace) {
|
|
354
|
+
var originalPlacement = placement;
|
|
355
|
+
var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();
|
|
356
|
+
var containerPosition = getPosition(container);
|
|
357
|
+
|
|
358
|
+
// Determine if the vertical placement
|
|
359
|
+
if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {
|
|
360
|
+
placement = originalPlacement.replace('bottom', 'top');
|
|
361
|
+
} else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {
|
|
362
|
+
placement = originalPlacement.replace('top', 'bottom');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Determine the horizontal placement
|
|
366
|
+
// The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right
|
|
367
|
+
// and flow in the opposite direction of their placement.
|
|
368
|
+
if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&
|
|
369
|
+
elementPosition.right + tipWidth > containerPosition.width) {
|
|
370
|
+
|
|
371
|
+
placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
|
|
372
|
+
} else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&
|
|
373
|
+
elementPosition.left - tipWidth < containerPosition.left) {
|
|
374
|
+
|
|
375
|
+
placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
tipElement.removeClass(originalPlacement).addClass(placement);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Get the tooltip's top and left coordinates to center it with this directive.
|
|
382
|
+
var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
|
|
383
|
+
applyPlacementCss(tipPosition.top, tipPosition.left);
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
$tooltip.$onKeyUp = function(evt) {
|
|
387
|
+
if (evt.which === 27 && $tooltip.$isShown) {
|
|
388
|
+
$tooltip.hide();
|
|
389
|
+
evt.stopPropagation();
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
$tooltip.$onFocusKeyUp = function(evt) {
|
|
394
|
+
if (evt.which === 27) {
|
|
395
|
+
element[0].blur();
|
|
396
|
+
evt.stopPropagation();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
$tooltip.$onFocusElementMouseDown = function(evt) {
|
|
401
|
+
evt.preventDefault();
|
|
402
|
+
evt.stopPropagation();
|
|
403
|
+
// Some browsers do not auto-focus buttons (eg. Safari)
|
|
404
|
+
$tooltip.$isShown ? element[0].blur() : element[0].focus();
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// bind/unbind events
|
|
408
|
+
function bindTriggerEvents() {
|
|
409
|
+
var triggers = options.trigger.split(' ');
|
|
410
|
+
angular.forEach(triggers, function(trigger) {
|
|
411
|
+
if(trigger === 'click') {
|
|
412
|
+
element.on('click', $tooltip.toggle);
|
|
413
|
+
} else if(trigger !== 'manual') {
|
|
414
|
+
element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
|
|
415
|
+
element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
|
|
416
|
+
nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function unbindTriggerEvents() {
|
|
422
|
+
var triggers = options.trigger.split(' ');
|
|
423
|
+
for (var i = triggers.length; i--;) {
|
|
424
|
+
var trigger = triggers[i];
|
|
425
|
+
if(trigger === 'click') {
|
|
426
|
+
element.off('click', $tooltip.toggle);
|
|
427
|
+
} else if(trigger !== 'manual') {
|
|
428
|
+
element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
|
|
429
|
+
element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
|
|
430
|
+
nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function bindKeyboardEvents() {
|
|
436
|
+
if(options.trigger !== 'focus') {
|
|
437
|
+
tipElement.on('keyup', $tooltip.$onKeyUp);
|
|
438
|
+
} else {
|
|
439
|
+
element.on('keyup', $tooltip.$onFocusKeyUp);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function unbindKeyboardEvents() {
|
|
444
|
+
if(options.trigger !== 'focus') {
|
|
445
|
+
tipElement.off('keyup', $tooltip.$onKeyUp);
|
|
446
|
+
} else {
|
|
447
|
+
element.off('keyup', $tooltip.$onFocusKeyUp);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
var _autoCloseEventsBinded = false;
|
|
452
|
+
function bindAutoCloseEvents() {
|
|
453
|
+
// use timeout to hookup the events to prevent
|
|
454
|
+
// event bubbling from being processed imediately.
|
|
455
|
+
$timeout(function() {
|
|
456
|
+
// Stop propagation when clicking inside tooltip
|
|
457
|
+
tipElement.on('click', stopEventPropagation);
|
|
458
|
+
|
|
459
|
+
// Hide when clicking outside tooltip
|
|
460
|
+
$body.on('click', $tooltip.hide);
|
|
461
|
+
|
|
462
|
+
_autoCloseEventsBinded = true;
|
|
463
|
+
}, 0, false);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function unbindAutoCloseEvents() {
|
|
467
|
+
if (_autoCloseEventsBinded) {
|
|
468
|
+
tipElement.off('click', stopEventPropagation);
|
|
469
|
+
$body.off('click', $tooltip.hide);
|
|
470
|
+
_autoCloseEventsBinded = false;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function stopEventPropagation(event) {
|
|
475
|
+
event.stopPropagation();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Private methods
|
|
479
|
+
|
|
480
|
+
function getPosition($element) {
|
|
481
|
+
$element = $element || (options.target || element);
|
|
482
|
+
|
|
483
|
+
var el = $element[0];
|
|
484
|
+
|
|
485
|
+
var elRect = el.getBoundingClientRect();
|
|
486
|
+
if (elRect.width === null) {
|
|
487
|
+
// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
|
|
488
|
+
elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
var elPos;
|
|
492
|
+
if (options.container === 'body') {
|
|
493
|
+
elPos = dimensions.offset(el);
|
|
494
|
+
} else {
|
|
495
|
+
elPos = dimensions.position(el);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return angular.extend({}, elRect, elPos);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
|
|
502
|
+
var offset;
|
|
503
|
+
var split = placement.split('-');
|
|
504
|
+
|
|
505
|
+
switch (split[0]) {
|
|
506
|
+
case 'right':
|
|
507
|
+
offset = {
|
|
508
|
+
top: position.top + position.height / 2 - actualHeight / 2,
|
|
509
|
+
left: position.left + position.width
|
|
510
|
+
};
|
|
511
|
+
break;
|
|
512
|
+
case 'bottom':
|
|
513
|
+
offset = {
|
|
514
|
+
top: position.top + position.height,
|
|
515
|
+
left: position.left + position.width / 2 - actualWidth / 2
|
|
516
|
+
};
|
|
517
|
+
break;
|
|
518
|
+
case 'left':
|
|
519
|
+
offset = {
|
|
520
|
+
top: position.top + position.height / 2 - actualHeight / 2,
|
|
521
|
+
left: position.left - actualWidth
|
|
522
|
+
};
|
|
523
|
+
break;
|
|
524
|
+
default:
|
|
525
|
+
offset = {
|
|
526
|
+
top: position.top - actualHeight,
|
|
527
|
+
left: position.left + position.width / 2 - actualWidth / 2
|
|
528
|
+
};
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if(!split[1]) {
|
|
533
|
+
return offset;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Add support for corners @todo css
|
|
537
|
+
if(split[0] === 'top' || split[0] === 'bottom') {
|
|
538
|
+
switch (split[1]) {
|
|
539
|
+
case 'left':
|
|
540
|
+
offset.left = position.left;
|
|
541
|
+
break;
|
|
542
|
+
case 'right':
|
|
543
|
+
offset.left = position.left + position.width - actualWidth;
|
|
544
|
+
}
|
|
545
|
+
} else if(split[0] === 'left' || split[0] === 'right') {
|
|
546
|
+
switch (split[1]) {
|
|
547
|
+
case 'top':
|
|
548
|
+
offset.top = position.top - actualHeight;
|
|
549
|
+
break;
|
|
550
|
+
case 'bottom':
|
|
551
|
+
offset.top = position.top + position.height;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return offset;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function applyPlacementCss(top, left) {
|
|
559
|
+
tipElement.css({ top: top + 'px', left: left + 'px' });
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function destroyTipElement() {
|
|
563
|
+
// Cancel pending callbacks
|
|
564
|
+
clearTimeout(timeout);
|
|
565
|
+
|
|
566
|
+
if($tooltip.$isShown && tipElement !== null) {
|
|
567
|
+
if(options.autoClose) {
|
|
568
|
+
unbindAutoCloseEvents();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if(options.keyboard) {
|
|
572
|
+
unbindKeyboardEvents();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if(tipScope) {
|
|
577
|
+
tipScope.$destroy();
|
|
578
|
+
tipScope = null;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if(tipElement) {
|
|
582
|
+
tipElement.remove();
|
|
583
|
+
tipElement = $tooltip.$element = null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return $tooltip;
|
|
588
|
+
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Helper functions
|
|
592
|
+
|
|
593
|
+
function safeDigest(scope) {
|
|
594
|
+
scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function findElement(query, element) {
|
|
598
|
+
return angular.element((element || document).querySelectorAll(query));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
var fetchPromises = {};
|
|
602
|
+
function fetchTemplate(template) {
|
|
603
|
+
if(fetchPromises[template]) return fetchPromises[template];
|
|
604
|
+
return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))
|
|
605
|
+
.then(function(res) {
|
|
606
|
+
if(angular.isObject(res)) {
|
|
607
|
+
$templateCache.put(template, res.data);
|
|
608
|
+
return res.data;
|
|
609
|
+
}
|
|
610
|
+
return res;
|
|
611
|
+
}));
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return TooltipFactory;
|
|
615
|
+
|
|
616
|
+
}];
|
|
617
|
+
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
.directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) {
|
|
621
|
+
|
|
622
|
+
return {
|
|
623
|
+
restrict: 'EAC',
|
|
624
|
+
scope: true,
|
|
625
|
+
link: function postLink(scope, element, attr, transclusion) {
|
|
626
|
+
|
|
627
|
+
// Directive options
|
|
628
|
+
var options = {scope: scope};
|
|
629
|
+
angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {
|
|
630
|
+
if(angular.isDefined(attr[key])) options[key] = attr[key];
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// overwrite inherited title value when no value specified
|
|
634
|
+
// fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11
|
|
635
|
+
if (!scope.hasOwnProperty('title')){
|
|
636
|
+
scope.title = '';
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Observe scope attributes for change
|
|
640
|
+
attr.$observe('title', function(newValue) {
|
|
641
|
+
if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
|
|
642
|
+
var oldValue = scope.title;
|
|
643
|
+
scope.title = $sce.trustAsHtml(newValue);
|
|
644
|
+
angular.isDefined(oldValue) && $$rAF(function() {
|
|
645
|
+
tooltip && tooltip.$applyPlacement();
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
// Support scope as an object
|
|
651
|
+
attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
|
|
652
|
+
if(angular.isObject(newValue)) {
|
|
653
|
+
angular.extend(scope, newValue);
|
|
654
|
+
} else {
|
|
655
|
+
scope.title = newValue;
|
|
656
|
+
}
|
|
657
|
+
angular.isDefined(oldValue) && $$rAF(function() {
|
|
658
|
+
tooltip && tooltip.$applyPlacement();
|
|
659
|
+
});
|
|
660
|
+
}, true);
|
|
661
|
+
|
|
662
|
+
// Visibility binding support
|
|
663
|
+
attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
|
|
664
|
+
if(!tooltip || !angular.isDefined(newValue)) return;
|
|
665
|
+
if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
|
|
666
|
+
newValue === true ? tooltip.show() : tooltip.hide();
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
// Enabled binding support
|
|
670
|
+
attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
|
|
671
|
+
// console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);
|
|
672
|
+
if(!tooltip || !angular.isDefined(newValue)) return;
|
|
673
|
+
if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
|
|
674
|
+
newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
// Initialize popover
|
|
678
|
+
var tooltip = $tooltip(element, options);
|
|
679
|
+
|
|
680
|
+
// Garbage collection
|
|
681
|
+
scope.$on('$destroy', function() {
|
|
682
|
+
if(tooltip) tooltip.destroy();
|
|
683
|
+
options = null;
|
|
684
|
+
tooltip = null;
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
}]);
|