sidebar.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. (function (window, $) {
  2. // TODO
  3. // - check the actual
  4. // - add options
  5. // - some demos, patterns
  6. var Sidebar = function (target, opts) {
  7. this.$sidebar = $(target);
  8. this.$body = $(document.body);
  9. this.$content = this.$body.find('.jsc-sidebar-content');
  10. this.sidebarW = this.$sidebar.width();
  11. this.opts = opts;
  12. this.meta = this.$sidebar.data('sidebar-options');
  13. };
  14. Sidebar.prototype = {
  15. defaults: {
  16. trigger: null,
  17. scrollbarDisplay: false,
  18. pullCb: function () {},
  19. pushCb: function () {}
  20. },
  21. init: function () {
  22. this.config = $.extend({}, this.defaults, this.opts, this.meta);
  23. this.$trigger = this.config.trigger ? this.$body.find(this.config.trigger) : this.$body.find('.jsc-sidebar-trigger');
  24. this.detect3dEnabled();
  25. this.attachEvent();
  26. return this;
  27. },
  28. pushTransitionEndEvent: 'transitionEnd.push webkitTransitionEnd.push transitionend.push msTransitionEnd.push',
  29. pullTransitionEndEvent: 'transitionEnd.pull webkitTransitionEnd.pull transitionend.pull msTransitionEnd.pull',
  30. isAndroid: function () {
  31. var ua = (window.navigator.userAgent).toLowerCase(),
  32. isAndroid = ua.indexOf('android') > -1;
  33. return isAndroid;
  34. },
  35. hasTranslate3dSupport: function () {
  36. var p = document.createElement('p'),
  37. has3dSupport,
  38. transforms = {
  39. 'transform': 'transform',
  40. 'webkitTransform': '-webkit-transform',
  41. 'MozTransform': '-moz-transform',
  42. 'msTransform': '-ms-transform'
  43. };
  44. this.$body[0].insertBefore(p, null);
  45. for (var transform in transforms) {
  46. if (p.style[transform] !== undefined) {
  47. p.style[transform] = 'translate3d(1px, 1px, 1px)';
  48. has3dSupport = window.getComputedStyle(p).getPropertyValue(transforms[transform]);
  49. }
  50. }
  51. this.$body[0].removeChild(p);
  52. return (has3dSupport !== undefined && has3dSupport.length && has3dSupport !== 'none');
  53. },
  54. detect3dEnabled: function () {
  55. if (this.isAndroid() || !this.hasTranslate3dSupport()) {
  56. this.$content.removeClass('jsc-sidebar-pulled');
  57. }
  58. },
  59. attachEvent: function () {
  60. this.$trigger.on('click', $.proxy(function (e) {
  61. e.preventDefault();
  62. this.push();
  63. }, this));
  64. this.$content
  65. .on(this.pushTransitionEndEvent, $.proxy(function (e) {
  66. this.detectPushEnd();
  67. this.config.pushCb();
  68. }, this))
  69. .on('click', $.proxy(function (e) {
  70. this.pull();
  71. }, this));
  72. },
  73. push: function () {
  74. if (this.isAndroid() || !this.hasTranslate3dSupport()) {
  75. this.slidePush();
  76. } else {
  77. this.$content
  78. .removeClass('jsc-sidebar-pull-end')
  79. .addClass('jsc-sidebar-pushed');
  80. }
  81. },
  82. pull: function () {
  83. if (this.isAndroid() || !this.hasTranslate3dSupport()) {
  84. this.slidePull();
  85. } else {
  86. if (!this.$content.hasClass('jsc-sidebar-push-end')) {
  87. return;
  88. }
  89. this.$content.removeClass('jsc-sidebar-pushed');
  90. }
  91. },
  92. slidePull: function () {
  93. if (this.$content.data('sidebar-first-click') !== 1 || !(this.$content.hasClass('jsc-sidebar-opened'))) {
  94. return;
  95. }
  96. this.$content.stop().animate({
  97. marginLeft: 0
  98. }).promise().done($.proxy(function () {
  99. this.$content.removeClass('jsc-sidebar-opened');
  100. !this.config.scrollbarDisplay && this.$content.removeClass('jsc-sidebar-scroll-disabled');
  101. this.config.pullCb();
  102. }, this));
  103. },
  104. slidePush: function () {
  105. var distance = this.sidebarW + 'px';
  106. this.$content.stop().animate({
  107. marginLeft: distance
  108. }).promise().done($.proxy(function () {
  109. this.$content.addClass('jsc-sidebar-opened');
  110. !this.config.scrollbarDisplay && this.$content.addClass('jsc-sidebar-scroll-disabled');
  111. if (!this.$content.data('sidebar-first-click')) {
  112. this.$content.data('sidebar-first-click', 1);
  113. }
  114. this.config.pushCb();
  115. }, this));
  116. },
  117. detectPushEnd: function () {
  118. this.$content.addClass('jsc-sidebar-opened');
  119. !this.config.scrollbarDisplay && this.$content.addClass('jsc-sidebar-scroll-disabled');
  120. this.$content
  121. .addClass('jsc-sidebar-push-end')
  122. .off(this.pushTransitionEndEvent)
  123. .on(this.pullTransitionEndEvent, $.proxy(function () {
  124. this.detectPullEnd();
  125. this.config.pullCb();
  126. }, this));
  127. },
  128. detectPullEnd: function () {
  129. this.$content.removeClass('jsc-sidebar-disabled');
  130. !this.config.scrollbarDisplay && this.$content.removeClass('jsc-sidebar-scroll-disabled');
  131. this.$content
  132. .removeClass('jsc-sidebar-push-end')
  133. .addClass('jsc-sidebar-pull-end')
  134. .off(this.pullTransitionEndEvent)
  135. .on(this.pushTransitionEndEvent, $.proxy(function () {
  136. this.detectPushEnd();
  137. this.config.pushCb();
  138. }, this));
  139. }
  140. };
  141. Sidebar.defaults = Sidebar.prototype.defaults;
  142. $.fn.sidebar = function (options) {
  143. return this.each(function () {
  144. new Sidebar(this, options).init();
  145. });
  146. };
  147. window.Sidebar = Sidebar;
  148. })(window, jQuery);