angularjs-foundation-rails 0.3.1.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,11 +2,11 @@
2
2
  * angular-mm-foundation
3
3
  * http://pineconellc.github.io/angular-foundation/
4
4
 
5
- * Version: 0.3.1 - 2014-08-19
5
+ * Version: 0.8.0 - 2015-10-13
6
6
  * License: MIT
7
7
  * (c) Pinecone, LLC
8
8
  */
9
- angular.module("mm.foundation", ["mm.foundation.accordion","mm.foundation.alert","mm.foundation.bindHtml","mm.foundation.buttons","mm.foundation.position","mm.foundation.dropdownToggle","mm.foundation.interchange","mm.foundation.transition","mm.foundation.modal","mm.foundation.offcanvas","mm.foundation.pagination","mm.foundation.tooltip","mm.foundation.popover","mm.foundation.progressbar","mm.foundation.rating","mm.foundation.tabs","mm.foundation.topbar","mm.foundation.tour","mm.foundation.typeahead"]);
9
+ angular.module("mm.foundation", ["mm.foundation.accordion","mm.foundation.alert","mm.foundation.bindHtml","mm.foundation.buttons","mm.foundation.position","mm.foundation.mediaQueries","mm.foundation.dropdownToggle","mm.foundation.interchange","mm.foundation.transition","mm.foundation.modal","mm.foundation.offcanvas","mm.foundation.pagination","mm.foundation.tooltip","mm.foundation.popover","mm.foundation.progressbar","mm.foundation.rating","mm.foundation.tabs","mm.foundation.topbar","mm.foundation.tour","mm.foundation.typeahead"]);
10
10
  angular.module('mm.foundation.accordion', [])
11
11
 
12
12
  .constant('accordionConfig', {
@@ -29,7 +29,7 @@ angular.module('mm.foundation.accordion', [])
29
29
  });
30
30
  }
31
31
  };
32
-
32
+
33
33
  // This is called from the accordion-group directive to add itself to the accordion
34
34
  this.addGroup = function(groupScope) {
35
35
  var that = this;
@@ -44,7 +44,7 @@ angular.module('mm.foundation.accordion', [])
44
44
  this.removeGroup = function(group) {
45
45
  var index = this.groups.indexOf(group);
46
46
  if ( index !== -1 ) {
47
- this.groups.splice(this.groups.indexOf(group), 1);
47
+ this.groups.splice(index, 1);
48
48
  }
49
49
  };
50
50
 
@@ -82,7 +82,7 @@ angular.module('mm.foundation.accordion', [])
82
82
  accordionCtrl.addGroup(scope);
83
83
 
84
84
  scope.isOpen = false;
85
-
85
+
86
86
  if ( attrs.isOpen ) {
87
87
  getIsOpen = $parse(attrs.isOpen);
88
88
  setIsOpen = getIsOpen.assign;
@@ -149,7 +149,7 @@ angular.module('mm.foundation.accordion', [])
149
149
  angular.module("mm.foundation.alert", [])
150
150
 
151
151
  .controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) {
152
- $scope.closeable = 'close' in $attrs;
152
+ $scope.closeable = 'close' in $attrs && typeof $attrs.close !== "undefined";
153
153
  }])
154
154
 
155
155
  .directive('alert', function () {
@@ -228,7 +228,7 @@ angular.module('mm.foundation.buttons', [])
228
228
  function getFalseValue() {
229
229
  return getCheckboxValue(attrs.btnCheckboxFalse, false);
230
230
  }
231
-
231
+
232
232
  function getCheckboxValue(attributeValue, defaultValue) {
233
233
  var val = scope.$eval(attributeValue);
234
234
  return angular.isDefined(val) ? val : defaultValue;
@@ -331,6 +331,66 @@ angular.module('mm.foundation.position', [])
331
331
  };
332
332
  }]);
333
333
 
334
+ angular.module("mm.foundation.mediaQueries", [])
335
+ .factory('matchMedia', ['$document', '$window', function($document, $window) {
336
+ // MatchMedia for IE <= 9
337
+ return $window.matchMedia || (function matchMedia(doc, undefined){
338
+ var bool,
339
+ docElem = doc.documentElement,
340
+ refNode = docElem.firstElementChild || docElem.firstChild,
341
+ // fakeBody required for <FF4 when executed in <head>
342
+ fakeBody = doc.createElement("body"),
343
+ div = doc.createElement("div");
344
+
345
+ div.id = "mq-test-1";
346
+ div.style.cssText = "position:absolute;top:-100em";
347
+ fakeBody.style.background = "none";
348
+ fakeBody.appendChild(div);
349
+
350
+ return function (q) {
351
+ div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
352
+ docElem.insertBefore(fakeBody, refNode);
353
+ bool = div.offsetWidth === 42;
354
+ docElem.removeChild(fakeBody);
355
+ return {
356
+ matches: bool,
357
+ media: q
358
+ };
359
+ };
360
+
361
+ }($document[0]));
362
+ }])
363
+ .factory('mediaQueries', ['$document', 'matchMedia', function($document, matchMedia) {
364
+ var head = angular.element($document[0].querySelector('head'));
365
+ head.append('<meta class="foundation-mq-topbar" />');
366
+ head.append('<meta class="foundation-mq-small" />');
367
+ head.append('<meta class="foundation-mq-medium" />');
368
+ head.append('<meta class="foundation-mq-large" />');
369
+
370
+ var regex = /^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g;
371
+ var queries = {
372
+ topbar: getComputedStyle(head[0].querySelector('meta.foundation-mq-topbar')).fontFamily.replace(regex, ''),
373
+ small : getComputedStyle(head[0].querySelector('meta.foundation-mq-small')).fontFamily.replace(regex, ''),
374
+ medium : getComputedStyle(head[0].querySelector('meta.foundation-mq-medium')).fontFamily.replace(regex, ''),
375
+ large : getComputedStyle(head[0].querySelector('meta.foundation-mq-large')).fontFamily.replace(regex, '')
376
+ };
377
+
378
+ return {
379
+ topbarBreakpoint: function () {
380
+ return !matchMedia(queries.topbar).matches;
381
+ },
382
+ small: function () {
383
+ return matchMedia(queries.small).matches;
384
+ },
385
+ medium: function () {
386
+ return matchMedia(queries.medium).matches;
387
+ },
388
+ large: function () {
389
+ return matchMedia(queries.large).matches;
390
+ }
391
+ };
392
+ }]);
393
+
334
394
  /*
335
395
  * dropdownToggle - Provides dropdown menu functionality
336
396
  * @restrict class or attribute
@@ -343,22 +403,30 @@ angular.module('mm.foundation.position', [])
343
403
  </li>
344
404
  </ul>
345
405
  */
346
- angular.module('mm.foundation.dropdownToggle', [ 'mm.foundation.position' ])
406
+ angular.module('mm.foundation.dropdownToggle', [ 'mm.foundation.position', 'mm.foundation.mediaQueries' ])
407
+
408
+ .controller('DropdownToggleController', ['$scope', '$attrs', 'mediaQueries', function($scope, $attrs, mediaQueries) {
409
+ this.small = function() {
410
+ return mediaQueries.small() && !mediaQueries.medium();
411
+ };
412
+ }])
347
413
 
