angularjs-foundation-rails 0.3.1.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ });