Allow beforeInit callbacks to lock and release init event, #152
authorimakewebthings <[email protected]>
Thu, 28 Nov 2013 01:43:13 +0000 (27 17:43 -0800)
committerimakewebthings <[email protected]>
Thu, 28 Nov 2013 01:43:13 +0000 (27 17:43 -0800)
core/deck.core.js
test/spec.core.js

index 02756c5..8150189 100644 (file)
@@ -227,28 +227,26 @@ that use the API provided by core.
     });
   };
 
-  /*
-      Kick iframe videos, which dont like to redraw w/ transforms.
-      Remove this if Webkit ever fixes it.
-       */
-  var hackWebkitIframes = function() {
-    $.each(slides, function(i, $slide) {
-      $slide.unbind('webkitTransitionEnd.deck');
-      $slide.bind('webkitTransitionEnd.deck', function(event) {
-        if ($el.hasClass($.deck('getOptions').classes.current)) {
-          var embeds = $(this).find('iframe').css('opacity', 0);
-          window.setTimeout(function() {
-            embeds.css('opacity', 1);
-          }, 100);
-        }
-      });
-    });
-  };
-
   var indexInBounds = function(index) {
     return typeof index === 'number' && index >=0 && index < slides.length;
   };
 
+  var createBeforeInitEvent = function() {
+    var event = $.Event(events.beforeInitialize);
+    event.locks = 0;
+    event.done = $.noop;
+    event.lockInit = function() {
+      ++event.locks;
+    };
+    event.releaseInit = function() {
+      --event.locks;
+      if (!event.locks) {
+        event.done();
+      }
+    };
+    return event;
+  };
+
   /* Methods exposed in the jQuery.deck namespace */
   var methods = {
 
@@ -275,31 +273,46 @@ that use the API provided by core.
     ]);
     */
     init: function(elements, opts) {
+      var beforeInitEvent = createBeforeInitEvent();
+
       options = $.extend(true, {}, $.deck.defaults, opts);
       slides = [];
       currentIndex = 0;
       $container = $(options.selectors.container);
-      tolerance = options.touch.swipeTolerance;
-
-      // Pre init event for preprocessing hooks
-      $document.trigger(events.beforeInitialize);
 
       // Hide the deck while states are being applied to kill transitions
       $container.addClass(options.classes.loading);
 
-      initSlidesArray(elements);
-      bindKeyEvents();
-      bindTouchEvents();
-      // hackWebkitIframes();
-      $container.scrollLeft(0).scrollTop(0);
+      // Pre init event for preprocessing hooks
+      beforeInitEvent.done = function() {
+        initSlidesArray(elements);
+        bindKeyEvents();
+        bindTouchEvents();
+        $container.scrollLeft(0).scrollTop(0);
+
+        if (slides.length) {
+          updateStates();
+        }
+
+        // Show deck again now that slides are in place
+        $container.removeClass(options.classes.loading);
+        $document.trigger(events.initialize);
+      };
 
-      if (slides.length) {
-        updateStates();
+      $document.trigger(beforeInitEvent);
+      if (!beforeInitEvent.locks) {
+        beforeInitEvent.done();
       }
-
-      // Show deck again now that slides are in place
-      $container.removeClass(options.classes.loading);
-      $document.trigger(events.initialize);
+      window.setTimeout(function() {
+        if (beforeInitEvent.locks) {
+          if (window.console) {
+            window.console.warn('Something locked deck initialization\
+              without releasing it before the timeout. Proceeding with\
+              initialization anyway.');
+          }
+          beforeInitEvent.done();
+        }
+      }, options.initLockTimeout);
     },
 
     /*
@@ -528,7 +541,9 @@ that use the API provided by core.
     touch: {
       swipeDirection: 'horizontal',
       swipeTolerance: 60
-    }
+    },
+
+    initLockTimeout: 10000
   };
 
   $document.ready(function() {
index 14953ff..0259ecd 100755 (executable)
@@ -242,41 +242,43 @@ describe('Deck JS', function() {
     });
 
     describe('events', function() {
-      var $d = $(document);
+      var $d;
 
       beforeEach(function() {
-        spyOnEvent($d, 'deck.init');
-        spyOnEvent($d, 'deck.beforeInit');
-        $.deck('.slide');
-        $.deck('go', 1);
-        spyOnEvent($d, 'deck.change');
+        $d = $(document);
       });
 
       describe('deck.change', function() {
+        var index, oldIndex;
+
+        beforeEach(function() {
+          $.deck('.slide');
+          $.deck('go', 1);
+          $d.one('deck.change', function(event, from, to) {
+            index = to;
+            oldIndex = from;
+          });
+        });
+
         it('should fire on go(i)', function() {
           $.deck('go', 3);
-          expect('deck.change').toHaveBeenTriggeredOn($d);
+          expect(index).toEqual(3);
         });
 
         it('should fire on next()', function() {
           $.deck('next');
-          expect('deck.change').toHaveBeenTriggeredOn($d);
+          expect(index).toEqual(2);
         });
 
         it('should fire on prev()', function() {
           $.deck('prev');
-          expect('deck.change').toHaveBeenTriggeredOn($d);
+          expect(index).toEqual(0);
         });
 
         it('should pass parameters with from and to indices', function() {
-          var f = function(e, from, to) {
-            expect(from).toEqual(1);
-            expect(to).toEqual(3);
-          };
-
-          $d.bind('deck.change', f);
           $.deck('go', 3);
-          $d.unbind('deck.change', f);
+          expect(index).toEqual(3);
+          expect(oldIndex).toEqual(1);
         });
 
         it('should not fire if default prevented in beforeChange', function() {
@@ -289,23 +291,24 @@ describe('Deck JS', function() {
 
       describe('deck.init', function() {
         it('should fire on deck initialization', function() {
-          expect('deck.init').toHaveBeenTriggeredOn($d);
-        });
-
-        it('should have already populated the slides array', function() {
-          var f = function() {
-            expect($.deck('getSlides').length).toBeGreaterThan(0);
-          };
-
-          $d.bind('deck.init', f);
           $.deck('.slide');
-          $d.unbind('deck.init', f);
+          expect($.deck('getSlides').length).toBeGreaterThan(0);
         });
       });
 
       describe('deck.beforeInit', function() {
+        var beforeHit;
+
+        beforeEach(function() {
+          beforeHit = false;
+          $d.on('deck.beforeInit', function() {
+            beforeHit = true;
+          });
+        });
+
         it('should fire on deck initialization', function() {
-          expect('deck.beforeInit').toHaveBeenTriggeredOn($d);
+          $.deck('.slide');
+          expect(beforeHit).toBeTruthy();
         });
 
         it('should have not populated the slides array', function() {
@@ -317,6 +320,67 @@ describe('Deck JS', function() {
           $.deck('.slide');
           $d.unbind('deck.beforeInit', f);
         });
+
+        it('should prevent the init event if lockInit is called', function() {
+          var initHit = false;
+          var f = function(event) {
+            event.lockInit();
+          };
+          var g = function() {
+            initHit = true;
+          };
+
+          $d.bind('deck.beforeInit', f);
+          $d.bind('deck.init', g);
+          $.deck('.slide');
+          $d.unbind('deck.beforeInit', f);
+          $d.unbind('deck.init', g);
+          expect(initHit).toBeFalsy();
+        });
+
+        it('should warn if locked without release', function() {
+          var warned = false;
+          var f = function(event) {
+            event.lockInit();
+          };
+          var warn = console.warn;
+          window.console.warn = function() {
+            warned = true;
+          };
+
+          $d.bind('deck.beforeInit', f);
+          $.deck('.slide', {
+            initLockTimeout: 20
+          });
+          $d.unbind('deck.beforeInit', f);
+
+          waitsFor(function() {
+            return warned;
+          }, 'warning', 2000);
+
+          runs(function() {
+            window.console.warn = warn;
+          });
+        });
+
+        it('should fire init event once releaseInit is called', function() {
+          var f = function(event) {
+            event.lockInit();
+            window.setTimeout(function() {
+              event.releaseInit();
+            }, 20);
+          };
+
+          runs(function() {
+            $d.bind('deck.beforeInit', f);
+            $.deck('.slide');
+            $d.unbind('deck.beforeInit', f);
+          });
+
+          waitsFor(function() {
+            return $.deck('getSlides').length > 0;
+          }, 'lock to release', 2000);
+        });
       });
     });
   });