this.$triggers = $();
this.position = 'left';
this.$content = $();
+ this.nested = false;
this._init();
this._events();
this.$content = this.$element.closest('[data-off-canvas-content]').first();
}
+ // Assume that the off-canvas element is nested if it isn't a sibling of the content
+ this.nested = this.$element.siblings('[data-off-canvas-content]').length && !this.options.contentId ? false : true;
+
this.$content.addClass(`has-transition-${this.options.transition}`);
// Add an overlay over the content if necessary
}
this._setContentClasses();
+
+ this._emulateFixedPosition(true);
}
/**
* @private
*/
_events() {
+ var id = this.$element.attr('id');
+
this.$element.off('.zf.trigger .zf.offcanvas').on({
'open.zf.trigger': this.open.bind(this),
'close.zf.trigger': this.close.bind(this),
var $target = this.options.contentOverlay ? this.$overlay : this.$content;
$target.on({'click.zf.offcanvas': this.close.bind(this)});
}
+
+ var resizeListener = this.resizeListener = `resize.zf.${id}`;
+ var resizeTimeout;
+
+ $(window).off(resizeListener).on(resizeListener, () => {
+ // Delay as timeout to prevent too many calls on resizing
+ clearTimeout(resizeTimeout);
+ resizeTimeout = setTimeout(() => {
+ if (this.$element.hasClass('is-open') || this.isRevealed) {
+ this._emulateFixedPosition(true);
+ }
+ }, 250);
+ });
}
/**
}
}
+ /**
+ * Emulate fixed position for a nested off-canvas element by using fixed height and current document scrollTop.
+ * This is necessary due to the transform property of the content that creates a new local coordinate system.
+ * @param {Boolean} resetHeight - true if the element's height should be set as well (mostly on init and window resize)
+ * @private
+ */
+ _emulateFixedPosition(resetHeight = false) {
+ if (this.nested === true) {
+
+ this.$element.css('top', $(document).scrollTop());
+
+ if (resetHeight === true) {
+ this.$element.height( $(window).height() );
+ }
+ }
+ }
+
/**
* Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
* @param {Boolean} isRevealed - true if element should be revealed.
this.$element.siblings('[data-off-canvas-content]').css('transition-duration', '');
}
+ this._emulateFixedPosition();
+
/**
* Fires when the off-canvas menu opens.
* @event OffCanvas#opened
this.$content.addClass('is-open-' + this.position);
// If `contentScroll` is set to false, add class and disable scrolling on touch devices.
- if (this.options.contentScroll === false) {
+ // If off-canvas element is nested, force `contentScroll` false.
+ if (this.options.contentScroll === false || this.nested === true) {
$('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
this.$element.on('touchstart', this._recordScrollable);
this.$element.on('touchmove', this._stopScrollPropagation);
this.$content.removeClass('is-open-left is-open-top is-open-right is-open-bottom');
// If `contentScroll` is set to false, remove class and re-enable scrolling on touch devices.
- if (this.options.contentScroll === false) {
+ // // If off-canvas element is nested, force `contentScroll` false.
+ if (this.options.contentScroll === false || this.nested === true) {
$('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
this.$element.off('touchstart', this._recordScrollable);
this.$element.off('touchmove', this._stopScrollPropagation);
this.close();
this.$element.off('.zf.trigger .zf.offcanvas');
this.$overlay.off('.zf.offcanvas');
+ $(window).off(this.resizeListener);
}
}