diff options
-rw-r--r-- | CHANGELOG.md | 17 | ||||
-rw-r--r-- | Stackerfile.yml | 2 | ||||
-rw-r--r-- | client/components/lists/list.styl | 3 | ||||
-rw-r--r-- | client/components/lists/listBody.jade | 12 | ||||
-rw-r--r-- | client/components/lists/listBody.js | 83 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | sandstorm-pkgdef.capnp | 4 |
7 files changed, 117 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index de9ec68f..1d101b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +# v2.13 2019-02-01 Wekan release + +This release adds the following new features with Apache I-CLA, thanks to bentiss: + +- [Use infinite-scrolling on lists](https://github.com/wekan/wekan/pull/2144). + This allows to reduce the loading time of a big board. + Note that there is an infinite scroll implementation in the mixins, + but this doesn't fit well as the cards in the list can have arbitrary + height. + The idea to rely on the visibility of a spinner is based on + http://www.meteorpedia.com/read/Infinite_Scrolling +- [When writing to minicard, press Shift-Enter on minicard to go to next line + below](https://github.com/wekan/wekan/commit/7a35099fb9778d5f3656a57c74af426cfb20fba3), + to continue writing on same minicard 2nd line. + +Thanks to GitHub user bentiss for contributions. + # v2.12 2019-01-31 Wekan release This release fixes the following bugs: diff --git a/Stackerfile.yml b/Stackerfile.yml index f0f61101..523ba2b4 100644 --- a/Stackerfile.yml +++ b/Stackerfile.yml @@ -1,5 +1,5 @@ appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928 -appVersion: "v2.12.0" +appVersion: "v2.13.0" files: userUploads: - README.md diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl index 51ade73c..70502083 100644 --- a/client/components/lists/list.styl +++ b/client/components/lists/list.styl @@ -211,6 +211,9 @@ max-height: 250px overflow: hidden +.sk-spinner-list + margin-top: unset !important + list-header-color(background, color...) border-bottom: 6px solid background diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade index c6c9b204..f030833b 100644 --- a/client/components/lists/listBody.jade +++ b/client/components/lists/listBody.jade @@ -4,7 +4,7 @@ template(name="listBody") if cards.count +inlinedForm(autoclose=false position="top") +addCardForm(listId=_id position="top") - each (cards (idOrNull ../../_id)) + each (cardsWithLimit (idOrNull ../../_id)) a.minicard-wrapper.js-minicard(href=absoluteUrl class="{{#if cardIsSelected}}is-selected{{/if}}" class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") @@ -12,6 +12,16 @@ template(name="listBody") .materialCheckBox.multi-selection-checkbox.js-toggle-multi-selection( class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") +minicard(this) + if (showSpinner (idOrNull ../../_id)) + .sk-spinner.sk-spinner-wave.sk-spinner-list( + class=currentBoard.colorClass + id="showMoreResults") + .sk-rect1 + .sk-rect2 + .sk-rect3 + .sk-rect4 + .sk-rect5 + if canSeeAddCard +inlinedForm(autoclose=false position="bottom") +addCardForm(listId=_id position="bottom") diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js index 1001f3bc..0f5caac5 100644 --- a/client/components/lists/listBody.js +++ b/client/components/lists/listBody.js @@ -1,6 +1,34 @@ const subManager = new SubsManager(); +const InfiniteScrollIter = 10; BlazeComponent.extendComponent({ + onCreated() { + // for infinite scrolling + this.cardlimit = new ReactiveVar(InfiniteScrollIter); + }, + + onRendered() { + const domElement = this.find('.js-perfect-scrollbar'); + + this.$(domElement).on('scroll', () => this.updateList(domElement)); + $(window).on(`resize.${this.data().listId}`, () => this.updateList(domElement)); + + // we add a Mutation Observer to allow propagations of cardlimit + // when the spinner stays in the current view (infinite scrolling) + this.mutationObserver = new MutationObserver(() => this.updateList(domElement)); + + this.mutationObserver.observe(domElement, { + childList: true, + }); + + this.updateList(domElement); + }, + + onDestroyed() { + $(window).off(`resize.${this.data().listId}`); + this.mutationObserver.disconnect(); + }, + mixins() { return [Mixins.PerfectScrollbar]; }, @@ -60,6 +88,13 @@ BlazeComponent.extendComponent({ type: 'cardType-card', }); + // if the displayed card count is less than the total cards in the list, + // we need to increment the displayed card count to prevent the spinner + // to appear + const cardCount = this.data().cards(this.idOrNull(swimlaneId)).count(); + if (this.cardlimit.get() < cardCount) { + this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter); + } // In case the filter is active we need to add the newly inserted card in // the list of exceptions -- cards that are not filtered. Otherwise the @@ -119,6 +154,52 @@ BlazeComponent.extendComponent({ return undefined; }, + cardsWithLimit(swimlaneId) { + const limit = this.cardlimit.get(); + const selector = { + listId: this.currentData()._id, + archived: false, + }; + if (swimlaneId) + selector.swimlaneId = swimlaneId; + return Cards.find(Filter.mongoSelector(selector), { + sort: ['sort'], + limit, + }); + }, + + spinnerInView(container) { + const parentViewHeight = container.clientHeight; + const bottomViewPosition = container.scrollTop + parentViewHeight; + + const spinner = this.find('.sk-spinner-list'); + + const threshold = spinner.offsetTop; + + return bottomViewPosition > threshold; + }, + + showSpinner(swimlaneId) { + const list = Template.currentData(); + return list.cards(swimlaneId).count() > this.cardlimit.get(); + }, + + updateList(container) { + // first, if the spinner is not rendered, we have reached the end of + // the list of cards, so skip and disable firing the events + const target = this.find('.sk-spinner-list'); + if (!target) { + this.$(container).off('scroll'); + $(window).off(`resize.${this.data().listId}`); + return; + } + + if (this.spinnerInView(container)) { + this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter); + Ps.update(container); + } + }, + canSeeAddCard() { return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); }, @@ -179,7 +260,7 @@ BlazeComponent.extendComponent({ pressKey(evt) { // Pressing Enter should submit the card - if (evt.keyCode === 13) { + if (evt.keyCode === 13 && !evt.shiftKey) { evt.preventDefault(); const $form = $(evt.currentTarget).closest('form'); // XXX For some reason $form.submit() does not work (it's probably a bug diff --git a/package.json b/package.json index 5209c96b..94dd303f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wekan", - "version": "v2.12.0", + "version": "v2.13.0", "description": "Open-Source kanban", "private": true, "scripts": { diff --git a/sandstorm-pkgdef.capnp b/sandstorm-pkgdef.capnp index d8d80938..19e81a74 100644 --- a/sandstorm-pkgdef.capnp +++ b/sandstorm-pkgdef.capnp @@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Wekan"), # The name of the app as it is displayed to the user. - appVersion = 214, + appVersion = 215, # Increment this for every release. - appMarketingVersion = (defaultText = "2.12.0~2019-01-31"), + appMarketingVersion = (defaultText = "2.13.0~2019-02-01"), # Human-readable presentation of the app version. minUpgradableAppVersion = 0, |