Initial commit
This commit is contained in:
141
lib/assets/javascripts/builder/components/scroll/scroll-view.js
Executable file
141
lib/assets/javascripts/builder/components/scroll/scroll-view.js
Executable file
@@ -0,0 +1,141 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var Ps = require('perfect-scrollbar');
|
||||
var template = require('./scroll.tpl');
|
||||
var MutationObserver = window.MutationObserver;
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'div',
|
||||
className: 'ScrollView',
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.createContentView) throw new Error('A factory createContentView function is required');
|
||||
this.options = opts || {};
|
||||
this._type = opts.type || 'vertical'; // vertical or horizontal
|
||||
this._maxScroll = 0;
|
||||
this._bindedCheckShadows = this._checkShadows.bind(this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._html();
|
||||
|
||||
var view = this.options.createContentView.call(this);
|
||||
this._contentContainer().append(view.render().el);
|
||||
this.addView(view);
|
||||
this._applyScroll();
|
||||
this._updateScrollWhenExist();
|
||||
return this;
|
||||
},
|
||||
|
||||
_html: function () {
|
||||
this.$el.html(template({
|
||||
type: this._type
|
||||
}));
|
||||
|
||||
(this._type === 'horizontal') && this.$el.addClass('ScrollView--horizontal');
|
||||
},
|
||||
|
||||
_contentContainer: function () {
|
||||
return this.$('.js-content');
|
||||
},
|
||||
|
||||
_wrapperContainer: function () {
|
||||
return this.$('.js-wrapper');
|
||||
},
|
||||
|
||||
_updateScrollWhenExist: function () {
|
||||
// Phantom doesn't provide this api for window.
|
||||
if (!MutationObserver) return;
|
||||
|
||||
// even with the changes in PS, we need to check when this element is added to the dom
|
||||
// in order to trigger manually an update.
|
||||
var element = document.body;
|
||||
var self = this._wrapperContainer().get(0);
|
||||
var onMutationObserver = function () {
|
||||
if (element.contains(self)) {
|
||||
Ps.update(self);
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
var observer = new MutationObserver(onMutationObserver);
|
||||
onMutationObserver();
|
||||
|
||||
var config = { subtree: true, childList: true };
|
||||
observer.observe(element, config);
|
||||
},
|
||||
|
||||
_applyScroll: function () {
|
||||
Ps.initialize(this._wrapperContainer().get(0), {
|
||||
wheelSpeed: 2,
|
||||
wheelPropagation: true,
|
||||
stopPropagationOnClick: false,
|
||||
minScrollbarLength: 20,
|
||||
suppressScrollX: this._type === 'vertical',
|
||||
suppressScrollY: this._type === 'horizontal'
|
||||
});
|
||||
|
||||
this._bindScroll();
|
||||
},
|
||||
|
||||
_bindScroll: function () {
|
||||
this._wrapperContainer()
|
||||
.on('ps-dom-change', this._bindedCheckShadows)
|
||||
.on('ps-x-reach-start', this._bindedCheckShadows)
|
||||
.on('ps-x-reach-end', this._bindedCheckShadows)
|
||||
.on('ps-y-reach-start', this._bindedCheckShadows)
|
||||
.on('ps-y-reach-end', this._bindedCheckShadows)
|
||||
.on('ps-scroll-x', this._bindedCheckShadows)
|
||||
.on('ps-scroll-y', this._bindedCheckShadows);
|
||||
},
|
||||
|
||||
_unbindScroll: function () {
|
||||
this._wrapperContainer()
|
||||
.off('ps-dom-change', this._bindedCheckShadows)
|
||||
.off('ps-x-reach-start', this._bindedCheckShadows)
|
||||
.off('ps-x-reach-end', this._bindedCheckShadows)
|
||||
.off('ps-y-reach-start', this._bindedCheckShadows)
|
||||
.off('ps-y-reach-end', this._bindedCheckShadows)
|
||||
.off('ps-scroll-x', this._bindedCheckShadows)
|
||||
.off('ps-scroll-y', this._bindedCheckShadows);
|
||||
},
|
||||
|
||||
_checkShadows: function () {
|
||||
var currentPos;
|
||||
var max;
|
||||
var width;
|
||||
var height;
|
||||
var maxPos;
|
||||
|
||||
if (this._type === 'horizontal') {
|
||||
currentPos = this._wrapperContainer().scrollLeft();
|
||||
max = this._wrapperContainer().get(0).scrollWidth;
|
||||
width = this._wrapperContainer().outerWidth();
|
||||
maxPos = max - width;
|
||||
|
||||
this.$('> .js-leftShadow').toggleClass('is-visible', currentPos > 0);
|
||||
this.$('> .js-rightShadow').toggleClass('is-visible', currentPos < maxPos);
|
||||
} else {
|
||||
currentPos = this._wrapperContainer().scrollTop();
|
||||
max = this._wrapperContainer().get(0).scrollHeight;
|
||||
height = this._wrapperContainer().outerHeight();
|
||||
maxPos = max - height;
|
||||
|
||||
// We use the direct descendant selector to avoid affect others nested view with scroll
|
||||
this.$('> .js-topShadow').toggleClass('is-visible', currentPos > 0);
|
||||
this.$('> .js-bottomShadow').toggleClass('is-visible', currentPos < maxPos);
|
||||
}
|
||||
},
|
||||
|
||||
destroyScroll: function () {
|
||||
if (this._wrapperContainer().length) {
|
||||
this._unbindScroll();
|
||||
Ps.destroy(this._wrapperContainer().get(0));
|
||||
}
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this.destroyScroll();
|
||||
CoreView.prototype.clean.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
10
lib/assets/javascripts/builder/components/scroll/scroll.tpl
Executable file
10
lib/assets/javascripts/builder/components/scroll/scroll.tpl
Executable file
@@ -0,0 +1,10 @@
|
||||
<% if (type === 'vertical') { %>
|
||||
<div class="ScrollView-shadow ScrollView-shadow--top js-topShadow"></div>
|
||||
<div class="ScrollView-shadow ScrollView-shadow--bottom js-bottomShadow"></div>
|
||||
<% } else { %>
|
||||
<div class="Carousel-shadow Carousel-shadow--left js-leftShadow"></div>
|
||||
<div class="Carousel-shadow Carousel-shadow--right js-rightShadow"></div>
|
||||
<% } %>
|
||||
<div class="ScrollView-wrapper js-wrapper js-perfect-scroll">
|
||||
<div class="ScrollView-content js-content"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user