Enh #3928: Add default Stream.initScroll with support of IntersectionObserver

This commit is contained in:
buddh4 2020-03-18 18:55:14 +01:00
parent a8d473355d
commit 4343e23e04
8 changed files with 503 additions and 330 deletions

View File

@ -36,6 +36,7 @@
"npm-asset/select2-bootstrap-theme": "0.1.0-beta.4",
"npm-asset/bootstrap-tour": "0.11.0",
"npm-asset/swiped-events": "1.0.9",
"npm-asset/intersection-observer": "^0.7.0",
"cebe/markdown": "1.0.2",
"firebase/php-jwt": "^5.0",
"jbroadway/urlify": "^1.0",

628
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,7 @@ class AppAsset extends AssetBundle
'humhub\assets\OpenSansAsset',
'humhub\assets\HighlightJsAsset',
'humhub\assets\SwipedEventsAssets',
IntersectionObserverPolyfillAsset::class,
];
/**

View File

@ -0,0 +1,40 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\assets;
use yii\web\AssetBundle;
/**
* animate.css
*
* @author buddha
*/
class IntersectionObserverPolyfillAsset extends AssetBundle
{
/**
* @inheritdoc
*/
public $sourcePath = '@npm/intersection-observer';
/**
* @inheritdoc
*/
public $js = ['intersection-observer.js'];
/**
* @inheritdoc
*/
public $publishOptions = [
'only' => [
'intersection-observer.js'
]
];
}

View File

@ -25,3 +25,4 @@ HumHub Change Log (DEVELOP)
- Enh #3924: Implement `Stream.onUpdateAvailable()`, `Stream.loadUpdate()` and `Stream.options.autoUpdate` to manage stream updates
- Enh #3924: Added `humhub\modules\content\live\NewContent:$streamChannel`
- Enh #3928: Implement auto updates on activity stream
- Enh #3928: Add default `Stream.initScroll` with support of IntersectionObserver

View File

