angular-strap.js 166 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071
  1. /**
  2. * angular-strap
  3. * @version v2.3.5 - 2015-10-29
  4. * @link http://mgcrea.github.io/angular-strap
  5. * @author Olivier Louvignes <olivier@mg-crea.com> (https://github.com/mgcrea)
  6. * @license MIT License, http://www.opensource.org/licenses/MIT
  7. */
  8. (function(window, document, undefined) {
  9. 'use strict';
  10. angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() {
  11. var defaults = this.defaults = {
  12. animation: 'am-fade',
  13. prefixClass: 'typeahead',
  14. prefixEvent: '$typeahead',
  15. placement: 'bottom-left',
  16. templateUrl: 'typeahead/typeahead.tpl.html',
  17. trigger: 'focus',
  18. container: false,
  19. keyboard: true,
  20. html: false,
  21. delay: 0,
  22. minLength: 1,
  23. filter: 'bsAsyncFilter',
  24. limit: 6,
  25. autoSelect: false,
  26. comparator: '',
  27. trimValue: true
  28. };
  29. this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) {
  30. var bodyEl = angular.element($window.document.body);
  31. function TypeaheadFactory(element, controller, config) {
  32. var $typeahead = {};
  33. var options = angular.extend({}, defaults, config);
  34. $typeahead = $tooltip(element, options);
  35. var parentScope = config.scope;
  36. var scope = $typeahead.$scope;
  37. scope.$resetMatches = function() {
  38. scope.$matches = [];
  39. scope.$activeIndex = options.autoSelect ? 0 : -1;
  40. };
  41. scope.$resetMatches();
  42. scope.$activate = function(index) {
  43. scope.$$postDigest(function() {
  44. $typeahead.activate(index);
  45. });
  46. };
  47. scope.$select = function(index, evt) {
  48. scope.$$postDigest(function() {
  49. $typeahead.select(index);
  50. });
  51. };
  52. scope.$isVisible = function() {
  53. return $typeahead.$isVisible();
  54. };
  55. $typeahead.update = function(matches) {
  56. scope.$matches = matches;
  57. if (scope.$activeIndex >= matches.length) {
  58. scope.$activeIndex = options.autoSelect ? 0 : -1;
  59. }
  60. safeDigest(scope);
  61. $$rAF($typeahead.$applyPlacement);
  62. };
  63. $typeahead.activate = function(index) {
  64. scope.$activeIndex = index;
  65. };
  66. $typeahead.select = function(index) {
  67. if (index === -1) return;
  68. var value = scope.$matches[index].value;
  69. controller.$setViewValue(value);
  70. controller.$render();
  71. scope.$resetMatches();
  72. if (parentScope) parentScope.$digest();
  73. scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);
  74. };
  75. $typeahead.$isVisible = function() {
  76. if (!options.minLength || !controller) {
  77. return !!scope.$matches.length;
  78. }
  79. return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;
  80. };
  81. $typeahead.$getIndex = function(value) {
  82. var l = scope.$matches.length, i = l;
  83. if (!l) return;
  84. for (i = l; i--; ) {
  85. if (scope.$matches[i].value === value) break;
  86. }
  87. if (i < 0) return;
  88. return i;
  89. };
  90. $typeahead.$onMouseDown = function(evt) {
  91. evt.preventDefault();
  92. evt.stopPropagation();
  93. };
  94. $typeahead.$onKeyDown = function(evt) {
  95. if (!/(38|40|13)/.test(evt.keyCode)) return;
  96. if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {
  97. evt.preventDefault();
  98. evt.stopPropagation();
  99. }
  100. if (evt.keyCode === 13 && scope.$matches.length) {
  101. $typeahead.select(scope.$activeIndex);
  102. } else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;
  103. scope.$digest();
  104. };
  105. var show = $typeahead.show;
  106. $typeahead.show = function() {
  107. show();
  108. $timeout(function() {
  109. $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);
  110. if (options.keyboard) {
  111. element && element.on('keydown', $typeahead.$onKeyDown);
  112. }
  113. }, 0, false);
  114. };
  115. var hide = $typeahead.hide;
  116. $typeahead.hide = function() {
  117. $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);
  118. if (options.keyboard) {
  119. element && element.off('keydown', $typeahead.$onKeyDown);
  120. }
  121. if (!options.autoSelect) $typeahead.activate(-1);
  122. hide();
  123. };
  124. return $typeahead;
  125. }
  126. function safeDigest(scope) {
  127. scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
  128. }
  129. TypeaheadFactory.defaults = defaults;
  130. return TypeaheadFactory;
  131. } ];
  132. }).filter('bsAsyncFilter', [ '$filter', function($filter) {
  133. return function(array, expression, comparator) {
  134. if (array && angular.isFunction(array.then)) {
  135. return array.then(function(results) {
  136. return $filter('filter')(results, expression, comparator);
  137. });
  138. } else {
  139. return $filter('filter')(array, expression, comparator);
  140. }
  141. };
  142. } ]).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) {
  143. var defaults = $typeahead.defaults;
  144. return {
  145. restrict: 'EAC',
  146. require: 'ngModel',
  147. link: function postLink(scope, element, attr, controller) {
  148. var options = {
  149. scope: scope
  150. };
  151. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass' ], function(key) {
  152. if (angular.isDefined(attr[key])) options[key] = attr[key];
  153. });
  154. var falseValueRegExp = /^(false|0|)$/i;
  155. angular.forEach([ 'html', 'container', 'trimValue' ], function(key) {
  156. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  157. });
  158. if (!element.attr('autocomplete')) element.attr('autocomplete', 'off');
  159. var filter = options.filter || defaults.filter;
  160. var limit = options.limit || defaults.limit;
  161. var comparator = options.comparator || defaults.comparator;
  162. var bsOptions = attr.bsOptions;
  163. if (filter) bsOptions += ' | ' + filter + ':$viewValue';
  164. if (comparator) bsOptions += ':' + comparator;
  165. if (limit) bsOptions += ' | limitTo:' + limit;
  166. var parsedOptions = $parseOptions(bsOptions);
  167. var typeahead = $typeahead(element, controller, options);
  168. if (options.watchOptions) {
  169. var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim();
  170. scope.$watchCollection(watchedOptions, function(newValue, oldValue) {
  171. parsedOptions.valuesFn(scope, controller).then(function(values) {
  172. typeahead.update(values);
  173. controller.$render();
  174. });
  175. });
  176. }
  177. scope.$watch(attr.ngModel, function(newValue, oldValue) {
  178. scope.$modelValue = newValue;
  179. parsedOptions.valuesFn(scope, controller).then(function(values) {
  180. if (options.selectMode && !values.length && newValue.length > 0) {
  181. controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));
  182. return;
  183. }
  184. if (values.length > limit) values = values.slice(0, limit);
  185. typeahead.update(values);
  186. controller.$render();
  187. });
  188. });
  189. controller.$formatters.push(function(modelValue) {
  190. var displayValue = parsedOptions.displayValue(modelValue);
  191. if (displayValue) {
  192. return displayValue;
  193. }
  194. if (modelValue && typeof modelValue !== 'object') {
  195. return modelValue;
  196. }
  197. return '';
  198. });
  199. controller.$render = function() {
  200. if (controller.$isEmpty(controller.$viewValue)) {
  201. return element.val('');
  202. }
  203. var index = typeahead.$getIndex(controller.$modelValue);
  204. var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;
  205. selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;
  206. var value = selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '') : '';
  207. element.val(options.trimValue === false ? value : value.trim());
  208. };
  209. scope.$on('$destroy', function() {
  210. if (typeahead) typeahead.destroy();
  211. options = null;
  212. typeahead = null;
  213. });
  214. }
  215. };
  216. } ]);
  217. angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$tooltip', function() {
  218. var defaults = this.defaults = {
  219. animation: 'am-fade',
  220. customClass: '',
  221. prefixClass: 'tooltip',
  222. prefixEvent: 'tooltip',
  223. container: false,
  224. target: false,
  225. placement: 'top',
  226. templateUrl: 'tooltip/tooltip.tpl.html',
  227. template: '',
  228. contentTemplate: false,
  229. trigger: 'hover focus',
  230. keyboard: false,
  231. html: false,
  232. show: false,
  233. title: '',
  234. type: '',
  235. delay: 0,
  236. autoClose: false,
  237. bsEnabled: true,
  238. viewport: {
  239. selector: 'body',
  240. padding: 0
  241. }
  242. };
  243. this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$sce', 'dimensions', '$$rAF', '$timeout', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
  244. var trim = String.prototype.trim;
  245. var isTouch = 'createTouch' in $window.document;
  246. var htmlReplaceRegExp = /ng-bind="/gi;
  247. var $body = angular.element($window.document);
  248. function TooltipFactory(element, config) {
  249. var $tooltip = {};
  250. var options = $tooltip.$options = angular.extend({}, defaults, config);
  251. var promise = $tooltip.$promise = $bsCompiler.compile(options);
  252. var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
  253. var nodeName = element[0].nodeName.toLowerCase();
  254. if (options.delay && angular.isString(options.delay)) {
  255. var split = options.delay.split(',').map(parseFloat);
  256. options.delay = split.length > 1 ? {
  257. show: split[0],
  258. hide: split[1]
  259. } : split[0];
  260. }
  261. $tooltip.$id = options.id || element.attr('id') || '';
  262. if (options.title) {
  263. scope.title = $sce.trustAsHtml(options.title);
  264. }
  265. scope.$setEnabled = function(isEnabled) {
  266. scope.$$postDigest(function() {
  267. $tooltip.setEnabled(isEnabled);
  268. });
  269. };
  270. scope.$hide = function() {
  271. scope.$$postDigest(function() {
  272. $tooltip.hide();
  273. });
  274. };
  275. scope.$show = function() {
  276. scope.$$postDigest(function() {
  277. $tooltip.show();
  278. });
  279. };
  280. scope.$toggle = function() {
  281. scope.$$postDigest(function() {
  282. $tooltip.toggle();
  283. });
  284. };
  285. $tooltip.$isShown = scope.$isShown = false;
  286. var timeout, hoverState;
  287. var compileData, tipElement, tipContainer, tipScope;
  288. promise.then(function(data) {
  289. compileData = data;
  290. $tooltip.init();
  291. });
  292. $tooltip.init = function() {
  293. if (options.delay && angular.isNumber(options.delay)) {
  294. options.delay = {
  295. show: options.delay,
  296. hide: options.delay
  297. };
  298. }
  299. if (options.container === 'self') {
  300. tipContainer = element;
  301. } else if (angular.isElement(options.container)) {
  302. tipContainer = options.container;
  303. } else if (options.container) {
  304. tipContainer = findElement(options.container);
  305. }
  306. bindTriggerEvents();
  307. if (options.target) {
  308. options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
  309. }
  310. if (options.show) {
  311. scope.$$postDigest(function() {
  312. options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
  313. });
  314. }
  315. };
  316. $tooltip.destroy = function() {
  317. unbindTriggerEvents();
  318. destroyTipElement();
  319. scope.$destroy();
  320. };
  321. $tooltip.enter = function() {
  322. clearTimeout(timeout);
  323. hoverState = 'in';
  324. if (!options.delay || !options.delay.show) {
  325. return $tooltip.show();
  326. }
  327. timeout = setTimeout(function() {
  328. if (hoverState === 'in') $tooltip.show();
  329. }, options.delay.show);
  330. };
  331. $tooltip.show = function() {
  332. if (!options.bsEnabled || $tooltip.$isShown) return;
  333. scope.$emit(options.prefixEvent + '.show.before', $tooltip);
  334. var parent, after;
  335. if (options.container) {
  336. parent = tipContainer;
  337. if (tipContainer[0].lastChild) {
  338. after = angular.element(tipContainer[0].lastChild);
  339. } else {
  340. after = null;
  341. }
  342. } else {
  343. parent = null;
  344. after = element;
  345. }
  346. if (tipElement) destroyTipElement();
  347. tipScope = $tooltip.$scope.$new();
  348. tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});
  349. tipElement.css({
  350. top: '-9999px',
  351. left: '-9999px',
  352. right: 'auto',
  353. display: 'block',
  354. visibility: 'hidden'
  355. });
  356. if (options.animation) tipElement.addClass(options.animation);
  357. if (options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
  358. if (options.customClass) tipElement.addClass(options.customClass);
  359. after ? after.after(tipElement) : parent.prepend(tipElement);
  360. $tooltip.$isShown = scope.$isShown = true;
  361. safeDigest(scope);
  362. $tooltip.$applyPlacement();
  363. if (angular.version.minor <= 2) {
  364. $animate.enter(tipElement, parent, after, enterAnimateCallback);
  365. } else {
  366. $animate.enter(tipElement, parent, after).then(enterAnimateCallback);
  367. }
  368. safeDigest(scope);
  369. $$rAF(function() {
  370. if (tipElement) tipElement.css({
  371. visibility: 'visible'
  372. });
  373. if (options.keyboard) {
  374. if (options.trigger !== 'focus') {
  375. $tooltip.focus();
  376. }
  377. bindKeyboardEvents();
  378. }
  379. });
  380. if (options.autoClose) {
  381. bindAutoCloseEvents();
  382. }
  383. };
  384. function enterAnimateCallback() {
  385. scope.$emit(options.prefixEvent + '.show', $tooltip);
  386. }
  387. $tooltip.leave = function() {
  388. clearTimeout(timeout);
  389. hoverState = 'out';
  390. if (!options.delay || !options.delay.hide) {
  391. return $tooltip.hide();
  392. }
  393. timeout = setTimeout(function() {
  394. if (hoverState === 'out') {
  395. $tooltip.hide();
  396. }
  397. }, options.delay.hide);
  398. };
  399. var _blur;
  400. var _tipToHide;
  401. $tooltip.hide = function(blur) {
  402. if (!$tooltip.$isShown) return;
  403. scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
  404. _blur = blur;
  405. _tipToHide = tipElement;
  406. if (angular.version.minor <= 2) {
  407. $animate.leave(tipElement, leaveAnimateCallback);
  408. } else {
  409. $animate.leave(tipElement).then(leaveAnimateCallback);
  410. }
  411. $tooltip.$isShown = scope.$isShown = false;
  412. safeDigest(scope);
  413. if (options.keyboard && tipElement !== null) {
  414. unbindKeyboardEvents();
  415. }
  416. if (options.autoClose && tipElement !== null) {
  417. unbindAutoCloseEvents();
  418. }
  419. };
  420. function leaveAnimateCallback() {
  421. scope.$emit(options.prefixEvent + '.hide', $tooltip);
  422. if (tipElement === _tipToHide) {
  423. if (_blur && options.trigger === 'focus') {
  424. return element[0].blur();
  425. }
  426. destroyTipElement();
  427. }
  428. }
  429. $tooltip.toggle = function() {
  430. $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
  431. };
  432. $tooltip.focus = function() {
  433. tipElement[0].focus();
  434. };
  435. $tooltip.setEnabled = function(isEnabled) {
  436. options.bsEnabled = isEnabled;
  437. };
  438. $tooltip.setViewport = function(viewport) {
  439. options.viewport = viewport;
  440. };
  441. $tooltip.$applyPlacement = function() {
  442. if (!tipElement) return;
  443. var placement = options.placement, autoToken = /\s?auto?\s?/i, autoPlace = autoToken.test(placement);
  444. if (autoPlace) {
  445. placement = placement.replace(autoToken, '') || defaults.placement;
  446. }
  447. tipElement.addClass(options.placement);
  448. var elementPosition = getPosition(), tipWidth = tipElement.prop('offsetWidth'), tipHeight = tipElement.prop('offsetHeight');
  449. $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport);
  450. if (autoPlace) {
  451. var originalPlacement = placement;
  452. var viewportPosition = getPosition($tooltip.$viewport);
  453. if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) {
  454. placement = originalPlacement.replace('bottom', 'top');
  455. } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) {
  456. placement = originalPlacement.replace('top', 'bottom');
  457. }
  458. if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && elementPosition.right + tipWidth > viewportPosition.width) {
  459. placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
  460. } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && elementPosition.left - tipWidth < viewportPosition.left) {
  461. placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
  462. }
  463. tipElement.removeClass(originalPlacement).addClass(placement);
  464. }
  465. var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
  466. applyPlacement(tipPosition, placement);
  467. };
  468. $tooltip.$onKeyUp = function(evt) {
  469. if (evt.which === 27 && $tooltip.$isShown) {
  470. $tooltip.hide();
  471. evt.stopPropagation();
  472. }
  473. };
  474. $tooltip.$onFocusKeyUp = function(evt) {
  475. if (evt.which === 27) {
  476. element[0].blur();
  477. evt.stopPropagation();
  478. }
  479. };
  480. $tooltip.$onFocusElementMouseDown = function(evt) {
  481. evt.preventDefault();
  482. evt.stopPropagation();
  483. $tooltip.$isShown ? element[0].blur() : element[0].focus();
  484. };
  485. function bindTriggerEvents() {
  486. var triggers = options.trigger.split(' ');
  487. angular.forEach(triggers, function(trigger) {
  488. if (trigger === 'click') {
  489. element.on('click', $tooltip.toggle);
  490. } else if (trigger !== 'manual') {
  491. element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
  492. element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
  493. nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
  494. }
  495. });
  496. }
  497. function unbindTriggerEvents() {
  498. var triggers = options.trigger.split(' ');
  499. for (var i = triggers.length; i--; ) {
  500. var trigger = triggers[i];
  501. if (trigger === 'click') {
  502. element.off('click', $tooltip.toggle);
  503. } else if (trigger !== 'manual') {
  504. element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
  505. element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
  506. nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
  507. }
  508. }
  509. }
  510. function bindKeyboardEvents() {
  511. if (options.trigger !== 'focus') {
  512. tipElement.on('keyup', $tooltip.$onKeyUp);
  513. } else {
  514. element.on('keyup', $tooltip.$onFocusKeyUp);
  515. }
  516. }
  517. function unbindKeyboardEvents() {
  518. if (options.trigger !== 'focus') {
  519. tipElement.off('keyup', $tooltip.$onKeyUp);
  520. } else {
  521. element.off('keyup', $tooltip.$onFocusKeyUp);
  522. }
  523. }
  524. var _autoCloseEventsBinded = false;
  525. function bindAutoCloseEvents() {
  526. $timeout(function() {
  527. tipElement.on('click', stopEventPropagation);
  528. $body.on('click', $tooltip.hide);
  529. _autoCloseEventsBinded = true;
  530. }, 0, false);
  531. }
  532. function unbindAutoCloseEvents() {
  533. if (_autoCloseEventsBinded) {
  534. tipElement.off('click', stopEventPropagation);
  535. $body.off('click', $tooltip.hide);
  536. _autoCloseEventsBinded = false;
  537. }
  538. }
  539. function stopEventPropagation(event) {
  540. event.stopPropagation();
  541. }
  542. function getPosition($element) {
  543. $element = $element || (options.target || element);
  544. var el = $element[0], isBody = el.tagName === 'BODY';
  545. var elRect = el.getBoundingClientRect();
  546. var rect = {};
  547. for (var p in elRect) {
  548. rect[p] = elRect[p];
  549. }
  550. if (rect.width === null) {
  551. rect = angular.extend({}, rect, {
  552. width: elRect.right - elRect.left,
  553. height: elRect.bottom - elRect.top
  554. });
  555. }
  556. var elOffset = isBody ? {
  557. top: 0,
  558. left: 0
  559. } : dimensions.offset(el), scroll = {
  560. scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0
  561. }, outerDims = isBody ? {
  562. width: document.documentElement.clientWidth,
  563. height: $window.innerHeight
  564. } : null;
  565. return angular.extend({}, rect, scroll, outerDims, elOffset);
  566. }
  567. function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
  568. var offset;
  569. var split = placement.split('-');
  570. switch (split[0]) {
  571. case 'right':
  572. offset = {
  573. top: position.top + position.height / 2 - actualHeight / 2,
  574. left: position.left + position.width
  575. };
  576. break;
  577. case 'bottom':
  578. offset = {
  579. top: position.top + position.height,
  580. left: position.left + position.width / 2 - actualWidth / 2
  581. };
  582. break;
  583. case 'left':
  584. offset = {
  585. top: position.top + position.height / 2 - actualHeight / 2,
  586. left: position.left - actualWidth
  587. };
  588. break;
  589. default:
  590. offset = {
  591. top: position.top - actualHeight,
  592. left: position.left + position.width / 2 - actualWidth / 2
  593. };
  594. break;
  595. }
  596. if (!split[1]) {
  597. return offset;
  598. }
  599. if (split[0] === 'top' || split[0] === 'bottom') {
  600. switch (split[1]) {
  601. case 'left':
  602. offset.left = position.left;
  603. break;
  604. case 'right':
  605. offset.left = position.left + position.width - actualWidth;
  606. }
  607. } else if (split[0] === 'left' || split[0] === 'right') {
  608. switch (split[1]) {
  609. case 'top':
  610. offset.top = position.top - actualHeight;
  611. break;
  612. case 'bottom':
  613. offset.top = position.top + position.height;
  614. }
  615. }
  616. return offset;
  617. }
  618. function applyPlacement(offset, placement) {
  619. var tip = tipElement[0], width = tip.offsetWidth, height = tip.offsetHeight;
  620. var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10), marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);
  621. if (isNaN(marginTop)) marginTop = 0;
  622. if (isNaN(marginLeft)) marginLeft = 0;
  623. offset.top = offset.top + marginTop;
  624. offset.left = offset.left + marginLeft;
  625. dimensions.setOffset(tip, angular.extend({
  626. using: function(props) {
  627. tipElement.css({
  628. top: Math.round(props.top) + 'px',
  629. left: Math.round(props.left) + 'px',
  630. right: ''
  631. });
  632. }
  633. }, offset), 0);
  634. var actualWidth = tip.offsetWidth, actualHeight = tip.offsetHeight;
  635. if (placement === 'top' && actualHeight !== height) {
  636. offset.top = offset.top + height - actualHeight;
  637. }
  638. if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;
  639. var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);
  640. if (delta.left) {
  641. offset.left += delta.left;
  642. } else {
  643. offset.top += delta.top;
  644. }
  645. dimensions.setOffset(tip, offset);
  646. if (/top|right|bottom|left/.test(placement)) {
  647. var isVertical = /top|bottom/.test(placement), arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight, arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';
  648. replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);
  649. }
  650. }
  651. function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {
  652. var delta = {
  653. top: 0,
  654. left: 0
  655. };
  656. if (!$tooltip.$viewport) return delta;
  657. var viewportPadding = options.viewport && options.viewport.padding || 0;
  658. var viewportDimensions = getPosition($tooltip.$viewport);
  659. if (/right|left/.test(placement)) {
  660. var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll;
  661. var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;
  662. if (topEdgeOffset < viewportDimensions.top) {
  663. delta.top = viewportDimensions.top - topEdgeOffset;
  664. } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) {
  665. delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;
  666. }
  667. } else {
  668. var leftEdgeOffset = position.left - viewportPadding;
  669. var rightEdgeOffset = position.left + viewportPadding + actualWidth;
  670. if (leftEdgeOffset < viewportDimensions.left) {
  671. delta.left = viewportDimensions.left - leftEdgeOffset;
  672. } else if (rightEdgeOffset > viewportDimensions.right) {
  673. delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;
  674. }
  675. }
  676. return delta;
  677. }
  678. function replaceArrow(delta, dimension, isHorizontal) {
  679. var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);
  680. $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%').css(isHorizontal ? 'top' : 'left', '');
  681. }
  682. function destroyTipElement() {
  683. clearTimeout(timeout);
  684. if ($tooltip.$isShown && tipElement !== null) {
  685. if (options.autoClose) {
  686. unbindAutoCloseEvents();
  687. }
  688. if (options.keyboard) {
  689. unbindKeyboardEvents();
  690. }
  691. }
  692. if (tipScope) {
  693. tipScope.$destroy();
  694. tipScope = null;
  695. }
  696. if (tipElement) {
  697. tipElement.remove();
  698. tipElement = $tooltip.$element = null;
  699. }
  700. }
  701. return $tooltip;
  702. }
  703. function safeDigest(scope) {
  704. scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
  705. }
  706. function findElement(query, element) {
  707. return angular.element((element || document).querySelectorAll(query));
  708. }
  709. var fetchPromises = {};
  710. function fetchTemplate(template) {
  711. if (fetchPromises[template]) return fetchPromises[template];
  712. return fetchPromises[template] = $http.get(template, {
  713. cache: $templateCache
  714. }).then(function(res) {
  715. return res.data;
  716. });
  717. }
  718. return TooltipFactory;
  719. } ];
  720. }).directive('bsTooltip', [ '$window', '$location', '$sce', '$tooltip', '$$rAF', function($window, $location, $sce, $tooltip, $$rAF) {
  721. return {
  722. restrict: 'EAC',
  723. scope: true,
  724. link: function postLink(scope, element, attr, transclusion) {
  725. var options = {
  726. scope: scope
  727. };
  728. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id' ], function(key) {
  729. if (angular.isDefined(attr[key])) options[key] = attr[key];
  730. });
  731. var falseValueRegExp = /^(false|0|)$/i;
  732. angular.forEach([ 'html', 'container' ], function(key) {
  733. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  734. });
  735. var dataTarget = element.attr('data-target');
  736. if (angular.isDefined(dataTarget)) {
  737. if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget;
  738. }
  739. if (!scope.hasOwnProperty('title')) {
  740. scope.title = '';
  741. }
  742. attr.$observe('title', function(newValue) {
  743. if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
  744. var oldValue = scope.title;
  745. scope.title = $sce.trustAsHtml(newValue);
  746. angular.isDefined(oldValue) && $$rAF(function() {
  747. tooltip && tooltip.$applyPlacement();
  748. });
  749. }
  750. });
  751. attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
  752. if (angular.isObject(newValue)) {
  753. angular.extend(scope, newValue);
  754. } else {
  755. scope.title = newValue;
  756. }
  757. angular.isDefined(oldValue) && $$rAF(function() {
  758. tooltip && tooltip.$applyPlacement();
  759. });
  760. }, true);
  761. attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
  762. if (!tooltip || !angular.isDefined(newValue)) return;
  763. if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
  764. newValue === true ? tooltip.show() : tooltip.hide();
  765. });
  766. attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
  767. if (!tooltip || !angular.isDefined(newValue)) return;
  768. if (angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
  769. newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);
  770. });
  771. attr.viewport && scope.$watch(attr.viewport, function(newValue) {
  772. if (!tooltip || !angular.isDefined(newValue)) return;
  773. tooltip.setViewport(newValue);
  774. });
  775. var tooltip = $tooltip(element, options);
  776. scope.$on('$destroy', function() {
  777. if (tooltip) tooltip.destroy();
  778. options = null;
  779. tooltip = null;
  780. });
  781. }
  782. };
  783. } ]);
  784. angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$timepicker', function() {
  785. var defaults = this.defaults = {
  786. animation: 'am-fade',
  787. prefixClass: 'timepicker',
  788. placement: 'bottom-left',
  789. templateUrl: 'timepicker/timepicker.tpl.html',
  790. trigger: 'focus',
  791. container: false,
  792. keyboard: true,
  793. html: false,
  794. delay: 0,
  795. useNative: true,
  796. timeType: 'date',
  797. timeFormat: 'shortTime',
  798. timezone: null,
  799. modelTimeFormat: null,
  800. autoclose: false,
  801. minTime: -Infinity,
  802. maxTime: +Infinity,
  803. length: 5,
  804. hourStep: 1,
  805. minuteStep: 5,
  806. secondStep: 5,
  807. roundDisplay: false,
  808. iconUp: 'glyphicon glyphicon-chevron-up',
  809. iconDown: 'glyphicon glyphicon-chevron-down',
  810. arrowBehavior: 'pager'
  811. };
  812. this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {
  813. var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent);
  814. var isTouch = 'createTouch' in $window.document && isNative;
  815. if (!defaults.lang) {
  816. defaults.lang = $dateFormatter.getDefaultLocale();
  817. }
  818. function timepickerFactory(element, controller, config) {
  819. var $timepicker = $tooltip(element, angular.extend({}, defaults, config));
  820. var parentScope = config.scope;
  821. var options = $timepicker.$options;
  822. var scope = $timepicker.$scope;
  823. var lang = options.lang;
  824. var formatDate = function(date, format, timezone) {
  825. return $dateFormatter.formatDate(date, format, lang, timezone);
  826. };
  827. function floorMinutes(time) {
  828. var coeff = 1e3 * 60 * options.minuteStep;
  829. return new Date(Math.floor(time.getTime() / coeff) * coeff);
  830. }
  831. var selectedIndex = 0;
  832. var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();
  833. var startDate = controller.$dateValue || defaultDate;
  834. var viewDate = {
  835. hour: startDate.getHours(),
  836. meridian: startDate.getHours() < 12,
  837. minute: startDate.getMinutes(),
  838. second: startDate.getSeconds(),
  839. millisecond: startDate.getMilliseconds()
  840. };
  841. var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);
  842. var hoursFormat = $dateFormatter.hoursFormat(format), timeSeparator = $dateFormatter.timeSeparator(format), minutesFormat = $dateFormatter.minutesFormat(format), secondsFormat = $dateFormatter.secondsFormat(format), showSeconds = $dateFormatter.showSeconds(format), showAM = $dateFormatter.showAM(format);
  843. scope.$iconUp = options.iconUp;
  844. scope.$iconDown = options.iconDown;
  845. scope.$select = function(date, index) {
  846. $timepicker.select(date, index);
  847. };
  848. scope.$moveIndex = function(value, index) {
  849. $timepicker.$moveIndex(value, index);
  850. };
  851. scope.$switchMeridian = function(date) {
  852. $timepicker.switchMeridian(date);
  853. };
  854. $timepicker.update = function(date) {
  855. if (angular.isDate(date) && !isNaN(date.getTime())) {
  856. $timepicker.$date = date;
  857. angular.extend(viewDate, {
  858. hour: date.getHours(),
  859. minute: date.getMinutes(),
  860. second: date.getSeconds(),
  861. millisecond: date.getMilliseconds()
  862. });
  863. $timepicker.$build();
  864. } else if (!$timepicker.$isBuilt) {
  865. $timepicker.$build();
  866. }
  867. };
  868. $timepicker.select = function(date, index, keep) {
  869. if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);
  870. if (!angular.isDate(date)) date = new Date(date);
  871. if (index === 0) controller.$dateValue.setHours(date.getHours()); else if (index === 1) controller.$dateValue.setMinutes(date.getMinutes()); else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds());
  872. controller.$setViewValue(angular.copy(controller.$dateValue));
  873. controller.$render();
  874. if (options.autoclose && !keep) {
  875. $timeout(function() {
  876. $timepicker.hide(true);
  877. });
  878. }
  879. };
  880. $timepicker.switchMeridian = function(date) {
  881. if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {
  882. return;
  883. }
  884. var hours = (date || controller.$dateValue).getHours();
  885. controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);
  886. controller.$setViewValue(angular.copy(controller.$dateValue));
  887. controller.$render();
  888. };
  889. $timepicker.$build = function() {
  890. var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);
  891. var hours = [], hour;
  892. for (i = 0; i < options.length; i++) {
  893. hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);
  894. hours.push({
  895. date: hour,
  896. label: formatDate(hour, hoursFormat),
  897. selected: $timepicker.$date && $timepicker.$isSelected(hour, 0),
  898. disabled: $timepicker.$isDisabled(hour, 0)
  899. });
  900. }
  901. var minutes = [], minute;
  902. for (i = 0; i < options.length; i++) {
  903. minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);
  904. minutes.push({
  905. date: minute,
  906. label: formatDate(minute, minutesFormat),
  907. selected: $timepicker.$date && $timepicker.$isSelected(minute, 1),
  908. disabled: $timepicker.$isDisabled(minute, 1)
  909. });
  910. }
  911. var seconds = [], second;
  912. for (i = 0; i < options.length; i++) {
  913. second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);
  914. seconds.push({
  915. date: second,
  916. label: formatDate(second, secondsFormat),
  917. selected: $timepicker.$date && $timepicker.$isSelected(second, 2),
  918. disabled: $timepicker.$isDisabled(second, 2)
  919. });
  920. }
  921. var rows = [];
  922. for (i = 0; i < options.length; i++) {
  923. if (showSeconds) {
  924. rows.push([ hours[i], minutes[i], seconds[i] ]);
  925. } else {
  926. rows.push([ hours[i], minutes[i] ]);
  927. }
  928. }
  929. scope.rows = rows;
  930. scope.showSeconds = showSeconds;
  931. scope.showAM = showAM;
  932. scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;
  933. scope.timeSeparator = timeSeparator;
  934. $timepicker.$isBuilt = true;
  935. };
  936. $timepicker.$isSelected = function(date, index) {
  937. if (!$timepicker.$date) return false; else if (index === 0) {
  938. return date.getHours() === $timepicker.$date.getHours();
  939. } else if (index === 1) {
  940. return date.getMinutes() === $timepicker.$date.getMinutes();
  941. } else if (index === 2) {
  942. return date.getSeconds() === $timepicker.$date.getSeconds();
  943. }
  944. };
  945. $timepicker.$isDisabled = function(date, index) {
  946. var selectedTime;
  947. if (index === 0) {
  948. selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;
  949. } else if (index === 1) {
  950. selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;
  951. } else if (index === 2) {
  952. selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;
  953. }
  954. return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;
  955. };
  956. scope.$arrowAction = function(value, index) {
  957. if (options.arrowBehavior === 'picker') {
  958. $timepicker.$setTimeByStep(value, index);
  959. } else {
  960. $timepicker.$moveIndex(value, index);
  961. }
  962. };
  963. $timepicker.$setTimeByStep = function(value, index) {
  964. var newDate = new Date($timepicker.$date || startDate);
  965. var hours = newDate.getHours();
  966. var minutes = newDate.getMinutes();
  967. var seconds = newDate.getSeconds();
  968. if (index === 0) {
  969. newDate.setHours(hours - parseInt(options.hourStep, 10) * value);
  970. } else if (index === 1) {
  971. newDate.setMinutes(minutes - parseInt(options.minuteStep, 10) * value);
  972. } else if (index === 2) {
  973. newDate.setSeconds(seconds - parseInt(options.secondStep, 10) * value);
  974. }
  975. $timepicker.select(newDate, index, true);
  976. };
  977. $timepicker.$moveIndex = function(value, index) {
  978. var targetDate;
  979. if (index === 0) {
  980. targetDate = new Date(1970, 0, 1, viewDate.hour + value * options.length, viewDate.minute, viewDate.second);
  981. angular.extend(viewDate, {
  982. hour: targetDate.getHours()
  983. });
  984. } else if (index === 1) {
  985. targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + value * options.length * options.minuteStep, viewDate.second);
  986. angular.extend(viewDate, {
  987. minute: targetDate.getMinutes()
  988. });
  989. } else if (index === 2) {
  990. targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + value * options.length * options.secondStep);
  991. angular.extend(viewDate, {
  992. second: targetDate.getSeconds()
  993. });
  994. }
  995. $timepicker.$build();
  996. };
  997. $timepicker.$onMouseDown = function(evt) {
  998. if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();
  999. evt.stopPropagation();
  1000. if (isTouch) {
  1001. var targetEl = angular.element(evt.target);
  1002. if (targetEl[0].nodeName.toLowerCase() !== 'button') {
  1003. targetEl = targetEl.parent();
  1004. }
  1005. targetEl.triggerHandler('click');
  1006. }
  1007. };
  1008. $timepicker.$onKeyDown = function(evt) {
  1009. if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
  1010. evt.preventDefault();
  1011. evt.stopPropagation();
  1012. if (evt.keyCode === 13) {
  1013. $timepicker.hide(true);
  1014. return;
  1015. }
  1016. var newDate = new Date($timepicker.$date);
  1017. var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
  1018. var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
  1019. var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;
  1020. var sepLength = 1;
  1021. var lateralMove = /(37|39)/.test(evt.keyCode);
  1022. var count = 2 + showSeconds * 1 + showAM * 1;
  1023. if (lateralMove) {
  1024. if (evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; else if (evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;
  1025. }
  1026. var selectRange = [ 0, hoursLength ];
  1027. var incr = 0;
  1028. if (evt.keyCode === 38) incr = -1;
  1029. if (evt.keyCode === 40) incr = +1;
  1030. var isSeconds = selectedIndex === 2 && showSeconds;
  1031. var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;
  1032. if (selectedIndex === 0) {
  1033. newDate.setHours(hours + incr * parseInt(options.hourStep, 10));
  1034. hoursLength = formatDate(newDate, hoursFormat).length;
  1035. selectRange = [ 0, hoursLength ];
  1036. } else if (selectedIndex === 1) {
  1037. newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10));
  1038. minutesLength = formatDate(newDate, minutesFormat).length;
  1039. selectRange = [ hoursLength + sepLength, minutesLength ];
  1040. } else if (isSeconds) {
  1041. newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10));
  1042. secondsLength = formatDate(newDate, secondsFormat).length;
  1043. selectRange = [ hoursLength + sepLength + minutesLength + sepLength, secondsLength ];
  1044. } else if (isMeridian) {
  1045. if (!lateralMove) $timepicker.switchMeridian();
  1046. selectRange = [ hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2 ];
  1047. }
  1048. $timepicker.select(newDate, selectedIndex, true);
  1049. createSelection(selectRange[0], selectRange[1]);
  1050. parentScope.$digest();
  1051. };
  1052. function createSelection(start, length) {
  1053. var end = start + length;
  1054. if (element[0].createTextRange) {
  1055. var selRange = element[0].createTextRange();
  1056. selRange.collapse(true);
  1057. selRange.moveStart('character', start);
  1058. selRange.moveEnd('character', end);
  1059. selRange.select();
  1060. } else if (element[0].setSelectionRange) {
  1061. element[0].setSelectionRange(start, end);
  1062. } else if (angular.isUndefined(element[0].selectionStart)) {
  1063. element[0].selectionStart = start;
  1064. element[0].selectionEnd = end;
  1065. }
  1066. }
  1067. function focusElement() {
  1068. element[0].focus();
  1069. }
  1070. var _init = $timepicker.init;
  1071. $timepicker.init = function() {
  1072. if (isNative && options.useNative) {
  1073. element.prop('type', 'time');
  1074. element.css('-webkit-appearance', 'textfield');
  1075. return;
  1076. } else if (isTouch) {
  1077. element.prop('type', 'text');
  1078. element.attr('readonly', 'true');
  1079. element.on('click', focusElement);
  1080. }
  1081. _init();
  1082. };
  1083. var _destroy = $timepicker.destroy;
  1084. $timepicker.destroy = function() {
  1085. if (isNative && options.useNative) {
  1086. element.off('click', focusElement);
  1087. }
  1088. _destroy();
  1089. };
  1090. var _show = $timepicker.show;
  1091. $timepicker.show = function() {
  1092. if (!isTouch && element.attr('readonly') || element.attr('disabled')) return;
  1093. _show();
  1094. $timeout(function() {
  1095. $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
  1096. if (options.keyboard) {
  1097. element && element.on('keydown', $timepicker.$onKeyDown);
  1098. }
  1099. }, 0, false);
  1100. };
  1101. var _hide = $timepicker.hide;
  1102. $timepicker.hide = function(blur) {
  1103. if (!$timepicker.$isShown) return;
  1104. $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
  1105. if (options.keyboard) {
  1106. element && element.off('keydown', $timepicker.$onKeyDown);
  1107. }
  1108. _hide(blur);
  1109. };
  1110. return $timepicker;
  1111. }
  1112. timepickerFactory.defaults = defaults;
  1113. return timepickerFactory;
  1114. } ];
  1115. }).directive('bsTimepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$timepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {
  1116. var defaults = $timepicker.defaults;
  1117. var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent);
  1118. return {
  1119. restrict: 'EAC',
  1120. require: 'ngModel',
  1121. link: function postLink(scope, element, attr, controller) {
  1122. var options = {
  1123. scope: scope
  1124. };
  1125. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
  1126. if (angular.isDefined(attr[key])) options[key] = attr[key];
  1127. });
  1128. var falseValueRegExp = /^(false|0|)$/i;
  1129. angular.forEach([ 'html', 'container', 'autoclose', 'useNative', 'roundDisplay' ], function(key) {
  1130. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  1131. });
  1132. attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
  1133. if (!timepicker || !angular.isDefined(newValue)) return;
  1134. if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);
  1135. newValue === true ? timepicker.show() : timepicker.hide();
  1136. });
  1137. if (isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';
  1138. var timepicker = $timepicker(element, controller, options);
  1139. options = timepicker.$options;
  1140. var lang = options.lang;
  1141. var formatDate = function(date, format, timezone) {
  1142. return $dateFormatter.formatDate(date, format, lang, timezone);
  1143. };
  1144. var dateParser = $dateParser({
  1145. format: options.timeFormat,
  1146. lang: lang
  1147. });
  1148. angular.forEach([ 'minTime', 'maxTime' ], function(key) {
  1149. angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
  1150. timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);
  1151. !isNaN(timepicker.$options[key]) && timepicker.$build();
  1152. validateAgainstMinMaxTime(controller.$dateValue);
  1153. });
  1154. });
  1155. scope.$watch(attr.ngModel, function(newValue, oldValue) {
  1156. timepicker.update(controller.$dateValue);
  1157. }, true);
  1158. function validateAgainstMinMaxTime(parsedTime) {
  1159. if (!angular.isDate(parsedTime)) return;
  1160. var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;
  1161. var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;
  1162. var isValid = isMinValid && isMaxValid;
  1163. controller.$setValidity('date', isValid);
  1164. controller.$setValidity('min', isMinValid);
  1165. controller.$setValidity('max', isMaxValid);
  1166. if (!isValid) {
  1167. return;
  1168. }
  1169. controller.$dateValue = parsedTime;
  1170. }
  1171. controller.$parsers.unshift(function(viewValue) {
  1172. var date;
  1173. if (!viewValue) {
  1174. controller.$setValidity('date', true);
  1175. return null;
  1176. }
  1177. var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);
  1178. if (!parsedTime || isNaN(parsedTime.getTime())) {
  1179. controller.$setValidity('date', false);
  1180. return undefined;
  1181. } else {
  1182. validateAgainstMinMaxTime(parsedTime);
  1183. }
  1184. if (options.timeType === 'string') {
  1185. date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);
  1186. return formatDate(date, options.modelTimeFormat || options.timeFormat);
  1187. }
  1188. date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);
  1189. if (options.timeType === 'number') {
  1190. return date.getTime();
  1191. } else if (options.timeType === 'unix') {
  1192. return date.getTime() / 1e3;
  1193. } else if (options.timeType === 'iso') {
  1194. return date.toISOString();
  1195. } else {
  1196. return new Date(date);
  1197. }
  1198. });
  1199. controller.$formatters.push(function(modelValue) {
  1200. var date;
  1201. if (angular.isUndefined(modelValue) || modelValue === null) {
  1202. date = NaN;
  1203. } else if (angular.isDate(modelValue)) {
  1204. date = modelValue;
  1205. } else if (options.timeType === 'string') {
  1206. date = dateParser.parse(modelValue, null, options.modelTimeFormat);
  1207. } else if (options.timeType === 'unix') {
  1208. date = new Date(modelValue * 1e3);
  1209. } else {
  1210. date = new Date(modelValue);
  1211. }
  1212. controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);
  1213. return getTimeFormattedString();
  1214. });
  1215. controller.$render = function() {
  1216. element.val(getTimeFormattedString());
  1217. };
  1218. function getTimeFormattedString() {
  1219. return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);
  1220. }
  1221. scope.$on('$destroy', function() {
  1222. if (timepicker) timepicker.destroy();
  1223. options = null;
  1224. timepicker = null;
  1225. });
  1226. }
  1227. };
  1228. } ]);
  1229. angular.module('mgcrea.ngStrap.tab', []).provider('$tab', function() {
  1230. var defaults = this.defaults = {
  1231. animation: 'am-fade',
  1232. template: 'tab/tab.tpl.html',
  1233. navClass: 'nav-tabs',
  1234. activeClass: 'active'
  1235. };
  1236. var controller = this.controller = function($scope, $element, $attrs) {
  1237. var self = this;
  1238. self.$options = angular.copy(defaults);
  1239. angular.forEach([ 'animation', 'navClass', 'activeClass' ], function(key) {
  1240. if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
  1241. });
  1242. $scope.$navClass = self.$options.navClass;
  1243. $scope.$activeClass = self.$options.activeClass;
  1244. self.$panes = $scope.$panes = [];
  1245. self.$activePaneChangeListeners = self.$viewChangeListeners = [];
  1246. self.$push = function(pane) {
  1247. if (angular.isUndefined(self.$panes.$active)) {
  1248. $scope.$setActive(pane.name || 0);
  1249. }
  1250. self.$panes.push(pane);
  1251. };
  1252. self.$remove = function(pane) {
  1253. var index = self.$panes.indexOf(pane);
  1254. var active = self.$panes.$active;
  1255. var activeIndex;
  1256. if (angular.isString(active)) {
  1257. activeIndex = self.$panes.map(function(pane) {
  1258. return pane.name;
  1259. }).indexOf(active);
  1260. } else {
  1261. activeIndex = self.$panes.$active;
  1262. }
  1263. self.$panes.splice(index, 1);
  1264. if (index < activeIndex) {
  1265. activeIndex--;
  1266. } else if (index === activeIndex && activeIndex === self.$panes.length) {
  1267. activeIndex--;
  1268. }
  1269. if (activeIndex >= 0 && activeIndex < self.$panes.length) {
  1270. self.$setActive(self.$panes[activeIndex].name || activeIndex);
  1271. } else {
  1272. self.$setActive();
  1273. }
  1274. };
  1275. self.$setActive = $scope.$setActive = function(value) {
  1276. self.$panes.$active = value;
  1277. self.$activePaneChangeListeners.forEach(function(fn) {
  1278. fn();
  1279. });
  1280. };
  1281. self.$isActive = $scope.$isActive = function($pane, $index) {
  1282. return self.$panes.$active === $pane.name || self.$panes.$active === $index;
  1283. };
  1284. };
  1285. this.$get = function() {
  1286. var $tab = {};
  1287. $tab.defaults = defaults;
  1288. $tab.controller = controller;
  1289. return $tab;
  1290. };
  1291. }).directive('bsTabs', [ '$window', '$animate', '$tab', '$parse', function($window, $animate, $tab, $parse) {
  1292. var defaults = $tab.defaults;
  1293. return {
  1294. require: [ '?ngModel', 'bsTabs' ],
  1295. transclude: true,
  1296. scope: true,
  1297. controller: [ '$scope', '$element', '$attrs', $tab.controller ],
  1298. templateUrl: function(element, attr) {
  1299. return attr.template || defaults.template;
  1300. },
  1301. link: function postLink(scope, element, attrs, controllers) {
  1302. var ngModelCtrl = controllers[0];
  1303. var bsTabsCtrl = controllers[1];
  1304. if (ngModelCtrl) {
  1305. bsTabsCtrl.$activePaneChangeListeners.push(function() {
  1306. ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);
  1307. });
  1308. ngModelCtrl.$formatters.push(function(modelValue) {
  1309. bsTabsCtrl.$setActive(modelValue);
  1310. return modelValue;
  1311. });
  1312. }
  1313. if (attrs.bsActivePane) {
  1314. var parsedBsActivePane = $parse(attrs.bsActivePane);
  1315. bsTabsCtrl.$activePaneChangeListeners.push(function() {
  1316. parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);
  1317. });
  1318. scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {
  1319. bsTabsCtrl.$setActive(newValue);
  1320. }, true);
  1321. }
  1322. }
  1323. };
  1324. } ]).directive('bsPane', [ '$window', '$animate', '$sce', function($window, $animate, $sce) {
  1325. return {
  1326. require: [ '^?ngModel', '^bsTabs' ],
  1327. scope: true,
  1328. link: function postLink(scope, element, attrs, controllers) {
  1329. var ngModelCtrl = controllers[0];
  1330. var bsTabsCtrl = controllers[1];
  1331. element.addClass('tab-pane');
  1332. attrs.$observe('title', function(newValue, oldValue) {
  1333. scope.title = $sce.trustAsHtml(newValue);
  1334. });
  1335. scope.name = attrs.name;
  1336. if (bsTabsCtrl.$options.animation) {
  1337. element.addClass(bsTabsCtrl.$options.animation);
  1338. }
  1339. attrs.$observe('disabled', function(newValue, oldValue) {
  1340. scope.disabled = scope.$eval(newValue);
  1341. });
  1342. bsTabsCtrl.$push(scope);
  1343. scope.$on('$destroy', function() {
  1344. bsTabsCtrl.$remove(scope);
  1345. });
  1346. function render() {
  1347. var index = bsTabsCtrl.$panes.indexOf(scope);
  1348. $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
  1349. }
  1350. bsTabsCtrl.$activePaneChangeListeners.push(function() {
  1351. render();
  1352. });
  1353. render();
  1354. }
  1355. };
  1356. } ]);
  1357. angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$select', function() {
  1358. var defaults = this.defaults = {
  1359. animation: 'am-fade',
  1360. prefixClass: 'select',
  1361. prefixEvent: '$select',
  1362. placement: 'bottom-left',
  1363. templateUrl: 'select/select.tpl.html',
  1364. trigger: 'focus',
  1365. container: false,
  1366. keyboard: true,
  1367. html: false,
  1368. delay: 0,
  1369. multiple: false,
  1370. allNoneButtons: false,
  1371. sort: true,
  1372. caretHtml: '&nbsp;<span class="caret"></span>',
  1373. placeholder: 'Choose among the following...',
  1374. allText: 'All',
  1375. noneText: 'None',
  1376. maxLength: 3,
  1377. maxLengthHtml: 'selected',
  1378. iconCheckmark: 'glyphicon glyphicon-ok'
  1379. };
  1380. this.$get = [ '$window', '$document', '$rootScope', '$tooltip', '$timeout', function($window, $document, $rootScope, $tooltip, $timeout) {
  1381. var bodyEl = angular.element($window.document.body);
  1382. var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent);
  1383. var isTouch = 'createTouch' in $window.document && isNative;
  1384. function SelectFactory(element, controller, config) {
  1385. var $select = {};
  1386. var options = angular.extend({}, defaults, config);
  1387. $select = $tooltip(element, options);
  1388. var scope = $select.$scope;
  1389. scope.$matches = [];
  1390. if (options.multiple) {
  1391. scope.$activeIndex = [];
  1392. } else {
  1393. scope.$activeIndex = -1;
  1394. }
  1395. scope.$isMultiple = options.multiple;
  1396. scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;
  1397. scope.$iconCheckmark = options.iconCheckmark;
  1398. scope.$allText = options.allText;
  1399. scope.$noneText = options.noneText;
  1400. scope.$activate = function(index) {
  1401. scope.$$postDigest(function() {
  1402. $select.activate(index);
  1403. });
  1404. };
  1405. scope.$select = function(index, evt) {
  1406. scope.$$postDigest(function() {
  1407. $select.select(index);
  1408. });
  1409. };
  1410. scope.$isVisible = function() {
  1411. return $select.$isVisible();
  1412. };
  1413. scope.$isActive = function(index) {
  1414. return $select.$isActive(index);
  1415. };
  1416. scope.$selectAll = function() {
  1417. for (var i = 0; i < scope.$matches.length; i++) {
  1418. if (!scope.$isActive(i)) {
  1419. scope.$select(i);
  1420. }
  1421. }
  1422. };
  1423. scope.$selectNone = function() {
  1424. for (var i = 0; i < scope.$matches.length; i++) {
  1425. if (scope.$isActive(i)) {
  1426. scope.$select(i);
  1427. }
  1428. }
  1429. };
  1430. $select.update = function(matches) {
  1431. scope.$matches = matches;
  1432. $select.$updateActiveIndex();
  1433. };
  1434. $select.activate = function(index) {
  1435. if (options.multiple) {
  1436. $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);
  1437. if (options.sort) scope.$activeIndex.sort(function(a, b) {
  1438. return a - b;
  1439. });
  1440. } else {
  1441. scope.$activeIndex = index;
  1442. }
  1443. return scope.$activeIndex;
  1444. };
  1445. $select.select = function(index) {
  1446. var value = scope.$matches[index].value;
  1447. scope.$apply(function() {
  1448. $select.activate(index);
  1449. if (options.multiple) {
  1450. controller.$setViewValue(scope.$activeIndex.map(function(index) {
  1451. if (angular.isUndefined(scope.$matches[index])) {
  1452. return null;
  1453. }
  1454. return scope.$matches[index].value;
  1455. }));
  1456. } else {
  1457. controller.$setViewValue(value);
  1458. $select.hide();
  1459. }
  1460. });
  1461. scope.$emit(options.prefixEvent + '.select', value, index, $select);
  1462. };
  1463. $select.$updateActiveIndex = function() {
  1464. if (options.multiple) {
  1465. if (angular.isArray(controller.$modelValue)) {
  1466. scope.$activeIndex = controller.$modelValue.map(function(value) {
  1467. return $select.$getIndex(value);
  1468. });
  1469. } else {
  1470. scope.$activeIndex = [];
  1471. }
  1472. } else {
  1473. if (angular.isDefined(controller.$modelValue) && scope.$matches.length) {
  1474. scope.$activeIndex = $select.$getIndex(controller.$modelValue);
  1475. } else {
  1476. scope.$activeIndex = -1;
  1477. }
  1478. }
  1479. };
  1480. $select.$isVisible = function() {
  1481. if (!options.minLength || !controller) {
  1482. return scope.$matches.length;
  1483. }
  1484. return scope.$matches.length && controller.$viewValue.length >= options.minLength;
  1485. };
  1486. $select.$isActive = function(index) {
  1487. if (options.multiple) {
  1488. return scope.$activeIndex.indexOf(index) !== -1;
  1489. } else {
  1490. return scope.$activeIndex === index;
  1491. }
  1492. };
  1493. $select.$getIndex = function(value) {
  1494. var l = scope.$matches.length, i = l;
  1495. if (!l) return;
  1496. for (i = l; i--; ) {
  1497. if (scope.$matches[i].value === value) break;
  1498. }
  1499. if (i < 0) return;
  1500. return i;
  1501. };
  1502. $select.$onMouseDown = function(evt) {
  1503. evt.preventDefault();
  1504. evt.stopPropagation();
  1505. if (isTouch) {
  1506. var targetEl = angular.element(evt.target);
  1507. targetEl.triggerHandler('click');
  1508. }
  1509. };
  1510. $select.$onKeyDown = function(evt) {
  1511. if (!/(9|13|38|40)/.test(evt.keyCode)) return;
  1512. if (evt.keyCode !== 9) {
  1513. evt.preventDefault();
  1514. evt.stopPropagation();
  1515. }
  1516. if (options.multiple && evt.keyCode === 9) {
  1517. return $select.hide();
  1518. }
  1519. if (!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {
  1520. return $select.select(scope.$activeIndex);
  1521. }
  1522. if (!options.multiple) {
  1523. if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;
  1524. scope.$digest();
  1525. }
  1526. };
  1527. $select.$isIE = function() {
  1528. var ua = $window.navigator.userAgent;
  1529. return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0;
  1530. };
  1531. $select.$selectScrollFix = function(e) {
  1532. if ($document[0].activeElement.tagName === 'UL') {
  1533. e.preventDefault();
  1534. e.stopImmediatePropagation();
  1535. e.target.focus();
  1536. }
  1537. };
  1538. var _show = $select.show;
  1539. $select.show = function() {
  1540. _show();
  1541. if (options.multiple) {
  1542. $select.$element.addClass('select-multiple');
  1543. }
  1544. $timeout(function() {
  1545. $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
  1546. if (options.keyboard) {
  1547. element.on('keydown', $select.$onKeyDown);
  1548. }
  1549. }, 0, false);
  1550. };
  1551. var _hide = $select.hide;
  1552. $select.hide = function() {
  1553. if (!options.multiple && angular.isUndefined(controller.$modelValue)) {
  1554. scope.$activeIndex = -1;
  1555. }
  1556. $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
  1557. if (options.keyboard) {
  1558. element.off('keydown', $select.$onKeyDown);
  1559. }
  1560. _hide(true);
  1561. };
  1562. return $select;
  1563. }
  1564. SelectFactory.defaults = defaults;
  1565. return SelectFactory;
  1566. } ];
  1567. }).directive('bsSelect', [ '$window', '$parse', '$q', '$select', '$parseOptions', function($window, $parse, $q, $select, $parseOptions) {
  1568. var defaults = $select.defaults;
  1569. return {
  1570. restrict: 'EAC',
  1571. require: 'ngModel',
  1572. link: function postLink(scope, element, attr, controller) {
  1573. var options = {
  1574. scope: scope,
  1575. placeholder: defaults.placeholder
  1576. };
  1577. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent' ], function(key) {
  1578. if (angular.isDefined(attr[key])) options[key] = attr[key];
  1579. });
  1580. var falseValueRegExp = /^(false|0|)$/i;
  1581. angular.forEach([ 'html', 'container', 'allNoneButtons', 'sort' ], function(key) {
  1582. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  1583. });
  1584. var dataMultiple = element.attr('data-multiple');
  1585. if (angular.isDefined(dataMultiple)) {
  1586. if (falseValueRegExp.test(dataMultiple)) options.multiple = false; else options.multiple = dataMultiple;
  1587. }
  1588. if (element[0].nodeName.toLowerCase() === 'select') {
  1589. var inputEl = element;
  1590. inputEl.css('display', 'none');
  1591. element = angular.element('<button type="button" class="btn btn-default"></button>');
  1592. inputEl.after(element);
  1593. }
  1594. var parsedOptions = $parseOptions(attr.bsOptions);
  1595. var select = $select(element, controller, options);
  1596. if (select.$isIE()) {
  1597. element[0].addEventListener('blur', select.$selectScrollFix);
  1598. }
  1599. var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim();
  1600. scope.$watchCollection(watchedOptions, function(newValue, oldValue) {
  1601. parsedOptions.valuesFn(scope, controller).then(function(values) {
  1602. select.update(values);
  1603. controller.$render();
  1604. });
  1605. });
  1606. scope.$watch(attr.ngModel, function(newValue, oldValue) {
  1607. select.$updateActiveIndex();
  1608. controller.$render();
  1609. }, true);
  1610. controller.$render = function() {
  1611. var selected, index;
  1612. if (options.multiple && angular.isArray(controller.$modelValue)) {
  1613. selected = controller.$modelValue.map(function(value) {
  1614. index = select.$getIndex(value);
  1615. return angular.isDefined(index) ? select.$scope.$matches[index].label : false;
  1616. }).filter(angular.isDefined);
  1617. if (selected.length > (options.maxLength || defaults.maxLength)) {
  1618. selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);
  1619. } else {
  1620. selected = selected.join(', ');
  1621. }
  1622. } else {
  1623. index = select.$getIndex(controller.$modelValue);
  1624. selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;
  1625. }
  1626. element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml));
  1627. };
  1628. if (options.multiple) {
  1629. controller.$isEmpty = function(value) {
  1630. return !value || value.length === 0;
  1631. };
  1632. }
  1633. scope.$on('$destroy', function() {
  1634. if (select) select.destroy();
  1635. options = null;
  1636. select = null;
  1637. });
  1638. }
  1639. };
  1640. } ]);
  1641. angular.module('mgcrea.ngStrap.scrollspy', [ 'mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$scrollspy', function() {
  1642. var spies = this.$$spies = {};
  1643. var defaults = this.defaults = {
  1644. debounce: 150,
  1645. throttle: 100,
  1646. offset: 100
  1647. };
  1648. this.$get = [ '$window', '$document', '$rootScope', 'dimensions', 'debounce', 'throttle', function($window, $document, $rootScope, dimensions, debounce, throttle) {
  1649. var windowEl = angular.element($window);
  1650. var docEl = angular.element($document.prop('documentElement'));
  1651. var bodyEl = angular.element($window.document.body);
  1652. function nodeName(element, name) {
  1653. return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();
  1654. }
  1655. function ScrollSpyFactory(config) {
  1656. var options = angular.extend({}, defaults, config);
  1657. if (!options.element) options.element = bodyEl;
  1658. var isWindowSpy = nodeName(options.element, 'body');
  1659. var scrollEl = isWindowSpy ? windowEl : options.element;
  1660. var scrollId = isWindowSpy ? 'window' : options.id;
  1661. if (spies[scrollId]) {
  1662. spies[scrollId].$$count++;
  1663. return spies[scrollId];
  1664. }
  1665. var $scrollspy = {};
  1666. var unbindViewContentLoaded, unbindIncludeContentLoaded;
  1667. var trackedElements = $scrollspy.$trackedElements = [];
  1668. var sortedElements = [];
  1669. var activeTarget;
  1670. var debouncedCheckPosition;
  1671. var throttledCheckPosition;
  1672. var debouncedCheckOffsets;
  1673. var viewportHeight;
  1674. var scrollTop;
  1675. $scrollspy.init = function() {
  1676. this.$$count = 1;
  1677. debouncedCheckPosition = debounce(this.checkPosition, options.debounce);
  1678. throttledCheckPosition = throttle(this.checkPosition, options.throttle);
  1679. scrollEl.on('click', this.checkPositionWithEventLoop);
  1680. windowEl.on('resize', debouncedCheckPosition);
  1681. scrollEl.on('scroll', throttledCheckPosition);
  1682. debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);
  1683. unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);
  1684. unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);
  1685. debouncedCheckOffsets();
  1686. if (scrollId) {
  1687. spies[scrollId] = $scrollspy;
  1688. }
  1689. };
  1690. $scrollspy.destroy = function() {
  1691. this.$$count--;
  1692. if (this.$$count > 0) {
  1693. return;
  1694. }
  1695. scrollEl.off('click', this.checkPositionWithEventLoop);
  1696. windowEl.off('resize', debouncedCheckPosition);
  1697. scrollEl.off('scroll', throttledCheckPosition);
  1698. unbindViewContentLoaded();
  1699. unbindIncludeContentLoaded();
  1700. if (scrollId) {
  1701. delete spies[scrollId];
  1702. }
  1703. };
  1704. $scrollspy.checkPosition = function() {
  1705. if (!sortedElements.length) return;
  1706. scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;
  1707. viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));
  1708. if (scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {
  1709. return $scrollspy.$activateElement(sortedElements[0]);
  1710. }
  1711. for (var i = sortedElements.length; i--; ) {
  1712. if (angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;
  1713. if (activeTarget === sortedElements[i].target) continue;
  1714. if (scrollTop < sortedElements[i].offsetTop) continue;
  1715. if (sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;
  1716. return $scrollspy.$activateElement(sortedElements[i]);
  1717. }
  1718. };
  1719. $scrollspy.checkPositionWithEventLoop = function() {
  1720. setTimeout($scrollspy.checkPosition, 1);
  1721. };
  1722. $scrollspy.$activateElement = function(element) {
  1723. if (activeTarget) {
  1724. var activeElement = $scrollspy.$getTrackedElement(activeTarget);
  1725. if (activeElement) {
  1726. activeElement.source.removeClass('active');
  1727. if (nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {
  1728. activeElement.source.parent().parent().removeClass('active');
  1729. }
  1730. }
  1731. }
  1732. activeTarget = element.target;
  1733. element.source.addClass('active');
  1734. if (nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {
  1735. element.source.parent().parent().addClass('active');
  1736. }
  1737. };
  1738. $scrollspy.$getTrackedElement = function(target) {
  1739. return trackedElements.filter(function(obj) {
  1740. return obj.target === target;
  1741. })[0];
  1742. };
  1743. $scrollspy.checkOffsets = function() {
  1744. angular.forEach(trackedElements, function(trackedElement) {
  1745. var targetElement = document.querySelector(trackedElement.target);
  1746. trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;
  1747. if (options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;
  1748. });
  1749. sortedElements = trackedElements.filter(function(el) {
  1750. return el.offsetTop !== null;
  1751. }).sort(function(a, b) {
  1752. return a.offsetTop - b.offsetTop;
  1753. });
  1754. debouncedCheckPosition();
  1755. };
  1756. $scrollspy.trackElement = function(target, source) {
  1757. trackedElements.push({
  1758. target: target,
  1759. source: source
  1760. });
  1761. };
  1762. $scrollspy.untrackElement = function(target, source) {
  1763. var toDelete;
  1764. for (var i = trackedElements.length; i--; ) {
  1765. if (trackedElements[i].target === target && trackedElements[i].source === source) {
  1766. toDelete = i;
  1767. break;
  1768. }
  1769. }
  1770. trackedElements = trackedElements.splice(toDelete, 1);
  1771. };
  1772. $scrollspy.activate = function(i) {
  1773. trackedElements[i].addClass('active');
  1774. };
  1775. $scrollspy.init();
  1776. return $scrollspy;
  1777. }
  1778. return ScrollSpyFactory;
  1779. } ];
  1780. }).directive('bsScrollspy', [ '$rootScope', 'debounce', 'dimensions', '$scrollspy', function($rootScope, debounce, dimensions, $scrollspy) {
  1781. return {
  1782. restrict: 'EAC',
  1783. link: function postLink(scope, element, attr) {
  1784. var options = {
  1785. scope: scope
  1786. };
  1787. angular.forEach([ 'offset', 'target' ], function(key) {
  1788. if (angular.isDefined(attr[key])) options[key] = attr[key];
  1789. });
  1790. var scrollspy = $scrollspy(options);
  1791. scrollspy.trackElement(options.target, element);
  1792. scope.$on('$destroy', function() {
  1793. if (scrollspy) {
  1794. scrollspy.untrackElement(options.target, element);
  1795. scrollspy.destroy();
  1796. }
  1797. options = null;
  1798. scrollspy = null;
  1799. });
  1800. }
  1801. };
  1802. } ]).directive('bsScrollspyList', [ '$rootScope', 'debounce', 'dimensions', '$scrollspy', function($rootScope, debounce, dimensions, $scrollspy) {
  1803. return {
  1804. restrict: 'A',
  1805. compile: function postLink(element, attr) {
  1806. var children = element[0].querySelectorAll('li > a[href]');
  1807. angular.forEach(children, function(child) {
  1808. var childEl = angular.element(child);
  1809. childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));
  1810. });
  1811. }
  1812. };
  1813. } ]);
  1814. angular.module('mgcrea.ngStrap.popover', [ 'mgcrea.ngStrap.tooltip' ]).provider('$popover', function() {
  1815. var defaults = this.defaults = {
  1816. animation: 'am-fade',
  1817. customClass: '',
  1818. container: false,
  1819. target: false,
  1820. placement: 'right',
  1821. templateUrl: 'popover/popover.tpl.html',
  1822. contentTemplate: false,
  1823. trigger: 'click',
  1824. keyboard: true,
  1825. html: false,
  1826. title: '',
  1827. content: '',
  1828. delay: 0,
  1829. autoClose: false
  1830. };
  1831. this.$get = [ '$tooltip', function($tooltip) {
  1832. function PopoverFactory(element, config) {
  1833. var options = angular.extend({}, defaults, config);
  1834. var $popover = $tooltip(element, options);
  1835. if (options.content) {
  1836. $popover.$scope.content = options.content;
  1837. }
  1838. return $popover;
  1839. }
  1840. return PopoverFactory;
  1841. } ];
  1842. }).directive('bsPopover', [ '$window', '$sce', '$popover', function($window, $sce, $popover) {
  1843. var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
  1844. return {
  1845. restrict: 'EAC',
  1846. scope: true,
  1847. link: function postLink(scope, element, attr) {
  1848. var options = {
  1849. scope: scope
  1850. };
  1851. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
  1852. if (angular.isDefined(attr[key])) options[key] = attr[key];
  1853. });
  1854. var falseValueRegExp = /^(false|0|)$/i;
  1855. angular.forEach([ 'html', 'container', 'autoClose' ], function(key) {
  1856. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  1857. });
  1858. var dataTarget = element.attr('data-target');
  1859. if (angular.isDefined(dataTarget)) {
  1860. if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget;
  1861. }
  1862. angular.forEach([ 'title', 'content' ], function(key) {
  1863. attr[key] && attr.$observe(key, function(newValue, oldValue) {
  1864. scope[key] = $sce.trustAsHtml(newValue);
  1865. angular.isDefined(oldValue) && requestAnimationFrame(function() {
  1866. popover && popover.$applyPlacement();
  1867. });
  1868. });
  1869. });
  1870. attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {
  1871. if (angular.isObject(newValue)) {
  1872. angular.extend(scope, newValue);
  1873. } else {
  1874. scope.content = newValue;
  1875. }
  1876. angular.isDefined(oldValue) && requestAnimationFrame(function() {
  1877. popover && popover.$applyPlacement();
  1878. });
  1879. }, true);
  1880. attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
  1881. if (!popover || !angular.isDefined(newValue)) return;
  1882. if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);
  1883. newValue === true ? popover.show() : popover.hide();
  1884. });
  1885. attr.viewport && scope.$watch(attr.viewport, function(newValue) {
  1886. if (!popover || !angular.isDefined(newValue)) return;
  1887. popover.setViewport(newValue);
  1888. });
  1889. var popover = $popover(element, options);
  1890. scope.$on('$destroy', function() {
  1891. if (popover) popover.destroy();
  1892. options = null;
  1893. popover = null;
  1894. });
  1895. }
  1896. };
  1897. } ]);
  1898. angular.module('mgcrea.ngStrap.navbar', []).provider('$navbar', function() {
  1899. var defaults = this.defaults = {
  1900. activeClass: 'active',
  1901. routeAttr: 'data-match-route',
  1902. strict: false
  1903. };
  1904. this.$get = function() {
  1905. return {
  1906. defaults: defaults
  1907. };
  1908. };
  1909. }).directive('bsNavbar', [ '$window', '$location', '$navbar', function($window, $location, $navbar) {
  1910. var defaults = $navbar.defaults;
  1911. return {
  1912. restrict: 'A',
  1913. link: function postLink(scope, element, attr, controller) {
  1914. var options = angular.copy(defaults);
  1915. angular.forEach(Object.keys(defaults), function(key) {
  1916. if (angular.isDefined(attr[key])) options[key] = attr[key];
  1917. });
  1918. scope.$watch(function() {
  1919. return $location.path();
  1920. }, function(newValue, oldValue) {
  1921. var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');
  1922. angular.forEach(liElements, function(li) {
  1923. var liElement = angular.element(li);
  1924. var pattern = liElement.attr(options.routeAttr).replace('/', '\\/');
  1925. if (options.strict) {
  1926. pattern = '^' + pattern + '$';
  1927. }
  1928. var regexp = new RegExp(pattern, 'i');
  1929. if (regexp.test(newValue)) {
  1930. liElement.addClass(options.activeClass);
  1931. } else {
  1932. liElement.removeClass(options.activeClass);
  1933. }
  1934. });
  1935. });
  1936. }
  1937. };
  1938. } ]);
  1939. angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$modal', function() {
  1940. var defaults = this.defaults = {
  1941. animation: 'am-fade',
  1942. backdropAnimation: 'am-fade',
  1943. prefixClass: 'modal',
  1944. prefixEvent: 'modal',
  1945. placement: 'top',
  1946. templateUrl: 'modal/modal.tpl.html',
  1947. template: '',
  1948. contentTemplate: false,
  1949. container: false,
  1950. element: null,
  1951. backdrop: true,
  1952. keyboard: true,
  1953. html: false,
  1954. show: true
  1955. };
  1956. this.$get = [ '$window', '$rootScope', '$bsCompiler', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $animate, $timeout, $sce, dimensions) {
  1957. var forEach = angular.forEach;
  1958. var trim = String.prototype.trim;
  1959. var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
  1960. var bodyElement = angular.element($window.document.body);
  1961. function ModalFactory(config) {
  1962. var $modal = {};
  1963. var options = $modal.$options = angular.extend({}, defaults, config);
  1964. var promise = $modal.$promise = $bsCompiler.compile(options);
  1965. var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();
  1966. if (!options.element && !options.container) {
  1967. options.container = 'body';
  1968. }
  1969. $modal.$id = options.id || options.element && options.element.attr('id') || '';
  1970. forEach([ 'title', 'content' ], function(key) {
  1971. if (options[key]) scope[key] = $sce.trustAsHtml(options[key]);
  1972. });
  1973. scope.$hide = function() {
  1974. scope.$$postDigest(function() {
  1975. $modal.hide();
  1976. });
  1977. };
  1978. scope.$show = function() {
  1979. scope.$$postDigest(function() {
  1980. $modal.show();
  1981. });
  1982. };
  1983. scope.$toggle = function() {
  1984. scope.$$postDigest(function() {
  1985. $modal.toggle();
  1986. });
  1987. };
  1988. $modal.$isShown = scope.$isShown = false;
  1989. var compileData, modalElement, modalScope;
  1990. var backdropElement = angular.element('<div class="' + options.prefixClass + '-backdrop"/>');
  1991. backdropElement.css({
  1992. position: 'fixed',
  1993. top: '0px',
  1994. left: '0px',
  1995. bottom: '0px',
  1996. right: '0px',
  1997. 'z-index': 1038
  1998. });
  1999. promise.then(function(data) {
  2000. compileData = data;
  2001. $modal.init();
  2002. });
  2003. $modal.init = function() {
  2004. if (options.show) {
  2005. scope.$$postDigest(function() {
  2006. $modal.show();
  2007. });
  2008. }
  2009. };
  2010. $modal.destroy = function() {
  2011. destroyModalElement();
  2012. if (backdropElement) {
  2013. backdropElement.remove();
  2014. backdropElement = null;
  2015. }
  2016. scope.$destroy();
  2017. };
  2018. $modal.show = function() {
  2019. if ($modal.$isShown) return;
  2020. var parent, after;
  2021. if (angular.isElement(options.container)) {
  2022. parent = options.container;
  2023. after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;
  2024. } else {
  2025. if (options.container) {
  2026. parent = findElement(options.container);
  2027. after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;
  2028. } else {
  2029. parent = null;
  2030. after = options.element;
  2031. }
  2032. }
  2033. if (modalElement) destroyModalElement();
  2034. modalScope = $modal.$scope.$new();
  2035. modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});
  2036. if (scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {
  2037. return;
  2038. }
  2039. modalElement.css({
  2040. display: 'block'
  2041. }).addClass(options.placement);
  2042. if (options.animation) {
  2043. if (options.backdrop) {
  2044. backdropElement.addClass(options.backdropAnimation);
  2045. }
  2046. modalElement.addClass(options.animation);
  2047. }
  2048. if (options.backdrop) {
  2049. $animate.enter(backdropElement, bodyElement, null);
  2050. }
  2051. if (angular.version.minor <= 2) {
  2052. $animate.enter(modalElement, parent, after, enterAnimateCallback);
  2053. } else {
  2054. $animate.enter(modalElement, parent, after).then(enterAnimateCallback);
  2055. }
  2056. $modal.$isShown = scope.$isShown = true;
  2057. safeDigest(scope);
  2058. var el = modalElement[0];
  2059. requestAnimationFrame(function() {
  2060. el.focus();
  2061. });
  2062. bodyElement.addClass(options.prefixClass + '-open');
  2063. if (options.animation) {
  2064. bodyElement.addClass(options.prefixClass + '-with-' + options.animation);
  2065. }
  2066. bindBackdropEvents();
  2067. bindKeyboardEvents();
  2068. };
  2069. function enterAnimateCallback() {
  2070. scope.$emit(options.prefixEvent + '.show', $modal);
  2071. }
  2072. $modal.hide = function() {
  2073. if (!$modal.$isShown) return;
  2074. if (scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {
  2075. return;
  2076. }
  2077. if (angular.version.minor <= 2) {
  2078. $animate.leave(modalElement, leaveAnimateCallback);
  2079. } else {
  2080. $animate.leave(modalElement).then(leaveAnimateCallback);
  2081. }
  2082. if (options.backdrop) {
  2083. $animate.leave(backdropElement);
  2084. }
  2085. $modal.$isShown = scope.$isShown = false;
  2086. safeDigest(scope);
  2087. unbindBackdropEvents();
  2088. unbindKeyboardEvents();
  2089. };
  2090. function leaveAnimateCallback() {
  2091. scope.$emit(options.prefixEvent + '.hide', $modal);
  2092. bodyElement.removeClass(options.prefixClass + '-open');
  2093. if (options.animation) {
  2094. bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);
  2095. }
  2096. }
  2097. $modal.toggle = function() {
  2098. $modal.$isShown ? $modal.hide() : $modal.show();
  2099. };
  2100. $modal.focus = function() {
  2101. modalElement[0].focus();
  2102. };
  2103. $modal.$onKeyUp = function(evt) {
  2104. if (evt.which === 27 && $modal.$isShown) {
  2105. $modal.hide();
  2106. evt.stopPropagation();
  2107. }
  2108. };
  2109. function bindBackdropEvents() {
  2110. if (options.backdrop) {
  2111. modalElement.on('click', hideOnBackdropClick);
  2112. backdropElement.on('click', hideOnBackdropClick);
  2113. backdropElement.on('wheel', preventEventDefault);
  2114. }
  2115. }
  2116. function unbindBackdropEvents() {
  2117. if (options.backdrop) {
  2118. modalElement.off('click', hideOnBackdropClick);
  2119. backdropElement.off('click', hideOnBackdropClick);
  2120. backdropElement.off('wheel', preventEventDefault);
  2121. }
  2122. }
  2123. function bindKeyboardEvents() {
  2124. if (options.keyboard) {
  2125. modalElement.on('keyup', $modal.$onKeyUp);
  2126. }
  2127. }
  2128. function unbindKeyboardEvents() {
  2129. if (options.keyboard) {
  2130. modalElement.off('keyup', $modal.$onKeyUp);
  2131. }
  2132. }
  2133. function hideOnBackdropClick(evt) {
  2134. if (evt.target !== evt.currentTarget) return;
  2135. options.backdrop === 'static' ? $modal.focus() : $modal.hide();
  2136. }
  2137. function preventEventDefault(evt) {
  2138. evt.preventDefault();
  2139. }
  2140. function destroyModalElement() {
  2141. if ($modal.$isShown && modalElement !== null) {
  2142. unbindBackdropEvents();
  2143. unbindKeyboardEvents();
  2144. }
  2145. if (modalScope) {
  2146. modalScope.$destroy();
  2147. modalScope = null;
  2148. }
  2149. if (modalElement) {
  2150. modalElement.remove();
  2151. modalElement = $modal.$element = null;
  2152. }
  2153. }
  2154. return $modal;
  2155. }
  2156. function safeDigest(scope) {
  2157. scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
  2158. }
  2159. function findElement(query, element) {
  2160. return angular.element((element || document).querySelectorAll(query));
  2161. }
  2162. return ModalFactory;
  2163. } ];
  2164. }).directive('bsModal', [ '$window', '$sce', '$modal', function($window, $sce, $modal) {
  2165. return {
  2166. restrict: 'EAC',
  2167. scope: true,
  2168. link: function postLink(scope, element, attr, transclusion) {
  2169. var options = {
  2170. scope: scope,
  2171. element: element,
  2172. show: false
  2173. };
  2174. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', 'id', 'prefixEvent', 'prefixClass' ], function(key) {
  2175. if (angular.isDefined(attr[key])) options[key] = attr[key];
  2176. });
  2177. var falseValueRegExp = /^(false|0|)$/i;
  2178. angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) {
  2179. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  2180. });
  2181. angular.forEach([ 'title', 'content' ], function(key) {
  2182. attr[key] && attr.$observe(key, function(newValue, oldValue) {
  2183. scope[key] = $sce.trustAsHtml(newValue);
  2184. });
  2185. });
  2186. attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {
  2187. if (angular.isObject(newValue)) {
  2188. angular.extend(scope, newValue);
  2189. } else {
  2190. scope.content = newValue;
  2191. }
  2192. }, true);
  2193. var modal = $modal(options);
  2194. element.on(attr.trigger || 'click', modal.toggle);
  2195. scope.$on('$destroy', function() {
  2196. if (modal) modal.destroy();
  2197. options = null;
  2198. modal = null;
  2199. });
  2200. }
  2201. };
  2202. } ]);
  2203. angular.version.minor < 3 && angular.version.dot < 14 && angular.module('ng').factory('$$rAF', [ '$window', '$timeout', function($window, $timeout) {
  2204. var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame;
  2205. var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame;
  2206. var rafSupported = !!requestAnimationFrame;
  2207. var raf = rafSupported ? function(fn) {
  2208. var id = requestAnimationFrame(fn);
  2209. return function() {
  2210. cancelAnimationFrame(id);
  2211. };
  2212. } : function(fn) {
  2213. var timer = $timeout(fn, 16.66, false);
  2214. return function() {
  2215. $timeout.cancel(timer);
  2216. };
  2217. };
  2218. raf.supported = rafSupported;
  2219. return raf;
  2220. } ]);
  2221. angular.module('mgcrea.ngStrap.helpers.parseOptions', []).provider('$parseOptions', function() {
  2222. var defaults = this.defaults = {
  2223. regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/
  2224. };
  2225. this.$get = [ '$parse', '$q', function($parse, $q) {
  2226. function ParseOptionsFactory(attr, config) {
  2227. var $parseOptions = {};
  2228. var options = angular.extend({}, defaults, config);
  2229. $parseOptions.$values = [];
  2230. var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;
  2231. $parseOptions.init = function() {
  2232. $parseOptions.$match = match = attr.match(options.regexp);
  2233. displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5],
  2234. groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName),
  2235. valuesFn = $parse(match[7]);
  2236. };
  2237. $parseOptions.valuesFn = function(scope, controller) {
  2238. return $q.when(valuesFn(scope, controller)).then(function(values) {
  2239. if (!angular.isArray(values)) {
  2240. values = [];
  2241. }
  2242. $parseOptions.$values = values.length ? parseValues(values, scope) : [];
  2243. return $parseOptions.$values;
  2244. });
  2245. };
  2246. $parseOptions.displayValue = function(modelValue) {
  2247. var scope = {};
  2248. scope[valueName] = modelValue;
  2249. return displayFn(scope);
  2250. };
  2251. function parseValues(values, scope) {
  2252. return values.map(function(match, index) {
  2253. var locals = {}, label, value;
  2254. locals[valueName] = match;
  2255. label = displayFn(scope, locals);
  2256. value = valueFn(scope, locals);
  2257. return {
  2258. label: label,
  2259. value: value,
  2260. index: index
  2261. };
  2262. });
  2263. }
  2264. $parseOptions.init();
  2265. return $parseOptions;
  2266. }
  2267. return ParseOptionsFactory;
  2268. } ];
  2269. });
  2270. angular.module('mgcrea.ngStrap.helpers.dimensions', []).factory('dimensions', [ '$document', '$window', function($document, $window) {
  2271. var jqLite = angular.element;
  2272. var fn = {};
  2273. var nodeName = fn.nodeName = function(element, name) {
  2274. return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
  2275. };
  2276. fn.css = function(element, prop, extra) {
  2277. var value;
  2278. if (element.currentStyle) {
  2279. value = element.currentStyle[prop];
  2280. } else if (window.getComputedStyle) {
  2281. value = window.getComputedStyle(element)[prop];
  2282. } else {
  2283. value = element.style[prop];
  2284. }
  2285. return extra === true ? parseFloat(value) || 0 : value;
  2286. };
  2287. fn.offset = function(element) {
  2288. var boxRect = element.getBoundingClientRect();
  2289. var docElement = element.ownerDocument;
  2290. return {
  2291. width: boxRect.width || element.offsetWidth,
  2292. height: boxRect.height || element.offsetHeight,
  2293. top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),
  2294. left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)
  2295. };
  2296. };
  2297. fn.setOffset = function(element, options, i) {
  2298. var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = fn.css(element, 'position'), curElem = angular.element(element), props = {};
  2299. if (position === 'static') {
  2300. element.style.position = 'relative';
  2301. }
  2302. curOffset = fn.offset(element);
  2303. curCSSTop = fn.css(element, 'top');
  2304. curCSSLeft = fn.css(element, 'left');
  2305. calculatePosition = (position === 'absolute' || position === 'fixed') && (curCSSTop + curCSSLeft).indexOf('auto') > -1;
  2306. if (calculatePosition) {
  2307. curPosition = fn.position(element);
  2308. curTop = curPosition.top;
  2309. curLeft = curPosition.left;
  2310. } else {
  2311. curTop = parseFloat(curCSSTop) || 0;
  2312. curLeft = parseFloat(curCSSLeft) || 0;
  2313. }
  2314. if (angular.isFunction(options)) {
  2315. options = options.call(element, i, curOffset);
  2316. }
  2317. if (options.top !== null) {
  2318. props.top = options.top - curOffset.top + curTop;
  2319. }
  2320. if (options.left !== null) {
  2321. props.left = options.left - curOffset.left + curLeft;
  2322. }
  2323. if ('using' in options) {
  2324. options.using.call(curElem, props);
  2325. } else {
  2326. curElem.css({
  2327. top: props.top + 'px',
  2328. left: props.left + 'px'
  2329. });
  2330. }
  2331. };
  2332. fn.position = function(element) {
  2333. var offsetParentRect = {
  2334. top: 0,
  2335. left: 0
  2336. }, offsetParentElement, offset;
  2337. if (fn.css(element, 'position') === 'fixed') {
  2338. offset = element.getBoundingClientRect();
  2339. } else {
  2340. offsetParentElement = offsetParent(element);
  2341. offset = fn.offset(element);
  2342. if (!nodeName(offsetParentElement, 'html')) {
  2343. offsetParentRect = fn.offset(offsetParentElement);
  2344. }
  2345. offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);
  2346. offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);
  2347. }
  2348. return {
  2349. width: element.offsetWidth,
  2350. height: element.offsetHeight,
  2351. top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),
  2352. left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)
  2353. };
  2354. };
  2355. var offsetParent = function offsetParentElement(element) {
  2356. var docElement = element.ownerDocument;
  2357. var offsetParent = element.offsetParent || docElement;
  2358. if (nodeName(offsetParent, '#document')) return docElement.documentElement;
  2359. while (offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
  2360. offsetParent = offsetParent.offsetParent;
  2361. }
  2362. return offsetParent || docElement.documentElement;
  2363. };
  2364. fn.height = function(element, outer) {
  2365. var value = element.offsetHeight;
  2366. if (outer) {
  2367. value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);
  2368. } else {
  2369. value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);
  2370. }
  2371. return value;
  2372. };
  2373. fn.width = function(element, outer) {
  2374. var value = element.offsetWidth;
  2375. if (outer) {
  2376. value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);
  2377. } else {
  2378. value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);
  2379. }
  2380. return value;
  2381. };
  2382. return fn;
  2383. } ]);
  2384. angular.module('mgcrea.ngStrap.helpers.debounce', []).factory('debounce', [ '$timeout', function($timeout) {
  2385. return function(func, wait, immediate) {
  2386. var timeout = null;
  2387. return function() {
  2388. var context = this, args = arguments, callNow = immediate && !timeout;
  2389. if (timeout) {
  2390. $timeout.cancel(timeout);
  2391. }
  2392. timeout = $timeout(function later() {
  2393. timeout = null;
  2394. if (!immediate) {
  2395. func.apply(context, args);
  2396. }
  2397. }, wait, false);
  2398. if (callNow) {
  2399. func.apply(context, args);
  2400. }
  2401. return timeout;
  2402. };
  2403. };
  2404. } ]).factory('throttle', [ '$timeout', function($timeout) {
  2405. return function(func, wait, options) {
  2406. var timeout = null;
  2407. options || (options = {});
  2408. return function() {
  2409. var context = this, args = arguments;
  2410. if (!timeout) {
  2411. if (options.leading !== false) {
  2412. func.apply(context, args);
  2413. }
  2414. timeout = $timeout(function later() {
  2415. timeout = null;
  2416. if (options.trailing !== false) {
  2417. func.apply(context, args);
  2418. }
  2419. }, wait, false);
  2420. }
  2421. };
  2422. };
  2423. } ]);
  2424. angular.module('mgcrea.ngStrap.helpers.dateParser', []).provider('$dateParser', [ '$localeProvider', function($localeProvider) {
  2425. function ParseDate() {
  2426. this.year = 1970;
  2427. this.month = 0;
  2428. this.day = 1;
  2429. this.hours = 0;
  2430. this.minutes = 0;
  2431. this.seconds = 0;
  2432. this.milliseconds = 0;
  2433. }
  2434. ParseDate.prototype.setMilliseconds = function(value) {
  2435. this.milliseconds = value;
  2436. };
  2437. ParseDate.prototype.setSeconds = function(value) {
  2438. this.seconds = value;
  2439. };
  2440. ParseDate.prototype.setMinutes = function(value) {
  2441. this.minutes = value;
  2442. };
  2443. ParseDate.prototype.setHours = function(value) {
  2444. this.hours = value;
  2445. };
  2446. ParseDate.prototype.getHours = function() {
  2447. return this.hours;
  2448. };
  2449. ParseDate.prototype.setDate = function(value) {
  2450. this.day = value;
  2451. };
  2452. ParseDate.prototype.setMonth = function(value) {
  2453. this.month = value;
  2454. };
  2455. ParseDate.prototype.setFullYear = function(value) {
  2456. this.year = value;
  2457. };
  2458. ParseDate.prototype.fromDate = function(value) {
  2459. this.year = value.getFullYear();
  2460. this.month = value.getMonth();
  2461. this.day = value.getDate();
  2462. this.hours = value.getHours();
  2463. this.minutes = value.getMinutes();
  2464. this.seconds = value.getSeconds();
  2465. this.milliseconds = value.getMilliseconds();
  2466. return this;
  2467. };
  2468. ParseDate.prototype.toDate = function() {
  2469. return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);
  2470. };
  2471. var proto = ParseDate.prototype;
  2472. function noop() {}
  2473. function isNumeric(n) {
  2474. return !isNaN(parseFloat(n)) && isFinite(n);
  2475. }
  2476. function indexOfCaseInsensitive(array, value) {
  2477. var len = array.length, str = value.toString().toLowerCase();
  2478. for (var i = 0; i < len; i++) {
  2479. if (array[i].toLowerCase() === str) {
  2480. return i;
  2481. }
  2482. }
  2483. return -1;
  2484. }
  2485. var defaults = this.defaults = {
  2486. format: 'shortDate',
  2487. strict: false
  2488. };
  2489. this.$get = [ '$locale', 'dateFilter', function($locale, dateFilter) {
  2490. var DateParserFactory = function(config) {
  2491. var options = angular.extend({}, defaults, config);
  2492. var $dateParser = {};
  2493. var regExpMap = {
  2494. sss: '[0-9]{3}',
  2495. ss: '[0-5][0-9]',
  2496. s: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]',
  2497. mm: '[0-5][0-9]',
  2498. m: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]',
  2499. HH: '[01][0-9]|2[0-3]',
  2500. H: options.strict ? '1?[0-9]|2[0-3]' : '[01]?[0-9]|2[0-3]',
  2501. hh: '[0][1-9]|[1][012]',
  2502. h: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]',
  2503. a: 'AM|PM',
  2504. EEEE: $locale.DATETIME_FORMATS.DAY.join('|'),
  2505. EEE: $locale.DATETIME_FORMATS.SHORTDAY.join('|'),
  2506. dd: '0[1-9]|[12][0-9]|3[01]',
  2507. d: options.strict ? '[1-9]|[1-2][0-9]|3[01]' : '0?[1-9]|[1-2][0-9]|3[01]',
  2508. MMMM: $locale.DATETIME_FORMATS.MONTH.join('|'),
  2509. MMM: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
  2510. MM: '0[1-9]|1[012]',
  2511. M: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]',
  2512. yyyy: '[1]{1}[0-9]{3}|[2]{1}[0-9]{3}',
  2513. yy: '[0-9]{2}',
  2514. y: options.strict ? '-?(0|[1-9][0-9]{0,3})' : '-?0*[0-9]{1,4}'
  2515. };
  2516. var setFnMap = {
  2517. sss: proto.setMilliseconds,
  2518. ss: proto.setSeconds,
  2519. s: proto.setSeconds,
  2520. mm: proto.setMinutes,
  2521. m: proto.setMinutes,
  2522. HH: proto.setHours,
  2523. H: proto.setHours,
  2524. hh: proto.setHours,
  2525. h: proto.setHours,
  2526. EEEE: noop,
  2527. EEE: noop,
  2528. dd: proto.setDate,
  2529. d: proto.setDate,
  2530. a: function(value) {
  2531. var hours = this.getHours() % 12;
  2532. return this.setHours(value.match(/pm/i) ? hours + 12 : hours);
  2533. },
  2534. MMMM: function(value) {
  2535. return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.MONTH, value));
  2536. },
  2537. MMM: function(value) {
  2538. return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.SHORTMONTH, value));
  2539. },
  2540. MM: function(value) {
  2541. return this.setMonth(1 * value - 1);
  2542. },
  2543. M: function(value) {
  2544. return this.setMonth(1 * value - 1);
  2545. },
  2546. yyyy: proto.setFullYear,
  2547. yy: function(value) {
  2548. return this.setFullYear(2e3 + 1 * value);
  2549. },
  2550. y: function(value) {
  2551. return 1 * value <= 50 && value.length === 2 ? this.setFullYear(2e3 + 1 * value) : this.setFullYear(1 * value);
  2552. }
  2553. };
  2554. var regex, setMap;
  2555. $dateParser.init = function() {
  2556. $dateParser.$format = $locale.DATETIME_FORMATS[options.format] || options.format;
  2557. regex = regExpForFormat($dateParser.$format);
  2558. setMap = setMapForFormat($dateParser.$format);
  2559. };
  2560. $dateParser.isValid = function(date) {
  2561. if (angular.isDate(date)) return !isNaN(date.getTime());
  2562. return regex.test(date);
  2563. };
  2564. $dateParser.parse = function(value, baseDate, format, timezone) {
  2565. if (format) format = $locale.DATETIME_FORMATS[format] || format;
  2566. if (angular.isDate(value)) value = dateFilter(value, format || $dateParser.$format, timezone);
  2567. var formatRegex = format ? regExpForFormat(format) : regex;
  2568. var formatSetMap = format ? setMapForFormat(format) : setMap;
  2569. var matches = formatRegex.exec(value);
  2570. if (!matches) return false;
  2571. var date = baseDate && !isNaN(baseDate.getTime()) ? new ParseDate().fromDate(baseDate) : new ParseDate().fromDate(new Date(1970, 0, 1, 0));
  2572. for (var i = 0; i < matches.length - 1; i++) {
  2573. formatSetMap[i] && formatSetMap[i].call(date, matches[i + 1]);
  2574. }
  2575. var newDate = date.toDate();
  2576. if (parseInt(date.day, 10) !== newDate.getDate()) {
  2577. return false;
  2578. }
  2579. return newDate;
  2580. };
  2581. $dateParser.getDateForAttribute = function(key, value) {
  2582. var date;
  2583. if (value === 'today') {
  2584. var today = new Date();
  2585. date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + (key === 'maxDate' ? 1 : 0), 0, 0, 0, key === 'minDate' ? 0 : -1);
  2586. } else if (angular.isString(value) && value.match(/^".+"$/)) {
  2587. date = new Date(value.substr(1, value.length - 2));
  2588. } else if (isNumeric(value)) {
  2589. date = new Date(parseInt(value, 10));
  2590. } else if (angular.isString(value) && 0 === value.length) {
  2591. date = key === 'minDate' ? -Infinity : +Infinity;
  2592. } else {
  2593. date = new Date(value);
  2594. }
  2595. return date;
  2596. };
  2597. $dateParser.getTimeForAttribute = function(key, value) {
  2598. var time;
  2599. if (value === 'now') {
  2600. time = new Date().setFullYear(1970, 0, 1);
  2601. } else if (angular.isString(value) && value.match(/^".+"$/)) {
  2602. time = new Date(value.substr(1, value.length - 2)).setFullYear(1970, 0, 1);
  2603. } else if (isNumeric(value)) {
  2604. time = new Date(parseInt(value, 10)).setFullYear(1970, 0, 1);
  2605. } else if (angular.isString(value) && 0 === value.length) {
  2606. time = key === 'minTime' ? -Infinity : +Infinity;
  2607. } else {
  2608. time = $dateParser.parse(value, new Date(1970, 0, 1, 0));
  2609. }
  2610. return time;
  2611. };
  2612. $dateParser.daylightSavingAdjust = function(date) {
  2613. if (!date) {
  2614. return null;
  2615. }
  2616. date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
  2617. return date;
  2618. };
  2619. $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {
  2620. if (!date) {
  2621. return null;
  2622. }
  2623. if (timezone && timezone === 'UTC') {
  2624. date = new Date(date.getTime());
  2625. date.setMinutes(date.getMinutes() + (undo ? -1 : 1) * date.getTimezoneOffset());
  2626. }
  2627. return date;
  2628. };
  2629. function setMapForFormat(format) {
  2630. var keys = Object.keys(setFnMap), i;
  2631. var map = [], sortedMap = [];
  2632. var clonedFormat = format;
  2633. for (i = 0; i < keys.length; i++) {
  2634. if (format.split(keys[i]).length > 1) {
  2635. var index = clonedFormat.search(keys[i]);
  2636. format = format.split(keys[i]).join('');
  2637. if (setFnMap[keys[i]]) {
  2638. map[index] = setFnMap[keys[i]];
  2639. }
  2640. }
  2641. }
  2642. angular.forEach(map, function(v) {
  2643. if (v) sortedMap.push(v);
  2644. });
  2645. return sortedMap;
  2646. }
  2647. function escapeReservedSymbols(text) {
  2648. return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]');
  2649. }
  2650. function regExpForFormat(format) {
  2651. var keys = Object.keys(regExpMap), i;
  2652. var re = format;
  2653. for (i = 0; i < keys.length; i++) {
  2654. re = re.split(keys[i]).join('${' + i + '}');
  2655. }
  2656. for (i = 0; i < keys.length; i++) {
  2657. re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');
  2658. }
  2659. format = escapeReservedSymbols(format);
  2660. return new RegExp('^' + re + '$', [ 'i' ]);
  2661. }
  2662. $dateParser.init();
  2663. return $dateParser;
  2664. };
  2665. return DateParserFactory;
  2666. } ];
  2667. } ]);
  2668. angular.module('mgcrea.ngStrap.helpers.dateFormatter', []).service('$dateFormatter', [ '$locale', 'dateFilter', function($locale, dateFilter) {
  2669. this.getDefaultLocale = function() {
  2670. return $locale.id;
  2671. };
  2672. this.getDatetimeFormat = function(format, lang) {
  2673. return $locale.DATETIME_FORMATS[format] || format;
  2674. };
  2675. this.weekdaysShort = function(lang) {
  2676. return $locale.DATETIME_FORMATS.SHORTDAY;
  2677. };
  2678. function splitTimeFormat(format) {
  2679. return /(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);
  2680. }
  2681. this.hoursFormat = function(timeFormat) {
  2682. return splitTimeFormat(timeFormat)[0];
  2683. };
  2684. this.minutesFormat = function(timeFormat) {
  2685. return splitTimeFormat(timeFormat)[2];
  2686. };
  2687. this.secondsFormat = function(timeFormat) {
  2688. return splitTimeFormat(timeFormat)[4];
  2689. };
  2690. this.timeSeparator = function(timeFormat) {
  2691. return splitTimeFormat(timeFormat)[1];
  2692. };
  2693. this.showSeconds = function(timeFormat) {
  2694. return !!splitTimeFormat(timeFormat)[4];
  2695. };
  2696. this.showAM = function(timeFormat) {
  2697. return !!splitTimeFormat(timeFormat)[5];
  2698. };
  2699. this.formatDate = function(date, format, lang, timezone) {
  2700. return dateFilter(date, format, timezone);
  2701. };
  2702. } ]);
  2703. angular.module('mgcrea.ngStrap.core', []).service('$bsCompiler', bsCompilerService);
  2704. function bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {
  2705. this.compile = function(options) {
  2706. if (options.template && /\.html$/.test(options.template)) {
  2707. console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');
  2708. options.templateUrl = options.template;
  2709. options.template = '';
  2710. }
  2711. var templateUrl = options.templateUrl;
  2712. var template = options.template || '';
  2713. var controller = options.controller;
  2714. var controllerAs = options.controllerAs;
  2715. var resolve = angular.copy(options.resolve || {});
  2716. var locals = angular.copy(options.locals || {});
  2717. var transformTemplate = options.transformTemplate || angular.identity;
  2718. var bindToController = options.bindToController;
  2719. angular.forEach(resolve, function(value, key) {
  2720. if (angular.isString(value)) {
  2721. resolve[key] = $injector.get(value);
  2722. } else {
  2723. resolve[key] = $injector.invoke(value);
  2724. }
  2725. });
  2726. angular.extend(resolve, locals);
  2727. if (template) {
  2728. resolve.$template = $q.when(template);
  2729. } else if (templateUrl) {
  2730. resolve.$template = fetchTemplate(templateUrl);
  2731. } else {
  2732. throw new Error('Missing `template` / `templateUrl` option.');
  2733. }
  2734. if (options.contentTemplate) {
  2735. resolve.$template = $q.all([ resolve.$template, fetchTemplate(options.contentTemplate) ]).then(function(templates) {
  2736. var templateEl = angular.element(templates[0]);
  2737. var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);
  2738. if (!options.templateUrl) contentEl.next().remove();
  2739. return templateEl[0].outerHTML;
  2740. });
  2741. }
  2742. return $q.all(resolve).then(function(locals) {
  2743. var template = transformTemplate(locals.$template);
  2744. if (options.html) {
  2745. template = template.replace(/ng-bind="/gi, 'ng-bind-html="');
  2746. }
  2747. var element = angular.element('<div>').html(template.trim()).contents();
  2748. var linkFn = $compile(element);
  2749. return {
  2750. locals: locals,
  2751. element: element,
  2752. link: function link(scope) {
  2753. locals.$scope = scope;
  2754. if (controller) {
  2755. var invokeCtrl = $controller(controller, locals, true);
  2756. if (bindToController) {
  2757. angular.extend(invokeCtrl.instance, locals);
  2758. }
  2759. var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();
  2760. element.data('$ngControllerController', ctrl);
  2761. element.children().data('$ngControllerController', ctrl);
  2762. if (controllerAs) {
  2763. scope[controllerAs] = ctrl;
  2764. }
  2765. }
  2766. return linkFn.apply(null, arguments);
  2767. }
  2768. };
  2769. });
  2770. };
  2771. function findElement(query, element) {
  2772. return angular.element((element || document).querySelectorAll(query));
  2773. }
  2774. var fetchPromises = {};
  2775. function fetchTemplate(template) {
  2776. if (fetchPromises[template]) return fetchPromises[template];
  2777. return fetchPromises[template] = $http.get(template, {
  2778. cache: $templateCache
  2779. }).then(function(res) {
  2780. return res.data;
  2781. });
  2782. }
  2783. }
  2784. bsCompilerService.$inject = [ '$q', '$http', '$injector', '$compile', '$controller', '$templateCache' ];
  2785. angular.module('mgcrea.ngStrap.dropdown', [ 'mgcrea.ngStrap.tooltip' ]).provider('$dropdown', function() {
  2786. var defaults = this.defaults = {
  2787. animation: 'am-fade',
  2788. prefixClass: 'dropdown',
  2789. prefixEvent: 'dropdown',
  2790. placement: 'bottom-left',
  2791. templateUrl: 'dropdown/dropdown.tpl.html',
  2792. trigger: 'click',
  2793. container: false,
  2794. keyboard: true,
  2795. html: false,
  2796. delay: 0
  2797. };
  2798. this.$get = [ '$window', '$rootScope', '$tooltip', '$timeout', function($window, $rootScope, $tooltip, $timeout) {
  2799. var bodyEl = angular.element($window.document.body);
  2800. var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;
  2801. function DropdownFactory(element, config) {
  2802. var $dropdown = {};
  2803. var options = angular.extend({}, defaults, config);
  2804. var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();
  2805. $dropdown = $tooltip(element, options);
  2806. var parentEl = element.parent();
  2807. $dropdown.$onKeyDown = function(evt) {
  2808. if (!/(38|40)/.test(evt.keyCode)) return;
  2809. evt.preventDefault();
  2810. evt.stopPropagation();
  2811. var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));
  2812. if (!items.length) return;
  2813. var index;
  2814. angular.forEach(items, function(el, i) {
  2815. if (matchesSelector && matchesSelector.call(el, ':focus')) index = i;
  2816. });
  2817. if (evt.keyCode === 38 && index > 0) index--; else if (evt.keyCode === 40 && index < items.length - 1) index++; else if (angular.isUndefined(index)) index = 0;
  2818. items.eq(index)[0].focus();
  2819. };
  2820. var show = $dropdown.show;
  2821. $dropdown.show = function() {
  2822. show();
  2823. $timeout(function() {
  2824. options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);
  2825. bodyEl.on('click', onBodyClick);
  2826. }, 0, false);
  2827. parentEl.hasClass('dropdown') && parentEl.addClass('open');
  2828. };
  2829. var hide = $dropdown.hide;
  2830. $dropdown.hide = function() {
  2831. if (!$dropdown.$isShown) return;
  2832. options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);
  2833. bodyEl.off('click', onBodyClick);
  2834. parentEl.hasClass('dropdown') && parentEl.removeClass('open');
  2835. hide();
  2836. };
  2837. var destroy = $dropdown.destroy;
  2838. $dropdown.destroy = function() {
  2839. bodyEl.off('click', onBodyClick);
  2840. destroy();
  2841. };
  2842. function onBodyClick(evt) {
  2843. if (evt.target === element[0]) return;
  2844. return evt.target !== element[0] && $dropdown.hide();
  2845. }
  2846. return $dropdown;
  2847. }
  2848. return DropdownFactory;
  2849. } ];
  2850. }).directive('bsDropdown', [ '$window', '$sce', '$dropdown', function($window, $sce, $dropdown) {
  2851. return {
  2852. restrict: 'EAC',
  2853. scope: true,
  2854. compile: function(tElement, tAttrs) {
  2855. var options = {};
  2856. if (!tAttrs.bsDropdown) {
  2857. var nextSibling = tElement[0].nextSibling;
  2858. while (nextSibling && nextSibling.nodeType !== 1) {
  2859. nextSibling = nextSibling.nextSibling;
  2860. }
  2861. if (nextSibling.classList.contains('dropdown-menu')) {
  2862. options.template = nextSibling.outerHTML;
  2863. options.templateUrl = undefined;
  2864. nextSibling.parentNode.removeChild(nextSibling);
  2865. }
  2866. }
  2867. return function postLink(scope, element, attr) {
  2868. options.scope = scope;
  2869. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id' ], function(key) {
  2870. if (angular.isDefined(tAttrs[key])) options[key] = tAttrs[key];
  2871. });
  2872. var falseValueRegExp = /^(false|0|)$/i;
  2873. angular.forEach([ 'html', 'container' ], function(key) {
  2874. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  2875. });
  2876. attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {
  2877. scope.content = newValue;
  2878. }, true);
  2879. attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
  2880. if (!dropdown || !angular.isDefined(newValue)) return;
  2881. if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);
  2882. newValue === true ? dropdown.show() : dropdown.hide();
  2883. });
  2884. var dropdown = $dropdown(element, options);
  2885. scope.$on('$destroy', function() {
  2886. if (dropdown) dropdown.destroy();
  2887. options = null;
  2888. dropdown = null;
  2889. });
  2890. };
  2891. }
  2892. };
  2893. } ]);
  2894. angular.module('mgcrea.ngStrap.datepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$datepicker', function() {
  2895. var defaults = this.defaults = {
  2896. animation: 'am-fade',
  2897. prefixClass: 'datepicker',
  2898. placement: 'bottom-left',
  2899. templateUrl: 'datepicker/datepicker.tpl.html',
  2900. trigger: 'focus',
  2901. container: false,
  2902. keyboard: true,
  2903. html: false,
  2904. delay: 0,
  2905. useNative: false,
  2906. dateType: 'date',
  2907. dateFormat: 'shortDate',
  2908. timezone: null,
  2909. modelDateFormat: null,
  2910. dayFormat: 'dd',
  2911. monthFormat: 'MMM',
  2912. yearFormat: 'yyyy',
  2913. monthTitleFormat: 'MMMM yyyy',
  2914. yearTitleFormat: 'yyyy',
  2915. strictFormat: false,
  2916. autoclose: false,
  2917. minDate: -Infinity,
  2918. maxDate: +Infinity,
  2919. startView: 0,
  2920. minView: 0,
  2921. startWeek: 0,
  2922. daysOfWeekDisabled: '',
  2923. iconLeft: 'glyphicon glyphicon-chevron-left',
  2924. iconRight: 'glyphicon glyphicon-chevron-right'
  2925. };
  2926. this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', 'datepickerViews', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {
  2927. var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent);
  2928. var isTouch = 'createTouch' in $window.document && isNative;
  2929. if (!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
  2930. function DatepickerFactory(element, controller, config) {
  2931. var $datepicker = $tooltip(element, angular.extend({}, defaults, config));
  2932. var parentScope = config.scope;
  2933. var options = $datepicker.$options;
  2934. var scope = $datepicker.$scope;
  2935. if (options.startView) options.startView -= options.minView;
  2936. var pickerViews = datepickerViews($datepicker);
  2937. $datepicker.$views = pickerViews.views;
  2938. var viewDate = pickerViews.viewDate;
  2939. scope.$mode = options.startView;
  2940. scope.$iconLeft = options.iconLeft;
  2941. scope.$iconRight = options.iconRight;
  2942. var $picker = $datepicker.$views[scope.$mode];
  2943. scope.$select = function(date) {
  2944. $datepicker.select(date);
  2945. };
  2946. scope.$selectPane = function(value) {
  2947. $datepicker.$selectPane(value);
  2948. };
  2949. scope.$toggleMode = function() {
  2950. $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);
  2951. };
  2952. $datepicker.update = function(date) {
  2953. if (angular.isDate(date) && !isNaN(date.getTime())) {
  2954. $datepicker.$date = date;
  2955. $picker.update.call($picker, date);
  2956. }
  2957. $datepicker.$build(true);
  2958. };
  2959. $datepicker.updateDisabledDates = function(dateRanges) {
  2960. options.disabledDateRanges = dateRanges;
  2961. for (var i = 0, l = scope.rows.length; i < l; i++) {
  2962. angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);
  2963. }
  2964. };
  2965. $datepicker.select = function(date, keep) {
  2966. if (!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);
  2967. if (!scope.$mode || keep) {
  2968. controller.$setViewValue(angular.copy(date));
  2969. controller.$render();
  2970. if (options.autoclose && !keep) {
  2971. $timeout(function() {
  2972. $datepicker.hide(true);
  2973. });
  2974. }
  2975. } else {
  2976. angular.extend(viewDate, {
  2977. year: date.getFullYear(),
  2978. month: date.getMonth(),
  2979. date: date.getDate()
  2980. });
  2981. $datepicker.setMode(scope.$mode - 1);
  2982. $datepicker.$build();
  2983. }
  2984. };
  2985. $datepicker.setMode = function(mode) {
  2986. scope.$mode = mode;
  2987. $picker = $datepicker.$views[scope.$mode];
  2988. $datepicker.$build();
  2989. };
  2990. $datepicker.$build = function(pristine) {
  2991. if (pristine === true && $picker.built) return;
  2992. if (pristine === false && !$picker.built) return;
  2993. $picker.build.call($picker);
  2994. };
  2995. $datepicker.$updateSelected = function() {
  2996. for (var i = 0, l = scope.rows.length; i < l; i++) {
  2997. angular.forEach(scope.rows[i], updateSelected);
  2998. }
  2999. };
  3000. $datepicker.$isSelected = function(date) {
  3001. return $picker.isSelected(date);
  3002. };
  3003. $datepicker.$setDisabledEl = function(el) {
  3004. el.disabled = $picker.isDisabled(el.date);
  3005. };
  3006. $datepicker.$selectPane = function(value) {
  3007. var steps = $picker.steps;
  3008. var targetDate = new Date(Date.UTC(viewDate.year + (steps.year || 0) * value, viewDate.month + (steps.month || 0) * value, 1));
  3009. angular.extend(viewDate, {
  3010. year: targetDate.getUTCFullYear(),
  3011. month: targetDate.getUTCMonth(),
  3012. date: targetDate.getUTCDate()
  3013. });
  3014. $datepicker.$build();
  3015. };
  3016. $datepicker.$onMouseDown = function(evt) {
  3017. evt.preventDefault();
  3018. evt.stopPropagation();
  3019. if (isTouch) {
  3020. var targetEl = angular.element(evt.target);
  3021. if (targetEl[0].nodeName.toLowerCase() !== 'button') {
  3022. targetEl = targetEl.parent();
  3023. }
  3024. targetEl.triggerHandler('click');
  3025. }
  3026. };
  3027. $datepicker.$onKeyDown = function(evt) {
  3028. if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
  3029. evt.preventDefault();
  3030. evt.stopPropagation();
  3031. if (evt.keyCode === 13) {
  3032. if (!scope.$mode) {
  3033. $datepicker.hide(true);
  3034. } else {
  3035. scope.$apply(function() {
  3036. $datepicker.setMode(scope.$mode - 1);
  3037. });
  3038. }
  3039. return;
  3040. }
  3041. $picker.onKeyDown(evt);
  3042. parentScope.$digest();
  3043. };
  3044. function updateSelected(el) {
  3045. el.selected = $datepicker.$isSelected(el.date);
  3046. }
  3047. function focusElement() {
  3048. element[0].focus();
  3049. }
  3050. var _init = $datepicker.init;
  3051. $datepicker.init = function() {
  3052. if (isNative && options.useNative) {
  3053. element.prop('type', 'date');
  3054. element.css('-webkit-appearance', 'textfield');
  3055. return;
  3056. } else if (isTouch) {
  3057. element.prop('type', 'text');
  3058. element.attr('readonly', 'true');
  3059. element.on('click', focusElement);
  3060. }
  3061. _init();
  3062. };
  3063. var _destroy = $datepicker.destroy;
  3064. $datepicker.destroy = function() {
  3065. if (isNative && options.useNative) {
  3066. element.off('click', focusElement);
  3067. }
  3068. _destroy();
  3069. };
  3070. var _show = $datepicker.show;
  3071. $datepicker.show = function() {
  3072. if (!isTouch && element.attr('readonly') || element.attr('disabled')) return;
  3073. _show();
  3074. $timeout(function() {
  3075. if (!$datepicker.$isShown) return;
  3076. $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
  3077. if (options.keyboard) {
  3078. element.on('keydown', $datepicker.$onKeyDown);
  3079. }
  3080. }, 0, false);
  3081. };
  3082. var _hide = $datepicker.hide;
  3083. $datepicker.hide = function(blur) {
  3084. if (!$datepicker.$isShown) return;
  3085. $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
  3086. if (options.keyboard) {
  3087. element.off('keydown', $datepicker.$onKeyDown);
  3088. }
  3089. _hide(blur);
  3090. };
  3091. return $datepicker;
  3092. }
  3093. DatepickerFactory.defaults = defaults;
  3094. return DatepickerFactory;
  3095. } ];
  3096. }).directive('bsDatepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$datepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {
  3097. var defaults = $datepicker.defaults;
  3098. var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent);
  3099. return {
  3100. restrict: 'EAC',
  3101. require: 'ngModel',
  3102. link: function postLink(scope, element, attr, controller) {
  3103. var options = {
  3104. scope: scope
  3105. };
  3106. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
  3107. if (angular.isDefined(attr[key])) options[key] = attr[key];
  3108. });
  3109. var falseValueRegExp = /^(false|0|)$/i;
  3110. angular.forEach([ 'html', 'container', 'autoclose', 'useNative' ], function(key) {
  3111. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
  3112. options[key] = false;
  3113. }
  3114. });
  3115. var datepicker = $datepicker(element, controller, options);
  3116. options = datepicker.$options;
  3117. if (isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';
  3118. var lang = options.lang;
  3119. var formatDate = function(date, format) {
  3120. return $dateFormatter.formatDate(date, format, lang);
  3121. };
  3122. var dateParser = $dateParser({
  3123. format: options.dateFormat,
  3124. lang: lang,
  3125. strict: options.strictFormat
  3126. });
  3127. attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
  3128. if (!datepicker || !angular.isDefined(newValue)) return;
  3129. if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);
  3130. newValue === true ? datepicker.show() : datepicker.hide();
  3131. });
  3132. angular.forEach([ 'minDate', 'maxDate' ], function(key) {
  3133. angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
  3134. datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);
  3135. !isNaN(datepicker.$options[key]) && datepicker.$build(false);
  3136. validateAgainstMinMaxDate(controller.$dateValue);
  3137. });
  3138. });
  3139. angular.isDefined(attr.dateFormat) && attr.$observe('dateFormat', function(newValue) {
  3140. datepicker.$options.dateFormat = newValue;
  3141. });
  3142. scope.$watch(attr.ngModel, function(newValue, oldValue) {
  3143. datepicker.update(controller.$dateValue);
  3144. }, true);
  3145. function normalizeDateRanges(ranges) {
  3146. if (!ranges || !ranges.length) return null;
  3147. return ranges;
  3148. }
  3149. if (angular.isDefined(attr.disabledDates)) {
  3150. scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {
  3151. disabledRanges = normalizeDateRanges(disabledRanges);
  3152. previousValue = normalizeDateRanges(previousValue);
  3153. if (disabledRanges) {
  3154. datepicker.updateDisabledDates(disabledRanges);
  3155. }
  3156. });
  3157. }
  3158. function validateAgainstMinMaxDate(parsedDate) {
  3159. if (!angular.isDate(parsedDate)) return;
  3160. var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;
  3161. var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;
  3162. var isValid = isMinValid && isMaxValid;
  3163. controller.$setValidity('date', isValid);
  3164. controller.$setValidity('min', isMinValid);
  3165. controller.$setValidity('max', isMaxValid);
  3166. if (isValid) controller.$dateValue = parsedDate;
  3167. }
  3168. controller.$parsers.unshift(function(viewValue) {
  3169. var date;
  3170. if (!viewValue) {
  3171. controller.$setValidity('date', true);
  3172. return null;
  3173. }
  3174. var parsedDate = dateParser.parse(viewValue, controller.$dateValue);
  3175. if (!parsedDate || isNaN(parsedDate.getTime())) {
  3176. controller.$setValidity('date', false);
  3177. return;
  3178. } else {
  3179. validateAgainstMinMaxDate(parsedDate);
  3180. }
  3181. if (options.dateType === 'string') {
  3182. date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);
  3183. return formatDate(date, options.modelDateFormat || options.dateFormat);
  3184. }
  3185. date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);
  3186. if (options.dateType === 'number') {
  3187. return date.getTime();
  3188. } else if (options.dateType === 'unix') {
  3189. return date.getTime() / 1e3;
  3190. } else if (options.dateType === 'iso') {
  3191. return date.toISOString();
  3192. } else {
  3193. return new Date(date);
  3194. }
  3195. });
  3196. controller.$formatters.push(function(modelValue) {
  3197. var date;
  3198. if (angular.isUndefined(modelValue) || modelValue === null) {
  3199. date = NaN;
  3200. } else if (angular.isDate(modelValue)) {
  3201. date = modelValue;
  3202. } else if (options.dateType === 'string') {
  3203. date = dateParser.parse(modelValue, null, options.modelDateFormat);
  3204. } else if (options.dateType === 'unix') {
  3205. date = new Date(modelValue * 1e3);
  3206. } else {
  3207. date = new Date(modelValue);
  3208. }
  3209. controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);
  3210. return getDateFormattedString();
  3211. });
  3212. controller.$render = function() {
  3213. element.val(getDateFormattedString());
  3214. };
  3215. function getDateFormattedString() {
  3216. return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);
  3217. }
  3218. scope.$on('$destroy', function() {
  3219. if (datepicker) datepicker.destroy();
  3220. options = null;
  3221. datepicker = null;
  3222. });
  3223. }
  3224. };
  3225. } ]).provider('datepickerViews', function() {
  3226. var defaults = this.defaults = {
  3227. dayFormat: 'dd',
  3228. daySplit: 7
  3229. };
  3230. function split(arr, size) {
  3231. var arrays = [];
  3232. while (arr.length > 0) {
  3233. arrays.push(arr.splice(0, size));
  3234. }
  3235. return arrays;
  3236. }
  3237. function mod(n, m) {
  3238. return (n % m + m) % m;
  3239. }
  3240. this.$get = [ '$dateFormatter', '$dateParser', '$sce', function($dateFormatter, $dateParser, $sce) {
  3241. return function(picker) {
  3242. var scope = picker.$scope;
  3243. var options = picker.$options;
  3244. var lang = options.lang;
  3245. var formatDate = function(date, format) {
  3246. return $dateFormatter.formatDate(date, format, lang);
  3247. };
  3248. var dateParser = $dateParser({
  3249. format: options.dateFormat,
  3250. lang: lang,
  3251. strict: options.strictFormat
  3252. });
  3253. var weekDaysMin = $dateFormatter.weekdaysShort(lang);
  3254. var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));
  3255. var weekDaysLabelsHtml = $sce.trustAsHtml('<th class="dow text-center">' + weekDaysLabels.join('</th><th class="dow text-center">') + '</th>');
  3256. var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());
  3257. var viewDate = {
  3258. year: startDate.getFullYear(),
  3259. month: startDate.getMonth(),
  3260. date: startDate.getDate()
  3261. };
  3262. var views = [ {
  3263. format: options.dayFormat,
  3264. split: 7,
  3265. steps: {
  3266. month: 1
  3267. },
  3268. update: function(date, force) {
  3269. if (!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {
  3270. angular.extend(viewDate, {
  3271. year: picker.$date.getFullYear(),
  3272. month: picker.$date.getMonth(),
  3273. date: picker.$date.getDate()
  3274. });
  3275. picker.$build();
  3276. } else if (date.getDate() !== viewDate.date || date.getDate() === 1) {
  3277. viewDate.date = picker.$date.getDate();
  3278. picker.$updateSelected();
  3279. }
  3280. },
  3281. build: function() {
  3282. var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();
  3283. var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();
  3284. var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();
  3285. if (firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 6e4);
  3286. var days = [], day;
  3287. for (var i = 0; i < 42; i++) {
  3288. day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));
  3289. days.push({
  3290. date: day,
  3291. isToday: day.toDateString() === today,
  3292. label: formatDate(day, this.format),
  3293. selected: picker.$date && this.isSelected(day),
  3294. muted: day.getMonth() !== viewDate.month,
  3295. disabled: this.isDisabled(day)
  3296. });
  3297. }
  3298. scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);
  3299. scope.showLabels = true;
  3300. scope.labels = weekDaysLabelsHtml;
  3301. scope.rows = split(days, this.split);
  3302. this.built = true;
  3303. },
  3304. isSelected: function(date) {
  3305. return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();
  3306. },
  3307. isDisabled: function(date) {
  3308. var time = date.getTime();
  3309. if (time < options.minDate || time > options.maxDate) return true;
  3310. if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;
  3311. if (options.disabledDateRanges) {
  3312. for (var i = 0; i < options.disabledDateRanges.length; i++) {
  3313. if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {
  3314. return true;
  3315. }
  3316. }
  3317. }
  3318. return false;
  3319. },
  3320. onKeyDown: function(evt) {
  3321. if (!picker.$date) {
  3322. return;
  3323. }
  3324. var actualTime = picker.$date.getTime();
  3325. var newDate;
  3326. if (evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); else if (evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); else if (evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); else if (evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);
  3327. if (!this.isDisabled(newDate)) picker.select(newDate, true);
  3328. }
  3329. }, {
  3330. name: 'month',
  3331. format: options.monthFormat,
  3332. split: 4,
  3333. steps: {
  3334. year: 1
  3335. },
  3336. update: function(date, force) {
  3337. if (!this.built || date.getFullYear() !== viewDate.year) {
  3338. angular.extend(viewDate, {
  3339. year: picker.$date.getFullYear(),
  3340. month: picker.$date.getMonth(),
  3341. date: picker.$date.getDate()
  3342. });
  3343. picker.$build();
  3344. } else if (date.getMonth() !== viewDate.month) {
  3345. angular.extend(viewDate, {
  3346. month: picker.$date.getMonth(),
  3347. date: picker.$date.getDate()
  3348. });
  3349. picker.$updateSelected();
  3350. }
  3351. },
  3352. build: function() {
  3353. var firstMonth = new Date(viewDate.year, 0, 1);
  3354. var months = [], month;
  3355. for (var i = 0; i < 12; i++) {
  3356. month = new Date(viewDate.year, i, 1);
  3357. months.push({
  3358. date: month,
  3359. label: formatDate(month, this.format),
  3360. selected: picker.$isSelected(month),
  3361. disabled: this.isDisabled(month)
  3362. });
  3363. }
  3364. scope.title = formatDate(month, options.yearTitleFormat);
  3365. scope.showLabels = false;
  3366. scope.rows = split(months, this.split);
  3367. this.built = true;
  3368. },
  3369. isSelected: function(date) {
  3370. return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();
  3371. },
  3372. isDisabled: function(date) {
  3373. var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);
  3374. return lastDate < options.minDate || date.getTime() > options.maxDate;
  3375. },
  3376. onKeyDown: function(evt) {
  3377. if (!picker.$date) {
  3378. return;
  3379. }
  3380. var actualMonth = picker.$date.getMonth();
  3381. var newDate = new Date(picker.$date);
  3382. if (evt.keyCode === 37) newDate.setMonth(actualMonth - 1); else if (evt.keyCode === 38) newDate.setMonth(actualMonth - 4); else if (evt.keyCode === 39) newDate.setMonth(actualMonth + 1); else if (evt.keyCode === 40) newDate.setMonth(actualMonth + 4);
  3383. if (!this.isDisabled(newDate)) picker.select(newDate, true);
  3384. }
  3385. }, {
  3386. name: 'year',
  3387. format: options.yearFormat,
  3388. split: 4,
  3389. steps: {
  3390. year: 12
  3391. },
  3392. update: function(date, force) {
  3393. if (!this.built || force || parseInt(date.getFullYear() / 20, 10) !== parseInt(viewDate.year / 20, 10)) {
  3394. angular.extend(viewDate, {
  3395. year: picker.$date.getFullYear(),
  3396. month: picker.$date.getMonth(),
  3397. date: picker.$date.getDate()
  3398. });
  3399. picker.$build();
  3400. } else if (date.getFullYear() !== viewDate.year) {
  3401. angular.extend(viewDate, {
  3402. year: picker.$date.getFullYear(),
  3403. month: picker.$date.getMonth(),
  3404. date: picker.$date.getDate()
  3405. });
  3406. picker.$updateSelected();
  3407. }
  3408. },
  3409. build: function() {
  3410. var firstYear = viewDate.year - viewDate.year % (this.split * 3);
  3411. var years = [], year;
  3412. for (var i = 0; i < 12; i++) {
  3413. year = new Date(firstYear + i, 0, 1);
  3414. years.push({
  3415. date: year,
  3416. label: formatDate(year, this.format),
  3417. selected: picker.$isSelected(year),
  3418. disabled: this.isDisabled(year)
  3419. });
  3420. }
  3421. scope.title = years[0].label + '-' + years[years.length - 1].label;
  3422. scope.showLabels = false;
  3423. scope.rows = split(years, this.split);
  3424. this.built = true;
  3425. },
  3426. isSelected: function(date) {
  3427. return picker.$date && date.getFullYear() === picker.$date.getFullYear();
  3428. },
  3429. isDisabled: function(date) {
  3430. var lastDate = +new Date(date.getFullYear() + 1, 0, 0);
  3431. return lastDate < options.minDate || date.getTime() > options.maxDate;
  3432. },
  3433. onKeyDown: function(evt) {
  3434. if (!picker.$date) {
  3435. return;
  3436. }
  3437. var actualYear = picker.$date.getFullYear(), newDate = new Date(picker.$date);
  3438. if (evt.keyCode === 37) newDate.setYear(actualYear - 1); else if (evt.keyCode === 38) newDate.setYear(actualYear - 4); else if (evt.keyCode === 39) newDate.setYear(actualYear + 1); else if (evt.keyCode === 40) newDate.setYear(actualYear + 4);
  3439. if (!this.isDisabled(newDate)) picker.select(newDate, true);
  3440. }
  3441. } ];
  3442. return {
  3443. views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,
  3444. viewDate: viewDate
  3445. };
  3446. };
  3447. } ];
  3448. });
  3449. angular.module('mgcrea.ngStrap.collapse', []).provider('$collapse', function() {
  3450. var defaults = this.defaults = {
  3451. animation: 'am-collapse',
  3452. disallowToggle: false,
  3453. activeClass: 'in',
  3454. startCollapsed: false,
  3455. allowMultiple: false
  3456. };
  3457. var controller = this.controller = function($scope, $element, $attrs) {
  3458. var self = this;
  3459. self.$options = angular.copy(defaults);
  3460. angular.forEach([ 'animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple' ], function(key) {
  3461. if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
  3462. });
  3463. var falseValueRegExp = /^(false|0|)$/i;
  3464. angular.forEach([ 'disallowToggle', 'startCollapsed', 'allowMultiple' ], function(key) {
  3465. if (angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {
  3466. self.$options[key] = false;
  3467. }
  3468. });
  3469. self.$toggles = [];
  3470. self.$targets = [];
  3471. self.$viewChangeListeners = [];
  3472. self.$registerToggle = function(element) {
  3473. self.$toggles.push(element);
  3474. };
  3475. self.$registerTarget = function(element) {
  3476. self.$targets.push(element);
  3477. };
  3478. self.$unregisterToggle = function(element) {
  3479. var index = self.$toggles.indexOf(element);
  3480. self.$toggles.splice(index, 1);
  3481. };
  3482. self.$unregisterTarget = function(element) {
  3483. var index = self.$targets.indexOf(element);
  3484. self.$targets.splice(index, 1);
  3485. if (self.$options.allowMultiple) {
  3486. deactivateItem(element);
  3487. }
  3488. fixActiveItemIndexes(index);
  3489. self.$viewChangeListeners.forEach(function(fn) {
  3490. fn();
  3491. });
  3492. };
  3493. self.$targets.$active = !self.$options.startCollapsed ? [ 0 ] : [];
  3494. self.$setActive = $scope.$setActive = function(value) {
  3495. if (angular.isArray(value)) {
  3496. self.$targets.$active = value;
  3497. } else if (!self.$options.disallowToggle) {
  3498. isActive(value) ? deactivateItem(value) : activateItem(value);
  3499. } else {
  3500. activateItem(value);
  3501. }
  3502. self.$viewChangeListeners.forEach(function(fn) {
  3503. fn();
  3504. });
  3505. };
  3506. self.$activeIndexes = function() {
  3507. return self.$options.allowMultiple ? self.$targets.$active : self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;
  3508. };
  3509. function fixActiveItemIndexes(index) {
  3510. var activeIndexes = self.$targets.$active;
  3511. for (var i = 0; i < activeIndexes.length; i++) {
  3512. if (index < activeIndexes[i]) {
  3513. activeIndexes[i] = activeIndexes[i] - 1;
  3514. }
  3515. if (activeIndexes[i] === self.$targets.length) {
  3516. activeIndexes[i] = self.$targets.length - 1;
  3517. }
  3518. }
  3519. }
  3520. function isActive(value) {
  3521. var activeItems = self.$targets.$active;
  3522. return activeItems.indexOf(value) === -1 ? false : true;
  3523. }
  3524. function deactivateItem(value) {
  3525. var index = self.$targets.$active.indexOf(value);
  3526. if (index !== -1) {
  3527. self.$targets.$active.splice(index, 1);
  3528. }
  3529. }
  3530. function activateItem(value) {
  3531. if (!self.$options.allowMultiple) {
  3532. self.$targets.$active.splice(0, 1);
  3533. }
  3534. if (self.$targets.$active.indexOf(value) === -1) {
  3535. self.$targets.$active.push(value);
  3536. }
  3537. }
  3538. };
  3539. this.$get = function() {
  3540. var $collapse = {};
  3541. $collapse.defaults = defaults;
  3542. $collapse.controller = controller;
  3543. return $collapse;
  3544. };
  3545. }).directive('bsCollapse', [ '$window', '$animate', '$collapse', function($window, $animate, $collapse) {
  3546. var defaults = $collapse.defaults;
  3547. return {
  3548. require: [ '?ngModel', 'bsCollapse' ],
  3549. controller: [ '$scope', '$element', '$attrs', $collapse.controller ],
  3550. link: function postLink(scope, element, attrs, controllers) {
  3551. var ngModelCtrl = controllers[0];
  3552. var bsCollapseCtrl = controllers[1];
  3553. if (ngModelCtrl) {
  3554. bsCollapseCtrl.$viewChangeListeners.push(function() {
  3555. ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());
  3556. });
  3557. ngModelCtrl.$formatters.push(function(modelValue) {
  3558. if (angular.isArray(modelValue)) {
  3559. bsCollapseCtrl.$setActive(modelValue);
  3560. } else {
  3561. var activeIndexes = bsCollapseCtrl.$activeIndexes();
  3562. if (angular.isArray(activeIndexes)) {
  3563. if (activeIndexes.indexOf(modelValue * 1) === -1) {
  3564. bsCollapseCtrl.$setActive(modelValue * 1);
  3565. }
  3566. } else if (activeIndexes !== modelValue * 1) {
  3567. bsCollapseCtrl.$setActive(modelValue * 1);
  3568. }
  3569. }
  3570. return modelValue;
  3571. });
  3572. }
  3573. }
  3574. };
  3575. } ]).directive('bsCollapseToggle', function() {
  3576. return {
  3577. require: [ '^?ngModel', '^bsCollapse' ],
  3578. link: function postLink(scope, element, attrs, controllers) {
  3579. var ngModelCtrl = controllers[0];
  3580. var bsCollapseCtrl = controllers[1];
  3581. element.attr('data-toggle', 'collapse');
  3582. bsCollapseCtrl.$registerToggle(element);
  3583. scope.$on('$destroy', function() {
  3584. bsCollapseCtrl.$unregisterToggle(element);
  3585. });
  3586. element.on('click', function() {
  3587. var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);
  3588. bsCollapseCtrl.$setActive(index * 1);
  3589. scope.$apply();
  3590. });
  3591. }
  3592. };
  3593. }).directive('bsCollapseTarget', [ '$animate', function($animate) {
  3594. return {
  3595. require: [ '^?ngModel', '^bsCollapse' ],
  3596. link: function postLink(scope, element, attrs, controllers) {
  3597. var ngModelCtrl = controllers[0];
  3598. var bsCollapseCtrl = controllers[1];
  3599. element.addClass('collapse');
  3600. if (bsCollapseCtrl.$options.animation) {
  3601. element.addClass(bsCollapseCtrl.$options.animation);
  3602. }
  3603. bsCollapseCtrl.$registerTarget(element);
  3604. scope.$on('$destroy', function() {
  3605. bsCollapseCtrl.$unregisterTarget(element);
  3606. });
  3607. function render() {
  3608. var index = bsCollapseCtrl.$targets.indexOf(element);
  3609. var active = bsCollapseCtrl.$activeIndexes();
  3610. var action = 'removeClass';
  3611. if (angular.isArray(active)) {
  3612. if (active.indexOf(index) !== -1) {
  3613. action = 'addClass';
  3614. }
  3615. } else if (index === active) {
  3616. action = 'addClass';
  3617. }
  3618. $animate[action](element, bsCollapseCtrl.$options.activeClass);
  3619. }
  3620. bsCollapseCtrl.$viewChangeListeners.push(function() {
  3621. render();
  3622. });
  3623. render();
  3624. }
  3625. };
  3626. } ]);
  3627. angular.module('mgcrea.ngStrap.button', []).provider('$button', function() {
  3628. var defaults = this.defaults = {
  3629. activeClass: 'active',
  3630. toggleEvent: 'click'
  3631. };
  3632. this.$get = function() {
  3633. return {
  3634. defaults: defaults
  3635. };
  3636. };
  3637. }).directive('bsCheckboxGroup', function() {
  3638. return {
  3639. restrict: 'A',
  3640. require: 'ngModel',
  3641. compile: function postLink(element, attr) {
  3642. element.attr('data-toggle', 'buttons');
  3643. element.removeAttr('ng-model');
  3644. var children = element[0].querySelectorAll('input[type="checkbox"]');
  3645. angular.forEach(children, function(child) {
  3646. var childEl = angular.element(child);
  3647. childEl.attr('bs-checkbox', '');
  3648. childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));
  3649. });
  3650. }
  3651. };
  3652. }).directive('bsCheckbox', [ '$button', '$$rAF', function($button, $$rAF) {
  3653. var defaults = $button.defaults;
  3654. var constantValueRegExp = /^(true|false|\d+)$/;
  3655. return {
  3656. restrict: 'A',
  3657. require: 'ngModel',
  3658. link: function postLink(scope, element, attr, controller) {
  3659. var options = defaults;
  3660. var isInput = element[0].nodeName === 'INPUT';
  3661. var activeElement = isInput ? element.parent() : element;
  3662. var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;
  3663. if (constantValueRegExp.test(attr.trueValue)) {
  3664. trueValue = scope.$eval(attr.trueValue);
  3665. }
  3666. var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;
  3667. if (constantValueRegExp.test(attr.falseValue)) {
  3668. falseValue = scope.$eval(attr.falseValue);
  3669. }
  3670. var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';
  3671. if (hasExoticValues) {
  3672. controller.$parsers.push(function(viewValue) {
  3673. return viewValue ? trueValue : falseValue;
  3674. });
  3675. controller.$formatters.push(function(modelValue) {
  3676. return angular.equals(modelValue, trueValue);
  3677. });
  3678. scope.$watch(attr.ngModel, function(newValue, oldValue) {
  3679. controller.$render();
  3680. });
  3681. }
  3682. controller.$render = function() {
  3683. var isActive = angular.equals(controller.$modelValue, trueValue);
  3684. $$rAF(function() {
  3685. if (isInput) element[0].checked = isActive;
  3686. activeElement.toggleClass(options.activeClass, isActive);
  3687. });
  3688. };
  3689. element.bind(options.toggleEvent, function() {
  3690. scope.$apply(function() {
  3691. if (!isInput) {
  3692. controller.$setViewValue(!activeElement.hasClass('active'));
  3693. }
  3694. if (!hasExoticValues) {
  3695. controller.$render();
  3696. }
  3697. });
  3698. });
  3699. }
  3700. };
  3701. } ]).directive('bsRadioGroup', function() {
  3702. return {
  3703. restrict: 'A',
  3704. require: 'ngModel',
  3705. compile: function postLink(element, attr) {
  3706. element.attr('data-toggle', 'buttons');
  3707. element.removeAttr('ng-model');
  3708. var children = element[0].querySelectorAll('input[type="radio"]');
  3709. angular.forEach(children, function(child) {
  3710. angular.element(child).attr('bs-radio', '');
  3711. angular.element(child).attr('ng-model', attr.ngModel);
  3712. });
  3713. }
  3714. };
  3715. }).directive('bsRadio', [ '$button', '$$rAF', function($button, $$rAF) {
  3716. var defaults = $button.defaults;
  3717. var constantValueRegExp = /^(true|false|\d+)$/;
  3718. return {
  3719. restrict: 'A',
  3720. require: 'ngModel',
  3721. link: function postLink(scope, element, attr, controller) {
  3722. var options = defaults;
  3723. var isInput = element[0].nodeName === 'INPUT';
  3724. var activeElement = isInput ? element.parent() : element;
  3725. var value;
  3726. attr.$observe('value', function(v) {
  3727. value = constantValueRegExp.test(v) ? scope.$eval(v) : v;
  3728. controller.$render();
  3729. });
  3730. controller.$render = function() {
  3731. var isActive = angular.equals(controller.$modelValue, value);
  3732. $$rAF(function() {
  3733. if (isInput) element[0].checked = isActive;
  3734. activeElement.toggleClass(options.activeClass, isActive);
  3735. });
  3736. };
  3737. element.bind(options.toggleEvent, function() {
  3738. scope.$apply(function() {
  3739. controller.$setViewValue(value);
  3740. controller.$render();
  3741. });
  3742. });
  3743. }
  3744. };
  3745. } ]);
  3746. angular.module('mgcrea.ngStrap.aside', [ 'mgcrea.ngStrap.modal' ]).provider('$aside', function() {
  3747. var defaults = this.defaults = {
  3748. animation: 'am-fade-and-slide-right',
  3749. prefixClass: 'aside',
  3750. prefixEvent: 'aside',
  3751. placement: 'right',
  3752. templateUrl: 'aside/aside.tpl.html',
  3753. contentTemplate: false,
  3754. container: false,
  3755. element: null,
  3756. backdrop: true,
  3757. keyboard: true,
  3758. html: false,
  3759. show: true
  3760. };
  3761. this.$get = [ '$modal', function($modal) {
  3762. function AsideFactory(config) {
  3763. var $aside = {};
  3764. var options = angular.extend({}, defaults, config);
  3765. $aside = $modal(options);
  3766. return $aside;
  3767. }
  3768. return AsideFactory;
  3769. } ];
  3770. }).directive('bsAside', [ '$window', '$sce', '$aside', function($window, $sce, $aside) {
  3771. var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
  3772. return {
  3773. restrict: 'EAC',
  3774. scope: true,
  3775. link: function postLink(scope, element, attr, transclusion) {
  3776. var options = {
  3777. scope: scope,
  3778. element: element,
  3779. show: false
  3780. };
  3781. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation' ], function(key) {
  3782. if (angular.isDefined(attr[key])) options[key] = attr[key];
  3783. });
  3784. var falseValueRegExp = /^(false|0|)$/i;
  3785. angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) {
  3786. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  3787. });
  3788. angular.forEach([ 'title', 'content' ], function(key) {
  3789. attr[key] && attr.$observe(key, function(newValue, oldValue) {
  3790. scope[key] = $sce.trustAsHtml(newValue);
  3791. });
  3792. });
  3793. attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {
  3794. if (angular.isObject(newValue)) {
  3795. angular.extend(scope, newValue);
  3796. } else {
  3797. scope.content = newValue;
  3798. }
  3799. }, true);
  3800. var aside = $aside(options);
  3801. element.on(attr.trigger || 'click', aside.toggle);
  3802. scope.$on('$destroy', function() {
  3803. if (aside) aside.destroy();
  3804. options = null;
  3805. aside = null;
  3806. });
  3807. }
  3808. };
  3809. } ]);
  3810. angular.module('mgcrea.ngStrap.alert', [ 'mgcrea.ngStrap.modal' ]).provider('$alert', function() {
  3811. var defaults = this.defaults = {
  3812. animation: 'am-fade',
  3813. prefixClass: 'alert',
  3814. prefixEvent: 'alert',
  3815. placement: null,
  3816. templateUrl: 'alert/alert.tpl.html',
  3817. container: false,
  3818. element: null,
  3819. backdrop: false,
  3820. keyboard: true,
  3821. show: true,
  3822. duration: false,
  3823. type: false,
  3824. dismissable: true
  3825. };
  3826. this.$get = [ '$modal', '$timeout', function($modal, $timeout) {
  3827. function AlertFactory(config) {
  3828. var $alert = {};
  3829. var options = angular.extend({}, defaults, config);
  3830. $alert = $modal(options);
  3831. $alert.$scope.dismissable = !!options.dismissable;
  3832. if (options.type) {
  3833. $alert.$scope.type = options.type;
  3834. }
  3835. var show = $alert.show;
  3836. if (options.duration) {
  3837. $alert.show = function() {
  3838. show();
  3839. $timeout(function() {
  3840. $alert.hide();
  3841. }, options.duration * 1e3);
  3842. };
  3843. }
  3844. return $alert;
  3845. }
  3846. return AlertFactory;
  3847. } ];
  3848. }).directive('bsAlert', [ '$window', '$sce', '$alert', function($window, $sce, $alert) {
  3849. var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
  3850. return {
  3851. restrict: 'EAC',
  3852. scope: true,
  3853. link: function postLink(scope, element, attr, transclusion) {
  3854. var options = {
  3855. scope: scope,
  3856. element: element,
  3857. show: false
  3858. };
  3859. angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable' ], function(key) {
  3860. if (angular.isDefined(attr[key])) options[key] = attr[key];
  3861. });
  3862. var falseValueRegExp = /^(false|0|)$/i;
  3863. angular.forEach([ 'keyboard', 'html', 'container', 'dismissable' ], function(key) {
  3864. if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
  3865. });
  3866. if (!scope.hasOwnProperty('title')) {
  3867. scope.title = '';
  3868. }
  3869. angular.forEach([ 'title', 'content', 'type' ], function(key) {
  3870. attr[key] && attr.$observe(key, function(newValue, oldValue) {
  3871. scope[key] = $sce.trustAsHtml(newValue);
  3872. });
  3873. });
  3874. attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {
  3875. if (angular.isObject(newValue)) {
  3876. angular.extend(scope, newValue);
  3877. } else {
  3878. scope.content = newValue;
  3879. }
  3880. }, true);
  3881. var alert = $alert(options);
  3882. element.on(attr.trigger || 'click', alert.toggle);
  3883. scope.$on('$destroy', function() {
  3884. if (alert) alert.destroy();
  3885. options = null;
  3886. alert = null;
  3887. });
  3888. }
  3889. };
  3890. } ]);
  3891. angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce' ]).provider('$affix', function() {
  3892. var defaults = this.defaults = {
  3893. offsetTop: 'auto',
  3894. inlineStyles: true
  3895. };
  3896. this.$get = [ '$window', 'debounce', 'dimensions', function($window, debounce, dimensions) {
  3897. var bodyEl = angular.element($window.document.body);
  3898. var windowEl = angular.element($window);
  3899. function AffixFactory(element, config) {
  3900. var $affix = {};
  3901. var options = angular.extend({}, defaults, config);
  3902. var targetEl = options.target;
  3903. var reset = 'affix affix-top affix-bottom', setWidth = false, initialAffixTop = 0, initialOffsetTop = 0, offsetTop = 0, offsetBottom = 0, affixed = null, unpin = null;
  3904. var parent = element.parent();
  3905. if (options.offsetParent) {
  3906. if (options.offsetParent.match(/^\d+$/)) {
  3907. for (var i = 0; i < options.offsetParent * 1 - 1; i++) {
  3908. parent = parent.parent();
  3909. }
  3910. } else {
  3911. parent = angular.element(options.offsetParent);
  3912. }
  3913. }
  3914. $affix.init = function() {
  3915. this.$parseOffsets();
  3916. initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;
  3917. setWidth = !element[0].style.width;
  3918. targetEl.on('scroll', this.checkPosition);
  3919. targetEl.on('click', this.checkPositionWithEventLoop);
  3920. windowEl.on('resize', this.$debouncedOnResize);
  3921. this.checkPosition();
  3922. this.checkPositionWithEventLoop();
  3923. };
  3924. $affix.destroy = function() {
  3925. targetEl.off('scroll', this.checkPosition);
  3926. targetEl.off('click', this.checkPositionWithEventLoop);
  3927. windowEl.off('resize', this.$debouncedOnResize);
  3928. };
  3929. $affix.checkPositionWithEventLoop = function() {
  3930. setTimeout($affix.checkPosition, 1);
  3931. };
  3932. $affix.checkPosition = function() {
  3933. var scrollTop = getScrollTop();
  3934. var position = dimensions.offset(element[0]);
  3935. var elementHeight = dimensions.height(element[0]);
  3936. var affix = getRequiredAffixClass(unpin, position, elementHeight);
  3937. if (affixed === affix) return;
  3938. affixed = affix;
  3939. if (affix === 'top') {
  3940. unpin = null;
  3941. if (setWidth) {
  3942. element.css('width', '');
  3943. }
  3944. if (options.inlineStyles) {
  3945. element.css('position', options.offsetParent ? '' : 'relative');
  3946. element.css('top', '');
  3947. }
  3948. } else if (affix === 'bottom') {
  3949. if (options.offsetUnpin) {
  3950. unpin = -(options.offsetUnpin * 1);
  3951. } else {
  3952. unpin = position.top - scrollTop;
  3953. }
  3954. if (setWidth) {
  3955. element.css('width', '');
  3956. }
  3957. if (options.inlineStyles) {
  3958. element.css('position', options.offsetParent ? '' : 'relative');
  3959. element.css('top', options.offsetParent ? '' : bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px');
  3960. }
  3961. } else {
  3962. unpin = null;
  3963. if (setWidth) {
  3964. element.css('width', element[0].offsetWidth + 'px');
  3965. }
  3966. if (options.inlineStyles) {
  3967. element.css('position', 'fixed');
  3968. element.css('top', initialAffixTop + 'px');
  3969. }
  3970. }
  3971. element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : ''));
  3972. };
  3973. $affix.$onResize = function() {
  3974. $affix.$parseOffsets();
  3975. $affix.checkPosition();
  3976. };
  3977. $affix.$debouncedOnResize = debounce($affix.$onResize, 50);
  3978. $affix.$parseOffsets = function() {
  3979. var initialPosition = element.css('position');
  3980. if (options.inlineStyles) {
  3981. element.css('position', options.offsetParent ? '' : 'relative');
  3982. }
  3983. if (options.offsetTop) {
  3984. if (options.offsetTop === 'auto') {
  3985. options.offsetTop = '+0';
  3986. }
  3987. if (options.offsetTop.match(/^[-+]\d+$/)) {
  3988. initialAffixTop = -options.offsetTop * 1;
  3989. if (options.offsetParent) {
  3990. offsetTop = dimensions.offset(parent[0]).top + options.offsetTop * 1;
  3991. } else {
  3992. offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + options.offsetTop * 1;
  3993. }
  3994. } else {
  3995. offsetTop = options.offsetTop * 1;
  3996. }
  3997. }
  3998. if (options.offsetBottom) {
  3999. if (options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) {
  4000. offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + options.offsetBottom * 1 + 1;
  4001. } else {
  4002. offsetBottom = options.offsetBottom * 1;
  4003. }
  4004. }
  4005. if (options.inlineStyles) {
  4006. element.css('position', initialPosition);
  4007. }
  4008. };
  4009. function getRequiredAffixClass(unpin, position, elementHeight) {
  4010. var scrollTop = getScrollTop();
  4011. var scrollHeight = getScrollHeight();
  4012. if (scrollTop <= offsetTop) {
  4013. return 'top';
  4014. } else if (unpin !== null && scrollTop + unpin <= position.top) {
  4015. return 'middle';
  4016. } else if (offsetBottom !== null && position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom) {
  4017. return 'bottom';
  4018. } else {
  4019. return 'middle';
  4020. }
  4021. }
  4022. function getScrollTop() {
  4023. return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;
  4024. }
  4025. function getScrollHeight() {
  4026. return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;
  4027. }
  4028. $affix.init();
  4029. return $affix;
  4030. }
  4031. return AffixFactory;
  4032. } ];
  4033. }).directive('bsAffix', [ '$affix', '$window', function($affix, $window) {
  4034. return {
  4035. restrict: 'EAC',
  4036. require: '^?bsAffixTarget',
  4037. link: function postLink(scope, element, attr, affixTarget) {
  4038. var options = {
  4039. scope: scope,
  4040. target: affixTarget ? affixTarget.$element : angular.element($window)
  4041. };
  4042. angular.forEach([ 'offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles' ], function(key) {
  4043. if (angular.isDefined(attr[key])) {
  4044. var option = attr[key];
  4045. if (/true/i.test(option)) option = true;
  4046. if (/false/i.test(option)) option = false;
  4047. options[key] = option;
  4048. }
  4049. });
  4050. var affix = $affix(element, options);
  4051. scope.$on('$destroy', function() {
  4052. affix && affix.destroy();
  4053. options = null;
  4054. affix = null;
  4055. });
  4056. }
  4057. };
  4058. } ]).directive('bsAffixTarget', function() {
  4059. return {
  4060. controller: [ '$element', function($element) {
  4061. this.$element = $element;
  4062. } ]
  4063. };
  4064. });
  4065. angular.module('mgcrea.ngStrap', [ 'mgcrea.ngStrap.modal', 'mgcrea.ngStrap.aside', 'mgcrea.ngStrap.alert', 'mgcrea.ngStrap.button', 'mgcrea.ngStrap.select', 'mgcrea.ngStrap.datepicker', 'mgcrea.ngStrap.timepicker', 'mgcrea.ngStrap.navbar', 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.popover', 'mgcrea.ngStrap.dropdown', 'mgcrea.ngStrap.typeahead', 'mgcrea.ngStrap.scrollspy', 'mgcrea.ngStrap.affix', 'mgcrea.ngStrap.tab', 'mgcrea.ngStrap.collapse' ]);
  4066. })(window, document);