348
- .directive('dropdownToggle', ['$document', '$location', '$position', function ($document, $location, $position) {
414
+ .directive('dropdownToggle', ['$document', '$window', '$location', '$position', function ($document, $window, $location, $position) {
349
415
  var openElement = null,
350
416
  closeMenu = angular.noop;
351
417
  return {
352
418
  restrict: 'CA',
353
- scope: {
354
- dropdownToggle: '@'
355
- },
356
- link: function(scope, element, attrs) {
357
- var dropdown = angular.element($document[0].querySelector(scope.dropdownToggle));
419
+ controller: 'DropdownToggleController',
420
+ link: function(scope, element, attrs, controller) {
421
+ var parent = element.parent(),
422
+ dropdown = angular.element($document[0].querySelector(attrs.dropdownToggle));
358
423
 
359
- scope.$watch('$location.path', function() { closeMenu(); });
360
- element.bind('click', function (event) {
361
- dropdown = angular.element($document[0].querySelector(scope.dropdownToggle));
424
+ var parentHasDropdown = function() {
425
+ return parent.hasClass('has-dropdown');
426
+ };
427
+
428
+ var onClick = function (event) {
429
+ dropdown = angular.element($document[0].querySelector(attrs.dropdownToggle));
362
430
  var elementWasOpen = (element === openElement);
363
431
 
364
432
  event.preventDefault();
@@ -369,30 +437,68 @@ angular.module('mm.foundation.dropdownToggle', [ 'mm.foundation.position' ])
369
437
  }
370
438
 
371
439
  if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
372
- dropdown.css('display', 'block');
440
+ dropdown.css('display', 'block'); // We display the element so that offsetParent is populated
441
+ dropdown.addClass('f-open-dropdown');
373
442
 
374
443
  var offset = $position.offset(element);
375
444
  var parentOffset = $position.offset(angular.element(dropdown[0].offsetParent));
376
-
377
- dropdown.css({
378
- left: offset.left - parentOffset.left + 'px',
445
+ var dropdownWidth = dropdown.prop('offsetWidth');
446
+ var css = {
379
447
  top: offset.top - parentOffset.top + offset.height + 'px'
380
- });
448
+ };
449
+
450
+ if (controller.small()) {
451
+ css.left = Math.max((parentOffset.width - dropdownWidth) / 2, 8) + 'px';
452
+ css.position = 'absolute';
453
+ css.width = '95%';
454
+ css['max-width'] = 'none';
455
+ }
456
+ else {
457
+ var left = Math.round(offset.left - parentOffset.left);
458
+ var rightThreshold = $window.innerWidth - dropdownWidth - 8;
459
+ if (left > rightThreshold) {
460
+ left = rightThreshold;
461
+ dropdown.removeClass('left').addClass('right');
462
+ }
463
+ css.left = left + 'px';
464
+ css.position = null;
465
+ css['max-width'] = null;
466
+ }
467
+
468
+ dropdown.css(css);
469
+ element.addClass('expanded');
470
+
471
+ if (parentHasDropdown()) {
472
+ parent.addClass('hover');
473
+ }
381
474
 
382
475
  openElement = element;
476
+
383
477
  closeMenu = function (event) {
384
- $document.unbind('click', closeMenu);
478
+ $document.off('click', closeMenu);
385
479
  dropdown.css('display', 'none');
480
+ dropdown.removeClass('f-open-dropdown');
481
+ element.removeClass('expanded');
386
482
  closeMenu = angular.noop;
387
483
  openElement = null;
484
+ if (parent.hasClass('hover')) {
485
+ parent.removeClass('hover');
486
+ }
388
487
  };
389
- $document.bind('click', closeMenu);
488
+ $document.on('click', closeMenu);
390
489
  }
391
- });
490
+ };
392
491
 
393
492
  if (dropdown) {
394
493
  dropdown.css('display', 'none');
395
494
  }
495
+
496
+ scope.$watch('$location.path', function() { closeMenu(); });
497
+
498
+ element.on('click', onClick);
499
+ element.on('$destroy', function() {
500
+ element.off('click', onClick);
501
+ });
396
502
  }
397
503
  };
398
504
  }]);
@@ -405,7 +511,7 @@ angular.module('mm.foundation.dropdownToggle', [ 'mm.foundation.position' ])
405
511
  * Package containing all services and directives
406
512
  * about the `interchange` module
407
513
  */
408
- angular.module('mm.foundation.interchange', [])
514
+ angular.module('mm.foundation.interchange', ['mm.foundation.mediaQueries'])
409
515
 
410
516
  /**
411
517
  * @ngdoc function
@@ -491,7 +597,7 @@ angular.module('mm.foundation.interchange', [])
491
597
  *
492
598
  * Tools to help with the `interchange` module.
493
599
  */
494
- .factory('interchangeTools', ['$window', 'interchangeQueries', function ($window, namedQueries) {
600
+ .factory('interchangeTools', ['$window', 'matchMedia', 'interchangeQueries', function ($window, matchMedia, namedQueries) {
495
601
 
496
602
  /**
497
603
  * @ngdoc method
@@ -555,7 +661,7 @@ angular.module('mm.foundation.interchange', [])
555
661
  var file, media, match;
556
662
  for (file in files) {
557
663
  media = namedQueries[file] || file;
558
- match = $window.matchMedia(media);
664
+ match = matchMedia(media);
559
665
  if (match.matches) {
560
666
  return files[file];
561
667
  }
@@ -876,12 +982,12 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
876
982
  };
877
983
  }])
878
984
 
879
- .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
880
- function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) {
985
+ .factory('$modalStack', ['$window', '$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
986
+ function ($window, $transition, $timeout, $document, $compile, $rootScope, $$stackedMap) {
881
987
 
882
988
  var OPENED_MODAL_CLASS = 'modal-open';
883
989
 
884
- var backdropDomEl, backdropScope;
990
+ var backdropDomEl, backdropScope, cssTop;
885
991
  var openedWindows = $$stackedMap.createNew();
886
992
  var $modalStack = {};
887
993
 
@@ -903,16 +1009,18 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
903
1009
  });
904
1010
 
905
1011
  function removeModalWindow(modalInstance) {
906
-
907
- var body = $document.find('body').eq(0);
1012
+ var parent = $document.find(modalInstance.options.parent).eq(0);
908
1013
  var modalWindow = openedWindows.get(modalInstance).value;
909
1014
 
910
1015
  //clean up the stack
911
1016
  openedWindows.remove(modalInstance);
912
1017
 
913
1018
  //remove window DOM element
914
- removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop);
915
- body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
1019
+ removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, function() {
1020
+ modalWindow.modalScope.$destroy();
1021
+ parent.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
1022
+ checkRemoveBackdrop();
1023
+ });
916
1024
  }
917
1025
 
918
1026
  function checkRemoveBackdrop() {
@@ -960,6 +1068,14 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
960
1068
  }
961
1069
  }
962
1070
 
1071
+ function calculateModalTop(modalElement, offset) {
1072
+ if (angular.isUndefined(offset)) {
1073
+ offset = 0;
1074
+ }
1075
+ var scrollY = $window.pageYOffset || 0;
1076
+ return offset + scrollY;
1077
+ }
1078
+
963
1079
  $document.bind('keydown', function (evt) {
964
1080
  var modal;
965
1081
 
@@ -974,48 +1090,68 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
974
1090
  });
975
1091
 
976
1092
  $modalStack.open = function (modalInstance, modal) {
977
-
978
- openedWindows.add(modalInstance, {
1093
+ modalInstance.options = {
979
1094
  deferred: modal.deferred,
980
1095
  modalScope: modal.scope,
981
1096
  backdrop: modal.backdrop,
982
- keyboard: modal.keyboard
983
- });
1097
+ keyboard: modal.keyboard,
1098
+ parent: modal.parent
1099
+ };
1100
+ openedWindows.add(modalInstance, modalInstance.options);
984
1101
 
985
- var body = $document.find('body').eq(0),
1102
+ var parent = $document.find(modal.parent).eq(0),
986
1103
  currBackdropIndex = backdropIndex();
987
1104
 
988
1105
  if (currBackdropIndex >= 0 && !backdropDomEl) {
989
1106
  backdropScope = $rootScope.$new(true);
990
1107
  backdropScope.index = currBackdropIndex;
991
1108
  backdropDomEl = $compile('<div modal-backdrop></div>')(backdropScope);
992
- body.append(backdropDomEl);
1109
+ parent.append(backdropDomEl);
993
1110
  }
994
-
995
- var angularDomEl = angular.element('<div modal-window></div>');
996
- angularDomEl.attr('window-class', modal.windowClass);
997
- angularDomEl.attr('index', openedWindows.length() - 1);
998
- angularDomEl.attr('animate', 'animate');
1111
+
1112
+ // Create a faux modal div just to measure its
1113
+ // distance to top
1114
+ var faux = angular.element('<div class="reveal-modal" style="z-index:-1""></div>');
1115
+ parent.append(faux[0]);
1116
+ cssTop = parseInt($window.getComputedStyle(faux[0]).top) || 0;
1117
+ var openAt = calculateModalTop(faux, cssTop);
1118
+ faux.remove();
1119
+
1120
+ var angularDomEl = angular.element('<div modal-window style="visibility: visible; top:' + openAt +'px;"></div>')
1121
+ .attr({
1122
+ 'window-class': modal.windowClass,
1123
+ 'index': openedWindows.length() - 1,
1124
+ 'animate': 'animate'
1125
+ });
999
1126
  angularDomEl.html(modal.content);
1000
1127
 
1001
1128
  var modalDomEl = $compile(angularDomEl)(modal.scope);
1002
1129
  openedWindows.top().value.modalDomEl = modalDomEl;
1003
- body.append(modalDomEl);
1004
- body.addClass(OPENED_MODAL_CLASS);
1130
+ parent.append(modalDomEl);
1131
+ parent.addClass(OPENED_MODAL_CLASS);
1005
1132
  };
1006
1133
 
1007
- $modalStack.close = function (modalInstance, result) {
1134
+ $modalStack.reposition = function (modalInstance) {
1008
1135
  var modalWindow = openedWindows.get(modalInstance).value;
1009
1136
  if (modalWindow) {
1010
- modalWindow.deferred.resolve(result);
1137
+ var modalDomEl = modalWindow.modalDomEl;
1138
+ var top = calculateModalTop(modalDomEl, cssTop);
1139
+ modalDomEl.css('top', top + "px");
1140
+ }
1141
+ };
1142
+
1143
+ $modalStack.close = function (modalInstance, result) {
1144
+ var modalWindow = openedWindows.get(modalInstance);
1145
+ if (modalWindow) {
1146
+ modalWindow.value.deferred.resolve(result);
1011
1147
  removeModalWindow(modalInstance);
1012
1148
  }
1013
1149
  };
1014
1150
 
1015
1151
  $modalStack.dismiss = function (modalInstance, reason) {
1016
- var modalWindow = openedWindows.get(modalInstance).value;
1152
+ var modalWindow = openedWindows.get(modalInstance);
1017
1153
  if (modalWindow) {
1018
- modalWindow.deferred.reject(reason);
1154
+ modalWindow.value.deferred.reject(reason);
1019
1155
  removeModalWindow(modalInstance);
1020
1156
  }
1021
1157
  };
@@ -1078,6 +1214,9 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
1078
1214
  },
1079
1215
  dismiss: function (reason) {
1080
1216
  $modalStack.dismiss(modalInstance, reason);
1217
+ },
1218
+ reposition: function () {
1219
+ $modalStack.reposition(modalInstance);
1081
1220
  }
1082
1221
  };
1083
1222
 
@@ -1112,6 +1251,9 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
1112
1251
  });
1113
1252
 
1114
1253
  ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
1254
+ if (modalOptions.controllerAs) {
1255
+ modalScope[modalOptions.controllerAs] = ctrlInstance;
1256
+ }
1115
1257
  }
1116
1258
 
1117
1259
  $modalStack.open(modalInstance, {
@@ -1120,7 +1262,8 @@ angular.module('mm.foundation.modal', ['mm.foundation.transition'])
1120
1262
  content: tplAndVars[0],
1121
1263
  backdrop: modalOptions.backdrop,
1122
1264
  keyboard: modalOptions.keyboard,
1123
- windowClass: modalOptions.windowClass
1265
+ windowClass: modalOptions.windowClass,
1266
+ parent: modalOptions.parent || 'body'
1124
1267
  });
1125
1268
 
1126
1269
  }, function resolveError(reason) {
@@ -1495,7 +1638,7 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1495
1638
 
1496
1639
  // The options specified to the provider globally.
1497
1640
  var globalOptions = {};
1498
-
1641
+
1499
1642
  /**
1500
1643
  * `options({})` allows global configuration of all tooltips in the
1501
1644
  * application.
@@ -1505,9 +1648,9 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1505
1648
  * $tooltipProvider.options( { placement: 'left' } );
1506
1649
  * });
1507
1650
  */
1508
- this.options = function( value ) {
1509
- angular.extend( globalOptions, value );
1510
- };
1651
+ this.options = function( value ) {
1652
+ angular.extend( globalOptions, value );
1653
+ };
1511
1654
 
1512
1655
  /**
1513
1656
  * This allows you to extend the set of trigger mappings available. E.g.:
@@ -1564,7 +1707,7 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1564
1707
 
1565
1708
  var startSym = $interpolate.startSymbol();
1566
1709
  var endSym = $interpolate.endSymbol();
1567
- var template =
1710
+ var template =
1568
1711
  '<div '+ directiveName +'-popup '+
1569
1712
  'title="'+startSym+'tt_title'+endSym+'" '+
1570
1713
  'content="'+startSym+'tt_content'+endSym+'" '+
@@ -1689,7 +1832,7 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1689
1832
  // Set the initial positioning.
1690
1833
  tooltip.css({ top: 0, left: 0, display: 'block' });
1691
1834
 
1692
- // Now we add it to the DOM because need some info about it. But it's not
1835
+ // Now we add it to the DOM because need some info about it. But it's not
1693
1836
  // visible yet anyway.
1694
1837
  if ( appendToBody ) {
1695
1838
  $document.find( 'body' ).append( tooltip );
@@ -1716,7 +1859,7 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1716
1859
  //if tooltip is going to be shown after delay, we must cancel this
1717
1860
  $timeout.cancel( popupTimeout );
1718
1861
 
1719
- // And now we remove it from the DOM. However, if we have animation, we
1862
+ // And now we remove it from the DOM. However, if we have animation, we
1720
1863
  // need to wait for it to expire beforehand.
1721
1864
  // FIXME: this is a placeholder for a port of the transitions library.
1722
1865
  if ( scope.tt_animation ) {
@@ -1759,24 +1902,34 @@ angular.module( 'mm.foundation.tooltip', [ 'mm.foundation.position', 'mm.foundat
1759
1902
  scope.tt_title = val;
1760
1903
  });
1761
1904
 
1905
+ attrs[prefix+'Placement'] = attrs[prefix+'Placement'] || null;
1906
+
1762
1907
  attrs.$observe( prefix+'Placement', function ( val ) {
1763
- scope.tt_placement = angular.isDefined( val ) ? val : options.placement;
1908
+ scope.tt_placement = angular.isDefined( val ) && val ? val : options.placement;
1764
1909
  });
1765
1910
 
1911
+ attrs[prefix+'PopupDelay'] = attrs[prefix+'PopupDelay'] || null;
1912
+
1766
1913
  attrs.$observe( prefix+'PopupDelay', function ( val ) {
1767
1914
  var delay = parseInt( val, 10 );
1768
1915
  scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
1769
1916
  });
1770
1917
 
1771
1918
  var unregisterTriggers = function() {
1772
- if (hasRegisteredTriggers) {
1773
- element.unbind( triggers.show, showTooltipBind );
1774
- element.unbind( triggers.hide, hideTooltipBind );
1919
+ if ( hasRegisteredTriggers ) {
1920
+ if ( angular.isFunction( triggers.show ) ) {
1921
+ unregisterTriggerFunction();
1922
+ } else {
1923
+ element.unbind( triggers.show, showTooltipBind );
1924
+ element.unbind( triggers.hide, hideTooltipBind );
1925
+ }
1775
1926
  }
1776
1927
  };
1777
1928
 
1778
1929
  var unregisterTriggerFunction = function () {};
1779
1930
 
1931
+ attrs[prefix+'Trigger'] = attrs[prefix+'Trigger'] || null;
1932
+
1780
1933
  attrs.$observe( prefix+'Trigger', function ( val ) {
1781
1934
  unregisterTriggers();
1782
1935
  unregisterTriggerFunction();
@@ -2069,6 +2222,8 @@ angular.module('mm.foundation.tabs', [])
2069
2222
  var ctrl = this,
2070
2223
  tabs = ctrl.tabs = $scope.tabs = [];
2071
2224
 
2225
+ if (angular.isUndefined($scope.openOnLoad)) { $scope.openOnLoad = true; }
2226
+
2072
2227
  ctrl.select = function(tab) {
2073
2228
  angular.forEach(tabs, function(tab) {
2074
2229
  tab.active = false;
@@ -2078,7 +2233,7 @@ angular.module('mm.foundation.tabs', [])
2078
2233
 
2079
2234
  ctrl.addTab = function addTab(tab) {
2080
2235
  tabs.push(tab);
2081
- if (tabs.length === 1 || tab.active) {
2236
+ if ($scope.openOnLoad && (tabs.length === 1 || tab.active)) {
2082
2237
  ctrl.select(tab);
2083
2238
  }
2084
2239
  };
@@ -2130,7 +2285,9 @@ angular.module('mm.foundation.tabs', [])
2130
2285
  restrict: 'EA',
2131
2286
  transclude: true,
2132
2287
  replace: true,
2133
- scope: {},
2288
+ scope: {
2289
+ openOnLoad: '=?'
2290
+ },
2134
2291
  controller: 'TabsetController',
2135
2292
  templateUrl: 'template/tabs/tabset.html',
2136
2293
  link: function(scope, element, attrs) {
@@ -2257,6 +2414,9 @@ angular.module('mm.foundation.tabs', [])
2257
2414
  }
2258
2415
 
2259
2416
  scope.$watch('active', function(active) {
2417
+ if( !angular.isFunction(setActive) ){
2418
+ return;
2419
+ }
2260
2420
  // Note this watcher also initializes and assigns scope.active to the
2261
2421
  // attrs.active expression.
2262
2422
  setActive(scope.$parent, active);
@@ -2343,508 +2503,462 @@ angular.module('mm.foundation.tabs', [])
2343
2503
 
2344
2504
  ;
2345
2505
 
2506
+ angular.module("mm.foundation.topbar", ['mm.foundation.mediaQueries'])
2507
+ .factory('closest', [function() {
2508
+ return function(el, selector) {
2509
+ var matchesSelector = function (node, selector) {
2510
+ var nodes = (node.parentNode || node.document).querySelectorAll(selector);
2511
+ var i = -1;
2512
+ while (nodes[++i] && nodes[i] != node){}
2513
+ return !!nodes[i];
2514
+ };
2346
2515
 
2347
- angular.module("mm.foundation.topbar", [])
2348
- .factory('mediaQueries', ['$document', '$window', function($document, $window){
2349
- var head = angular.element($document[0].querySelector('head'));
2350
- head.append('<meta class="foundation-mq-topbar" />');
2351
- head.append('<meta class="foundation-mq-small" />');
2352
- head.append('<meta class="foundation-mq-medium" />');
2353
- head.append('<meta class="foundation-mq-large" />');
2516
+ var element = el[0];
2517
+ while (element) {
2518
+ if (matchesSelector(element, selector)) {
2519
+ return angular.element(element);
2520
+ } else {
2521
+ element = element.parentElement;
2522
+ }
2523
+ }
2524
+ return false;
2525
+ };
2526
+ }])
2527
+ .directive('topBar', ['$timeout','$compile', '$window', '$document', 'mediaQueries',
2528
+ function($timeout, $compile, $window, $document, mediaQueries) {
2529
+ return {
2530
+ scope: {
2531
+ stickyClass : '@',
2532
+ backText: '@',
2533
+ stickyOn : '=',
2534
+ customBackText: '=',
2535
+ isHover: '=',
2536
+ mobileShowParentLink: '=',
2537
+ scrolltop : '=',
2538
+ },
2539
+ restrict: 'EA',
2540
+ replace: true,
2541
+ templateUrl: 'template/topbar/top-bar.html',
2542
+ transclude: true,
2543
+ controller: ['$window', '$scope', 'closest', function($window, $scope, closest) {
2544
+ $scope.settings = {};
2545
+ $scope.settings.stickyClass = $scope.stickyClass || 'sticky';
2546
+ $scope.settings.backText = $scope.backText || 'Back';
2547
+ $scope.settings.stickyOn = $scope.stickyOn || 'all';
2354
2548
 
2355
- // MatchMedia for IE <= 9
2356
- var matchMedia = $window.matchMedia || (function(doc, undefined){
2357
- var bool,
2358
- docElem = doc.documentElement,
2359
- refNode = docElem.firstElementChild || docElem.firstChild,
2360
- // fakeBody required for <FF4 when executed in <head>
2361
- fakeBody = doc.createElement("body"),
2362
- div = doc.createElement("div");
2549
+ $scope.settings.customBackText = $scope.customBackText === undefined ? true : $scope.customBackText;
2550
+ $scope.settings.isHover = $scope.isHover === undefined ? true : $scope.isHover;
2551
+ $scope.settings.mobileShowParentLink = $scope.mobileShowParentLink === undefined ? true : $scope.mobileShowParentLink;
2552
+ $scope.settings.scrolltop = $scope.scrolltop === undefined ? true : $scope.scrolltop; // jump to top when sticky nav menu toggle is clicked
2363
2553
 
2364
- div.id = "mq-test-1";
2365
- div.style.cssText = "position:absolute;top:-100em";
2366
- fakeBody.style.background = "none";
2367
- fakeBody.appendChild(div);
2554
+ this.settings = $scope.settings;
2368
2555
 
2369
- return function (q) {
2370
- div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
2371
- docElem.insertBefore(fakeBody, refNode);
2372
- bool = div.offsetWidth === 42;
2373
- docElem.removeChild(fakeBody);
2374
- return {
2375
- matches: bool,
2376
- media: q
2377
- };
2378
- };
2556
+ $scope.index = 0;
2379
2557
 
2380
- }($document[0]));
2558
+ var outerHeight = function(el) {
2559
+ var height = el.offsetHeight;
2560
+ var style = el.currentStyle || getComputedStyle(el);
2381
2561
 
2382
- var regex = /^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g;
2383
- var queries = {
2384
- topbar: getComputedStyle(head[0].querySelector('meta.foundation-mq-topbar')).fontFamily.replace(regex, ''),
2385
- small : getComputedStyle(head[0].querySelector('meta.foundation-mq-small')).fontFamily.replace(regex, ''),
2386
- medium : getComputedStyle(head[0].querySelector('meta.foundation-mq-medium')).fontFamily.replace(regex, ''),
2387
- large : getComputedStyle(head[0].querySelector('meta.foundation-mq-large')).fontFamily.replace(regex, '')
2562
+ height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
2563
+ return height;
2388
2564
  };
2389
2565
 
2390
- return {
2391
- topbarBreakpoint: function () {
2392
- return !matchMedia(queries.topbar).matches;
2393
- },
2394
- small: function () {
2395
- return matchMedia(queries.small).matches;
2396
- },
2397
- medium: function () {
2398
- return matchMedia(queries.medium).matches;
2399
- },
2400
- large: function () {
2401
- return matchMedia(queries.large).matches;
2402
- }
2403
- };
2404
2566
 
2405
- }])
2406
- .factory('closest', [function(){
2407
- return function(el, selector) {
2408
- var matchesSelector = function (node, selector) {
2409
- var nodes = (node.parentNode || node.document).querySelectorAll(selector);
2410
- var i = -1;
2411
- while (nodes[++i] && nodes[i] != node){}
2412
- return !!nodes[i];
2413
- };
2567
+ var sections = [];
2414
2568
 
2415
- var element = el[0];
2416
- while (element) {
2417
- if (matchesSelector(element, selector)) {
2418
- return angular.element(element);
2419
- } else {
2420
- element = element.parentElement;
2421
- }
2422
- }
2423
- return false;
2569
+ this.addSection = function(section) {
2570
+ sections.push(section);
2424
2571
  };
2425
- }])
2426
- .directive('topBar', ['$timeout','$compile', '$window', '$document', 'mediaQueries',
2427
- function ($timeout, $compile, $window, $document, mediaQueries) {
2428
- return {
2429
- scope: {
2430
- stickyClass : '@',
2431
- backText: '@',
2432
- stickyOn : '=',
2433
- customBackText: '=',
2434
- isHover: '=',
2435
- mobileShowParentLink: '=',
2436
- scrolltop : '=',
2437
- },
2438
- restrict: 'EA',
2439
- replace: true,
2440
- templateUrl: 'template/topbar/top-bar.html',
2441
- transclude: true,
2442
- link: function ($scope, element, attrs) {
2443
- var topbar = $scope.topbar = element;
2444
- var topbarContainer = topbar.parent();
2445
- var body = angular.element($document[0].querySelector('body'));
2446
-
2447
- var isSticky = $scope.isSticky = function () {
2448
- var sticky = topbarContainer.hasClass($scope.settings.stickyClass);
2449
- if (sticky && $scope.settings.stickyOn === 'all') {
2450
- return true;
2451
- } else if (sticky && mediaQueries.small() && $scope.settings.stickyOn === 'small') {
2452
- return true;
2453
- } else if (sticky && mediaQueries.medium() && $scope.settings.stickyOn === 'medium') {
2454
- return true;
2455
- } else if (sticky && mediaQueries.large() && $scope.settings.stickyOn === 'large') {
2456
- return true;
2457
- }
2458
- return false;
2459
- };
2460
2572
 
2461
- var updateStickyPositioning = function(){
2462
- if (!$scope.stickyTopbar || !$scope.isSticky()) {
2463
- return;
2464
- }
2465
-
2466
- var $class = angular.element($document[0].querySelector('.' + $scope.settings.stickyClass));
2467
- var distance = stickyoffset;
2468
-
2469
- if ($window.scrollY > distance && !$class.hasClass('fixed')) {
2470
- $class.addClass('fixed');
2471
- body.css('padding-top', $scope.originalHeight + 'px');
2472
- } else if ($window.scrollY <= distance && $class.hasClass('fixed')) {
2473
- $class.removeClass('fixed');
2474
- body.css('padding-top', '');
2475
- }
2476
- };
2573
+ this.removeSection = function(section) {
2574
+ var index = sections.indexOf(section);
2575
+ if (index > -1) {
2576
+ sections.splice(index, 1);
2577
+ }
2578
+ };
2477
2579
 
2478
- $scope.toggle = function(on) {
2479
- if(!mediaQueries.topbarBreakpoint()){
2480
- return false;
2481
- }
2482
-
2483
- var expand = (on === undefined) ? !topbar.hasClass('expanded') : on;
2484
-
2485
- if (expand){
2486
- topbar.addClass('expanded');
2487
- }
2488
- else {
2489
- topbar.removeClass('expanded');
2490
- }
2491
-
2492
- if ($scope.settings.scrolltop) {
2493
- if (!expand && topbar.hasClass('fixed')) {
2494
- topbar.parent().addClass('fixed');
2495
- topbar.removeClass('fixed');
2496
- body.css('padding-top', $scope.originalHeight + 'px');
2497
- } else if (expand && topbar.parent().hasClass('fixed')) {
2498
- topbar.parent().removeClass('fixed');
2499
- topbar.addClass('fixed');
2500
- body.css('padding-top', '');
2501
- $window.scrollTo(0,0);
2502
- }
2503
- } else {
2504
- if(isSticky()) {
2505
- topbar.parent().addClass('fixed');
2506
- }
2507
-
2508
- if(topbar.parent().hasClass('fixed')) {
2509
- if (!expand) {
2510
- topbar.removeClass('fixed');
2511
- topbar.parent().removeClass('expanded');
2512
- updateStickyPositioning();
2513
- } else {
2514
- topbar.addClass('fixed');
2515
- topbar.parent().addClass('expanded');
2516
- body.css('padding-top', $scope.originalHeight + 'px');
2517
- }
2518
- }
2519
- }
2520
- };
2580
+ var dir = /rtl/i.test($document.find('html').attr('dir')) ? 'right' : 'left';
2521
2581
 
2522
- if(topbarContainer.hasClass('fixed') || isSticky() ) {
2523
- $scope.stickyTopbar = true;
2524
- $scope.height = topbarContainer[0].offsetHeight;
2525
- var stickyoffset = topbarContainer[0].getBoundingClientRect().top;
2526
- } else {
2527
- $scope.height = topbar[0].offsetHeight;
2528
- }
2582
+ $scope.$watch('index', function(index) {
2583
+ for(var i = 0; i < sections.length; i++){
2584
+ sections[i].move(dir, index);
2585
+ }
2586
+ });
2529
2587
 
2530
- $scope.originalHeight = $scope.height;
2588
+ this.toggle = function(on) {
2589
+ $scope.toggle(on);
2590
+ for(var i = 0; i < sections.length; i++){
2591
+ sections[i].reset();
2592
+ }
2593
+ $scope.index = 0;
2594
+ $scope.height = '';
2595
+ $scope.$apply();
2596
+ };
2531
2597
 
2532
- $scope.$watch('height', function(h){
2533
- if(h){
2534
- topbar.css('height', h + 'px');
2535
- } else {
2536
- topbar.css('height', '');
2537
- }
2538
- });
2598
+ this.back = function(event) {
2599
+ if($scope.index < 1 || !mediaQueries.topbarBreakpoint()){
2600
+ return;
2601
+ }
2539
2602
 
2540
- var lastBreakpoint = mediaQueries.topbarBreakpoint();
2603
+ var $link = angular.element(event.currentTarget);
2604
+ var $movedLi = closest($link, 'li.moved');
2605
+ var $previousLevelUl = $movedLi.parent();
2606
+ $scope.index = $scope.index -1;
2541
2607
 
2542
- angular.element($window).bind('resize', function(){
2543
- var currentBreakpoint = mediaQueries.topbarBreakpoint();
2544
- if(lastBreakpoint === currentBreakpoint){
2545
- return;
2546
- }
2547
- lastBreakpoint = mediaQueries.topbarBreakpoint();
2608
+ if($scope.index === 0){
2609
+ $scope.height = '';
2610
+ } else {
2611
+ $scope.height = $scope.originalHeight + outerHeight($previousLevelUl[0]);
2612
+ }
2548
2613
 
2549
- topbar.removeClass('expanded');
2550
- topbar.parent().removeClass('expanded');
2551
- $scope.height = '';
2614
+ $timeout(function() {
2615
+ $movedLi.removeClass('moved');
2616
+ }, 300);
2617
+ };
2552
2618
 
2553
- var sections = angular.element(topbar[0].querySelectorAll('section'));
2554
- angular.forEach(sections, function(section){
2555
- angular.element(section.querySelectorAll('li.moved')).removeClass('moved');
2556
- });
2619
+ this.forward = function(event) {
2620
+ if(!mediaQueries.topbarBreakpoint()){
2621
+ return false;
2622
+ }
2557
2623
 
2558
- $scope.$apply();
2559
- });
2624
+ var $link = angular.element(event.currentTarget);
2625
+ var $selectedLi = closest($link, 'li');
2626
+ $selectedLi.addClass('moved');
2627
+ $scope.height = $scope.originalHeight + outerHeight($link.parent()[0].querySelector('ul'));
2628
+ $scope.index = $scope.index + 1;
2629
+ $scope.$apply();
2630
+ };
2560
2631
 
2561
- // update sticky positioning
2562
- angular.element($window).bind("scroll", function() {
2563
- updateStickyPositioning();
2564
- $scope.$apply();
2565
- });
2632
+ }],
2633
+ link: function(scope, element, attrs) {
2634
+ var topbar = scope.topbar = element;
2635
+ var topbarContainer = topbar.parent();
2636
+ var body = angular.element($document[0].querySelector('body'));
2637
+ var lastBreakpoint = mediaQueries.topbarBreakpoint();
2638
+
2639
+ var isSticky = scope.isSticky = function() {
2640
+ var sticky = topbarContainer.hasClass(scope.settings.stickyClass);
2641
+ if (sticky && scope.settings.stickyOn === 'all') {
2642
+ return true;
2643
+ } else if (sticky && mediaQueries.small() && scope.settings.stickyOn === 'small') {
2644
+ return true;
2645
+ } else if (sticky && mediaQueries.medium() && scope.settings.stickyOn === 'medium') {
2646
+ return true;
2647
+ } else if (sticky && mediaQueries.large() && scope.settings.stickyOn === 'large') {
2648
+ return true;
2649
+ }
2650
+ return false;
2651
+ };
2566
2652
 
2567
- $scope.$on('$destroy', function(){
2568
- angular.element($window).unbind("scroll");
2569
- angular.element($window).unbind("resize");
2570
- });
2653
+ var updateStickyPositioning = function() {
2654
+ if (!scope.stickyTopbar || !scope.isSticky()) {
2655
+ return;
2656
+ }
2571
2657
 
2572
- if (topbarContainer.hasClass('fixed')) {
2573
- body.css('padding-top', $scope.originalHeight + 'px');
2574
- }
2658
+ var distance = stickyoffset;
2575
2659
 
2576
- },
2577
- controller: ['$window', '$scope', 'closest', function($window, $scope, closest) {
2578
- $scope.settings = {};
2579
- $scope.settings.stickyClass = $scope.stickyClass || 'sticky';
2580
- $scope.settings.backText = $scope.backText || 'Back';
2581
- $scope.settings.stickyOn = $scope.stickyOn || 'all';
2660
+ if ($window.pageYOffset > distance && !topbarContainer.hasClass('fixed')) {
2661
+ topbarContainer.addClass('fixed');
2662
+ body.css('padding-top', scope.originalHeight + 'px');
2663
+ } else if ($window.pageYOffset <= distance && topbarContainer.hasClass('fixed')) {
2664
+ topbarContainer.removeClass('fixed');
2665
+ body.css('padding-top', '');
2666
+ }
2667
+ };
2582
2668
 
2583
- $scope.settings.customBackText = $scope.customBackText === undefined ? true : $scope.customBackText;
2584
- $scope.settings.isHover = $scope.isHover === undefined ? true : $scope.isHover;
2585
- $scope.settings.mobileShowParentLink = $scope.mobileShowParentLink === undefined ? true : $scope.mobileShowParentLink;
2586
- $scope.settings.scrolltop = $scope.scrolltop === undefined ? true : $scope.scrolltop; // jump to top when sticky nav menu toggle is clicked
2669
+ var onResize = function() {
2670
+ var currentBreakpoint = mediaQueries.topbarBreakpoint();
2671
+ if(lastBreakpoint === currentBreakpoint){
2672
+ return;
2673
+ }
2674
+ lastBreakpoint = mediaQueries.topbarBreakpoint();
2587
2675
 
2588
- this.settings = $scope.settings;
2676
+ topbar.removeClass('expanded');
2677
+ topbar.parent().removeClass('expanded');
2678
+ scope.height = '';
2589
2679
 
2590
- $scope.index = 0;
2680
+ var sections = angular.element(topbar[0].querySelectorAll('section'));
2681
+ angular.forEach(sections, function(section) {
2682
+ angular.element(section.querySelectorAll('li.moved')).removeClass('moved');
2683
+ });
2591
2684
 
2592
- var outerHeight = function(el){
2593
- var height = el.offsetHeight;
2594
- var style = el.currentStyle || getComputedStyle(el);
2685
+ scope.$apply();
2686
+ };
2595
2687
 
2596
- height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
2597
- return height;
2598
- };
2688
+ var onScroll = function() {
2689
+ updateStickyPositioning();
2690
+ scope.$apply();
2691
+ };
2599
2692
 
2693
+ scope.toggle = function(on) {
2694
+ if(!mediaQueries.topbarBreakpoint()){
2695
+ return false;
2696
+ }
2600
2697
 
2601
- var sections = [];
2698
+ var expand = (on === undefined) ? !topbar.hasClass('expanded') : on;
2602
2699
 
2603
- this.addSection = function(section){
2604
- sections.push(section);
2605
- };
2700
+ if (expand) {
2701
+ topbar.addClass('expanded');
2702
+ }
2703
+ else {
2704
+ topbar.removeClass('expanded');
2705
+ }
2606
2706
 
2607
- this.removeSection = function(section){
2608
- var index = sections.indexOf(section);
2609
- if (index > -1) {
2610
- sections.splice(index, 1);
2611
- }
2612
- };
2707
+ if (scope.settings.scrolltop) {
2708
+ if (!expand && topbar.hasClass('fixed')) {
2709
+ topbar.parent().addClass('fixed');
2710
+ topbar.removeClass('fixed');
2711
+ body.css('padding-top', scope.originalHeight + 'px');
2712
+ } else if (expand && topbar.parent().hasClass('fixed')) {
2713
+ topbar.parent().removeClass('fixed');
2714
+ topbar.addClass('fixed');
2715
+ body.css('padding-top', '');
2716
+ $window.scrollTo(0,0);
2717
+ }
2718
+ } else {
2719
+ if(isSticky()) {
2720
+ topbar.parent().addClass('fixed');
2721
+ }
2613
2722
 
2614
- var dir = /rtl/i.test($document.find('html').attr('dir')) ? 'right' : 'left';
2723
+ if(topbar.parent().hasClass('fixed')) {
2724
+ if (!expand) {
2725
+ topbar.removeClass('fixed');
2726
+ topbar.parent().removeClass('expanded');
2727
+ updateStickyPositioning();
2728
+ } else {
2729
+ topbar.addClass('fixed');
2730
+ topbar.parent().addClass('expanded');
2731
+ body.css('padding-top', scope.originalHeight + 'px');
2732
+ }
2733
+ }
2734
+ }
2735
+ };
2615
2736
 
2616
- $scope.$watch('index', function(index){
2617
- for(var i = 0; i < sections.length; i++){
2618
- sections[i].move(dir, index);
2619
- }
2620
- });
2737
+ if(topbarContainer.hasClass('fixed') || isSticky() ) {
2738
+ scope.stickyTopbar = true;
2739
+ scope.height = topbarContainer[0].offsetHeight;
2740
+ var stickyoffset = topbarContainer[0].getBoundingClientRect().top + $window.pageYOffset;
2741
+ } else {
2742
+ scope.height = topbar[0].offsetHeight;
2743
+ }
2621
2744
 
2622
- this.toggle = function(on){
2623
- $scope.toggle(on);
2624
- for(var i = 0; i < sections.length; i++){
2625
- sections[i].reset();
2626
- }
2627
- $scope.index = 0;
2628
- $scope.height = '';
2629
- $scope.$apply();
2630
- };
2745
+ scope.originalHeight = scope.height;
2631
2746
 
2632
- this.back = function(event) {
2633
- if($scope.index < 1 || !mediaQueries.topbarBreakpoint()){
2634
- return;
2635
- }
2636
-
2637
- var $link = angular.element(event.currentTarget);
2638
- var $movedLi = closest($link, 'li.moved');
2639
- var $previousLevelUl = $movedLi.parent();
2640
- $scope.index = $scope.index -1;
2641
-
2642
- if($scope.index === 0){
2643
- $scope.height = '';
2644
- } else {
2645
- $scope.height = $scope.originalHeight + outerHeight($previousLevelUl[0]);
2646
- }
2647
-
2648
- $timeout(function () {
2649
- $movedLi.removeClass('moved');
2650
- }, 300);
2651
- };
2747
+ scope.$watch('height', function(h) {
2748
+ if(h){
2749
+ topbar.css('height', h + 'px');
2750
+ } else {
2751
+ topbar.css('height', '');
2752
+ }
2753
+ });
2652
2754
 
2653
- this.forward = function(event) {
2654
- if(!mediaQueries.topbarBreakpoint()){
2655
- return false;
2656
- }
2657
-
2658
- var $link = angular.element(event.currentTarget);
2659
- var $selectedLi = closest($link, 'li');
2660
- $selectedLi.addClass('moved');
2661
- $scope.height = $scope.originalHeight + outerHeight($link.parent()[0].querySelector('ul'));
2662
- $scope.index = $scope.index + 1;
2663
- $scope.$apply();
2664
- };
2755
+ angular.element($window).bind('resize', onResize);
2756
+ angular.element($window).bind('scroll', onScroll);
2665
2757
 
2666
- }]
2667
- };
2668
- }])
2669
- .directive('toggleTopBar', ['closest', function (closest) {
2670
- return {
2671
- scope: {},
2672
- require: '^topBar',
2673
- restrict: 'A',
2674
- replace: true,
2675
- templateUrl: 'template/topbar/toggle-top-bar.html',
2676
- transclude: true,
2677
- link: function ($scope, element, attrs, topBar) {
2678
- element.bind('click', function(event) {
2679
- var li = closest(angular.element(event.currentTarget), 'li');
2680
- if(!li.hasClass('back') && !li.hasClass('has-dropdown')) {
2681
- topBar.toggle();
2682
- }
2683
- });
2758
+ scope.$on('$destroy', function() {
2759
+ angular.element($window).unbind('scroll', onResize);
2760
+ angular.element($window).unbind('resize', onScroll);
2761
+ });
2684
2762
 
2685
- $scope.$on('$destroy', function(){
2686
- element.unbind('click');
2687
- });
2688
- }
2689
- };
2690
- }])
2691
- .directive('topBarSection', ['$compile', 'closest', function ($compile, closest) {
2692
- return {
2693
- scope: {},
2694
- require: '^topBar',
2695
- restrict: 'EA',
2696
- replace: true,
2697
- templateUrl: 'template/topbar/top-bar-section.html',
2698
- transclude: true,
2699
- link: function ($scope, element, attrs, topBar) {
2700
- var section = element;
2701
-
2702
- $scope.reset = function(){
2703
- angular.element(section[0].querySelectorAll('li.moved')).removeClass('moved');
2704
- };
2763
+ if (topbarContainer.hasClass('fixed')) {
2764
+ body.css('padding-top', scope.originalHeight + 'px');
2765
+ }
2766
+ }
2767
+ };
2768
+ }]
2769
+ )
2770
+ .directive('toggleTopBar', ['closest', function (closest) {
2771
+ return {
2772
+ scope: {},
2773
+ require: '^topBar',
2774
+ restrict: 'A',
2775
+ replace: true,
2776
+ templateUrl: 'template/topbar/toggle-top-bar.html',
2777
+ transclude: true,
2778
+ link: function(scope, element, attrs, topBar) {
2779
+ element.bind('click', function(event) {
2780
+ var li = closest(angular.element(event.currentTarget), 'li');
2781
+ if(!li.hasClass('back') && !li.hasClass('has-dropdown')) {
2782
+ topBar.toggle();
2783
+ }
2784
+ });
2705
2785
 
2706
- $scope.move = function(dir, index){
2707
- if(dir === 'left'){
2708
- section.css({"left": index * -100 + '%'});
2709
- }
2710
- else {
2711
- section.css({"right": index * -100 + '%'});
2712
- }
2713
- };
2786
+ scope.$on('$destroy', function() {
2787
+ element.unbind('click');
2788
+ });
2789
+ }
2790
+ };
2791
+ }])
2792
+ .directive('topBarSection', ['$compile', 'closest', function($compile, closest) {
2793
+ return {
2794
+ scope: {},
2795
+ require: '^topBar',
2796
+ restrict: 'EA',
2797
+ replace: true,
2798
+ templateUrl: 'template/topbar/top-bar-section.html',
2799
+ transclude: true,
2800
+ link: function(scope, element, attrs, topBar) {
2801
+ var section = element;
2714
2802
 
2715
- topBar.addSection($scope);
2803
+ scope.reset = function() {
2804
+ angular.element(section[0].querySelectorAll('li.moved')).removeClass('moved');
2805
+ };
2716
2806
 
2717
- $scope.$on("$destroy", function(){
2718
- topBar.removeSection($scope);
2719
- });
2807
+ scope.move = function(dir, index) {
2808
+ if(dir === 'left'){
2809
+ section.css({"left": index * -100 + '%'});
2810
+ }
2811
+ else {
2812
+ section.css({"right": index * -100 + '%'});
2813
+ }
2814
+ };
2720
2815
 
2721
- // Top level links close menu on click
2722
- var links = section[0].querySelectorAll('li>a');
2723
- angular.forEach(links, function(link){
2724
- var $link = angular.element(link);
2725
- var li = closest($link, 'li');
2726
- if(li.hasClass('has-dropdown') || li.hasClass('back') || li.hasClass('title')){
2727
- return;
2728
- }
2729
-
2730
- $link.bind('click', function(){
2731
- topBar.toggle(false);
2732
- });
2733
-
2734
- $scope.$on('$destroy', function(){
2735
- $link.bind('click');
2736
- });
2737
- });
2816
+ topBar.addSection(scope);
2738
2817
 
2739
- }
2740
- };
2741
- }])
2742
- .directive('hasDropdown', ['mediaQueries', function (mediaQueries) {
2743
- return {
2744
- scope: {},
2745
- require: '^topBar',
2746
- restrict: 'A',
2747
- templateUrl: 'template/topbar/has-dropdown.html',
2748
- replace: true,
2749
- transclude: true,
2750
- link: function ($scope, element, attrs, topBar) {
2751
- $scope.triggerLink = element.children('a')[0];
2752
-
2753
- var $link = angular.element($scope.triggerLink);
2754
-
2755
- $link.bind('click', function(event){
2756
- topBar.forward(event);
2757
- });
2758
- $scope.$on('$destroy', function(){
2759
- $link.unbind('click');
2760
- });
2818
+ scope.$on("$destroy", function() {
2819
+ topBar.removeSection(scope);
2820
+ });
2761
2821
 
2762
- element.bind('mouseenter', function() {
2763
- if(topBar.settings.isHover && !mediaQueries.topbarBreakpoint()){
2764
- element.addClass('not-click');
2765
- }
2766
- });
2767
- element.bind('click', function(event) {
2768
- if(!topBar.settings.isHover && !mediaQueries.topbarBreakpoint()){
2769
- element.toggleClass('not-click');
2770
- }
2771
- });
2822
+ // Top level links close menu on click
2823
+ var links = section[0].querySelectorAll('li>a');
2824
+ angular.forEach(links, function(link) {
2825
+ var $link = angular.element(link);
2826
+ var li = closest($link, 'li');
2827
+ if (li.hasClass('has-dropdown') || li.hasClass('back') || li.hasClass('title')) {
2828
+ return;
2829
+ }
2772
2830
 
2773
- element.bind('mouseleave', function() {
2774
- element.removeClass('not-click');
2775
- });
2831
+ $link.bind('click', function() {
2832
+ topBar.toggle(false);
2833
+ });
2776
2834
 
2777
- $scope.$on('$destroy', function(){
2778
- element.unbind('click');
2779
- element.unbind('mouseenter');
2780
- element.unbind('mouseleave');
2781
- });
2782
- },
2783
- controller: ['$window', '$scope', function($window, $scope) {
2784
- this.triggerLink = $scope.triggerLink;
2785
- }]
2786
- };
2787
- }])
2788
- .directive('topBarDropdown', ['$compile', function ($compile) {
2789
- return {
2790
- scope: {},
2791
- require: ['^topBar', '^hasDropdown'],
2792
- restrict: 'A',
2793
- replace: true,
2794
- templateUrl: 'template/topbar/top-bar-dropdown.html',
2795
- transclude: true,
2796
- link: function ($scope, element, attrs, ctrls) {
2835
+ scope.$on('$destroy', function() {
2836
+ $link.bind('click');
2837
+ });
2838
+ });
2839
+ }
2840
+ };
2841
+ }])
2842
+ .directive('hasDropdown', ['mediaQueries', function (mediaQueries) {
2843
+ return {
2844
+ scope: {},
2845
+ require: '^topBar',
2846
+ restrict: 'A',
2847
+ templateUrl: 'template/topbar/has-dropdown.html',
2848
+ replace: true,
2849
+ transclude: true,
2850
+ link: function(scope, element, attrs, topBar) {
2851
+ scope.triggerLink = element.children('a')[0];
2797
2852
 
2798
- var topBar = ctrls[0];
2799
- var hasDropdown = ctrls[1];
2853
+ var $link = angular.element(scope.triggerLink);
2800
2854
 
2801
- var $link = angular.element(hasDropdown.triggerLink);
2802
- var url = $link.attr('href');
2855
+ $link.bind('click', function(event) {
2856
+ topBar.forward(event);
2857
+ });
2858
+ scope.$on('$destroy', function() {
2859
+ $link.unbind('click');
2860
+ });
2803
2861
 
2804
- $scope.linkText = $link.text();
2862
+ element.bind('mouseenter', function() {
2863
+ if(topBar.settings.isHover && !mediaQueries.topbarBreakpoint()){
2864
+ element.addClass('not-click');
2865
+ }
2866
+ });
2867
+ element.bind('click', function(event) {
2868
+ if(!topBar.settings.isHover && !mediaQueries.topbarBreakpoint()){
2869
+ element.toggleClass('not-click');
2870
+ }
2871
+ });
2805
2872
 
2806
- $scope.back = function(event){
2807
- topBar.back(event);
2808
- };
2873
+ element.bind('mouseleave', function() {
2874
+ element.removeClass('not-click');
2875
+ });
2809
2876
 
2810
- // Add back link
2811
- if (topBar.settings.customBackText) {
2812
- $scope.backText = topBar.settings.backText;
2813
- } else {
2814
- $scope.backText = '&laquo; ' + $link.html();
2815
- }
2877
+ scope.$on('$destroy', function() {
2878
+ element.unbind('click');
2879
+ element.unbind('mouseenter');
2880
+ element.unbind('mouseleave');
2881
+ });
2882
+ },
2883
+ controller: ['$window', '$scope', function($window, $scope) {
2884
+ this.triggerLink = $scope.triggerLink;
2885
+ }]
2886
+ };
2887
+ }])
2888
+ .directive('topBarDropdown', ['$compile', function($compile) {
2889
+ return {
2890
+ scope: {},
2891
+ require: ['^topBar', '^hasDropdown'],
2892
+ restrict: 'A',
2893
+ replace: true,
2894
+ templateUrl: 'template/topbar/top-bar-dropdown.html',
2895
+ transclude: true,
2896
+ link: function(scope, element, attrs, ctrls) {
2897
+ var topBar = ctrls[0];
2898
+ var hasDropdown = ctrls[1];
2899
+ var $link = angular.element(hasDropdown.triggerLink);
2900
+ var url = $link.attr('href');
2901
+ var $titleLi;
2816
2902
 
2817
- var $titleLi;
2818
- if (topBar.settings.mobileShowParentLink && url && url.length > 1) {
2819
- $titleLi = angular.element('<li class="title back js-generated">' +
2820
- '<h5><a href="#" ng-click="back($event);">{{backText}}</a></h5></li>' +
2821
- '<li><a class="parent-link js-generated" href="' +
2822
- url + '">{{linkText}}</a></li>');
2823
- } else {
2824
- $titleLi = angular.element('<li class="title back js-generated">' +
2825
- '<h5><a href="" ng-click="back($event);">{{backText}}</a></h5></li>');
2826
- }
2903
+ scope.linkText = $link.text();
2827
2904
 
2828
- $compile($titleLi)($scope);
2829
- element.prepend($titleLi);
2830
- }
2831
- };
2832
- }]);
2905
+ scope.back = function(event) {
2906
+ topBar.back(event);
2907
+ };
2908
+
2909
+ // Add back link
2910
+ if (topBar.settings.customBackText) {
2911
+ scope.backText = topBar.settings.backText;
2912
+ } else {
2913
+ scope.backText = '&laquo; ' + $link.html();
2914
+ }
2915
+
2916
+ if (topBar.settings.mobileShowParentLink && url && url.length > 1) {
2917
+ $titleLi = angular.element('<li class="title back js-generated">' +
2918
+ '<h5><a href="#" ng-click="back($event);">{{backText}}</a></h5></li>' +
2919
+ '<li><a class="parent-link js-generated" href="' +
2920
+ url + '">{{linkText}}</a></li>');
2921
+ } else {
2922
+ $titleLi = angular.element('<li class="title back js-generated">' +
2923
+ '<h5><a href="" ng-click="back($event);">{{backText}}</a></h5></li>');
2924
+ }
2925
+
2926
+ $compile($titleLi)(scope);
2927
+ element.prepend($titleLi);
2928
+ }
2929
+ };
2930
+ }]);
2833
2931
 
2834
2932
  angular.module( 'mm.foundation.tour', [ 'mm.foundation.position', 'mm.foundation.tooltip' ] )
2835
2933
 
2836
2934
  .service( '$tour', [ '$window', function ( $window ) {
2837
- var currentIndex = getCurrentStep();
2935
+ var currentIndex = getStoredCurrentStep();
2838
2936
  var ended = false;
2839
2937
  var steps = {};
2840
2938
 
2841
- function getCurrentStep() {
2842
- return parseInt( $window.localStorage.getItem( 'mm.tour.step' ), 10 );
2939
+ function getStoredCurrentStep() {
2940
+ try {
2941
+ return parseInt( $window.localStorage.getItem( 'mm.tour.step' ), 10 );
2942
+ } catch(e) {
2943
+ if (e.name !== "SecurityError") {
2944
+ throw e;
2945
+ }
2946
+ }
2947
+ }
2948
+
2949
+ function storeCurrentStep() {
2950
+ try {
2951
+ $window.localStorage.setItem( 'mm.tour.step', currentIndex );
2952
+ } catch(e) {
2953
+ if (e.name !== "SecurityError") {
2954
+ throw e;
2955
+ }
2956
+ }
2843
2957
  }
2844
2958
 
2845
2959
  function setCurrentStep(step) {
2846
2960
  currentIndex = step;
2847
- $window.localStorage.setItem( 'mm.tour.step', step );
2961
+ storeCurrentStep();
2848
2962
  }
2849
2963
 
2850
2964
  this.add = function ( index, attrs ) {
@@ -2900,6 +3014,8 @@ angular.module( 'mm.foundation.tour', [ 'mm.foundation.position', 'mm.foundation
2900
3014
  element.remove();
2901
3015
  $tour.next();
2902
3016
  };
3017
+
3018
+ scope.$on('$locationChangeSuccess', scope.endTour);
2903
3019
  }
2904
3020
  };
2905
3021
  }])
@@ -2931,7 +3047,7 @@ angular.module( 'mm.foundation.tour', [ 'mm.foundation.position', 'mm.foundation
2931
3047
  return true;
2932
3048
  }
2933
3049
  }
2934
-
3050
+
2935
3051
  return false;
2936
3052
  }
2937
3053
 
@@ -3068,10 +3184,10 @@ angular.module('mm.foundation.typeahead', ['mm.foundation.position', 'mm.foundat
3068
3184
  } else {
3069
3185
  resetMatches();
3070
3186
  }
3071
- isLoadingSetter(originalScope, false);
3072
3187
  }
3073
3188
  }, function(){
3074
3189
  resetMatches();
3190
+ }).finally(function() {
3075
3191
  isLoadingSetter(originalScope, false);
3076
3192
  });
3077
3193
  };
@@ -3288,4 +3404,4 @@ angular.module('mm.foundation.typeahead', ['mm.foundation.position', 'mm.foundat
3288
3404
  return function(matchItem, query) {
3289
3405
  return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
3290
3406
  };
3291
- });
3407
+ });