@ -49,8 +49,9 @@ humhub.module('activity', function (module, require, $) {
* @returns {undefined}
*/
var ActivityStream = stream.Stream.extend(function (container, options) {
var that = this;
stream.Stream.call(this, container, {
scrollSupport: true,
scrollOptions: { rootMargin: "30px" },
initLoadCount: STREAM_INIT_COUNT,
loadCount: STREAM_LOAD_COUNT,
autoUpdate: true,
@ -58,6 +59,24 @@ humhub.module('activity', function (module, require, $) {
});
});
ActivityStream.prototype.initEvents = function(events) {
var that = this;
this.on('humhub:stream:afterAddEntries', function() {
if(!that.$content.getNiceScroll().length) {
that.$content.niceScroll({
cursorwidth: "7",
cursorborder: "",
cursorcolor: "#555",
cursoropacitymax: "0.2",
nativeparentscrolling: false,
railpadding: {top: 0, right: 3, left: 0, bottom: 0}
});
} else {
that.$content.getNiceScroll().resize();
}
});
};
ActivityStream.prototype.isUpdateAvailable = function(events) {
var that = this;
@ -83,52 +102,6 @@ humhub.module('activity', function (module, require, $) {
return updatesAvailable;
};
ActivityStream.prototype.initScroll = function () {
if(!this.$content.is(':visible')) {
return;
}
// listen for scrolling event yes or no
var scrolling = true;
var that = this;
this.$content.scroll(function (evt) {
if(that.lastEntryLoaded()) {
return;
}
// save height of the overflow container
var _containerHeight = that.$content.height();
// save scroll height
var _scrollHeight = that.$content.prop("scrollHeight");
// save current scrollbar position
var _currentScrollPosition = that.$content.scrollTop();
// load more activites if current scroll position is near scroll height
if (_currentScrollPosition >= (_scrollHeight - _containerHeight - 30)) {
// checking if ajax loading is necessary or the last entries are already loaded
if (scrolling) {
scrolling = false;
// load more activities
that.loadEntries({loader: true}).then(function() {
that.$content.getNiceScroll().resize();
}).finally(function () {
scrolling = true;
});
}
}
});
// set niceScroll to activity list
that.$content.niceScroll({
cursorwidth: "7",
cursorborder: "",
cursorcolor: "#555",
cursoropacitymax: "0.2",
nativeparentscrolling: false,
railpadding: {top: 0, right: 3, left: 0, bottom: 0}
});
};
ActivityStream.templates = {
streamMessage: '<div class="streamMessage activity"><div class="panel-body">{message}</div></div>'
};

View File

@ -23,6 +23,10 @@ humhub.module('stream.Stream', function (module, require, $) {
var loader = require('ui.loader');
var event = require('event');
var EVENT_AFTER_ADD_ENTRIES = 'humhub:stream:afterAddEntries';
var EVENT_BEFORE_ADD_ENTRIES = 'humhub:stream:beforeAddEntries';
var EVENT_INITIALIZED = 'humhub:stream:initialized';
/**
* Number of initial stream entries loaded when stream is initialized.
* @type Number
@ -69,13 +73,39 @@ humhub.module('stream.Stream', function (module, require, $) {
* @param {type} container id or jQuery object of the stream container
* @returns {undefined}
*/
var Stream = Widget.extend(function (container, options) {
Widget.call(this, container, options);
});
var Stream = Widget.extend();
Stream.prototype.onClear = function() {/* abstract onClear function */};
Stream.prototype.initScroll = function() {/* abstract initScroll function */};
Stream.prototype.initScroll = function() {
if(window.IntersectionObserver && this.options.scrollSupport) {
var options = { root: this.$content[0], rootMargin: "50px" };
options = this.options.scrollOptions ? $.extend(options, this.options.scrollOptions) : options;
var $streamEnd = $('<div class="stream-end"></div>');
this.$content.append($streamEnd);
var that = this;
var observer = new IntersectionObserver(function(entries) {
if(that.preventScrollLoading()) {
return;
}
if(entries.length && entries[0].isIntersecting) {
that.load().finally(function() {
that.state.scrollLock = false;
});
}
}, options);
observer.observe($streamEnd[0]);
}
};
Stream.prototype.preventScrollLoading = function() {
return this.state.scrollLock || !this.canLoadMore() || !this.state.lastRequest || this.state.firstRequest.isSingleEntryRequest()
};
Stream.prototype.initEvents = function() {/* abstract initScroll function */};
@ -100,6 +130,10 @@ humhub.module('stream.Stream', function (module, require, $) {
that.onUpdateAvailable();
});
this.on(EVENT_INITIALIZED, function() {
that.initScroll();
});
};
Stream.prototype.isUpdateAvailable = function(events) {
@ -138,6 +172,7 @@ humhub.module('stream.Stream', function (module, require, $) {
.loadInit()
.then($.proxy(this.handleResponse, this))
.then($.proxy(this.updateTop, this))
.then($.proxy(this.triggerInitEvent, this))
.catch($.proxy(this.handleLoadError, this));
};
@ -155,13 +190,17 @@ humhub.module('stream.Stream', function (module, require, $) {
return response;
};
Stream.prototype.triggerInitEvent = function(response) {
this.trigger(EVENT_INITIALIZED, this);
return response;
};
Stream.prototype.initWidget = function() {
this.$content = this.$.find(this.options.contentSelector);
this.loader = this.options.loader || new StreamLoader(this);
this.initDefaultEvents();
this.initEvents();
this.initFilter();
this.initScroll();
};
Stream.prototype.initFilter = function () {
@ -328,7 +367,7 @@ humhub.module('stream.Stream', function (module, require, $) {
return Promise.resolve();
}
this.$.trigger('humhub:stream:beforeAddEntries', [request.response, request, $result]);
this.$.trigger(EVENT_BEFORE_ADD_ENTRIES, [request.response, request, $result]);
var promise;
@ -341,7 +380,7 @@ humhub.module('stream.Stream', function (module, require, $) {
}
return promise.then(function () {
that.trigger('humhub:stream:afterAddEntries', [request.response, request, $result]);
that.trigger(EVENT_AFTER_ADD_ENTRIES, [request.response, request, $result]);
return request;
});
};
@ -399,8 +438,14 @@ humhub.module('stream.Stream', function (module, require, $) {
* @param html
*/
Stream.prototype.appendEntry = function (html) {
var that = this;
return this._streamEntryAnimation(html, function ($html) {
this.$content.append($html);
var $streamEnd = that.$content.find('.stream-end:first');
if($streamEnd.length) {
$streamEnd.before($html)
} else {
this.$content.append($html);
}
});
};

View File

@ -13,7 +13,7 @@
humhub.module('stream.wall', function (module, require, $) {
var stream = require('stream');
var BaseStream = stream.Stream;
var Stream = stream.Stream;
var Component = require('action').Component;
var Widget = require('ui.widget').Widget;
var event = require('event');
@ -34,13 +34,15 @@ humhub.module('stream.wall', function (module, require, $) {
* @param {type} cfg
* @returns {undefined}
*/
var WallStream = BaseStream.extend(function (container, options) {
var WallStream = Stream.extend(function (container, options) {
options = options || {};
options.scrollSupport = true;
options.scrollOptions = { root: null, rootMargin: "300px" };
options.filter = Component.instance($('#wall-stream-filter-nav'), {stream : this});
options.pinSupport = !this.isDashboardStream();
BaseStream.call(this, container, options);
Stream.call(this, container, options);
if (module.config.horizontalImageScrollOnMobile && /Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent)) {
this.$.addClass('mobile');
@ -225,7 +227,7 @@ humhub.module('stream.wall', function (module, require, $) {
}, 10000);
}
}
};
WallStream.template = {
loadSuppressedButton: '<div class="load-suppressed" style="display:none;"><a href="#" data-action-click="loadSuppressed" data-entry-key="{key}" data-action-block="manual" data-ui-loader><i class="fa fa-chevron-down"></i>&nbsp;&nbsp;{message}&nbsp;&nbsp;<span class="badge">{contentName}</span></a></div>',
@ -247,30 +249,6 @@ humhub.module('stream.wall', function (module, require, $) {
});
};
WallStream.prototype.initScroll = function() {
var that = this;
$(window).off('scroll.wallStream').on('scroll.wallStream', function () {
if(that.state.scrollLock || !that.canLoadMore() || !that.state.lastRequest || that.state.firstRequest.isSingleEntryRequest()) {
return;
}
var $window = $(window);
var windowHeight = $window.height();
var windowBottom = $window.scrollTop() + windowHeight;
var elementBottom = that.$.offset().top + that.$.outerHeight();
var remaining = elementBottom - windowBottom;
if (remaining <= 300) {
that.state.scrollLock = true;
$('#btn-load-more').hide();
setTimeout(function () {
that.loadEntries().finally(function() {
that.state.scrollLock = false;
});
});
}
});
};
WallStream.prototype.onClear = function() {
this.$.find('.back_button_holder').hide();
};