diff --git a/OHIFViewer/.meteor/packages b/OHIFViewer/.meteor/packages index edd4b466c..23b2c3b6b 100644 --- a/OHIFViewer/.meteor/packages +++ b/OHIFViewer/.meteor/packages @@ -41,3 +41,4 @@ standard-minifier-css@1.1.8 standard-minifier-js@1.1.8 aldeed:simple-schema johdirr:meteor-git-rev +aldeed:template-extension diff --git a/OHIFViewer/.meteor/versions b/OHIFViewer/.meteor/versions index 4bc7a8cbb..94eb784aa 100644 --- a/OHIFViewer/.meteor/versions +++ b/OHIFViewer/.meteor/versions @@ -1,4 +1,5 @@ aldeed:simple-schema@1.5.3 +aldeed:template-extension@4.0.0 allow-deny@1.0.5 arsnebula:reactive-promise@0.9.1 autoupdate@1.3.11 diff --git a/Packages/worklist/client/components/worklistPagination/worklistPagination.html b/Packages/worklist/client/components/worklistPagination/worklistPagination.html new file mode 100644 index 000000000..050e4ec6f --- /dev/null +++ b/Packages/worklist/client/components/worklistPagination/worklistPagination.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/Packages/worklist/client/components/worklistPagination/worklistPagination.js b/Packages/worklist/client/components/worklistPagination/worklistPagination.js new file mode 100644 index 000000000..4409a471b --- /dev/null +++ b/Packages/worklist/client/components/worklistPagination/worklistPagination.js @@ -0,0 +1,58 @@ +import { Template } from 'meteor/templating'; + +import './worklistPagination.html'; + +const visiblePages = 10; +Template.worklistPagination.onCreated(function() { + let instance = Template.instance(); + // replace parentVariable with the name of the instance variable + instance.parent = this.parent(1); +}); + +Template.worklistPagination.onRendered(function() { + const instance = Template.instance(); + const $paginationControl = instance.$('#pagination'); + + // Track changes on recordCount and rowsPerPage + instance.autorun(function() { + const recordCount = instance.parent.recordCount.get(); + const rowsPerPage = instance.parent.rowsPerPage.get(); + + // Destroy plugin if exists + if ($paginationControl.data().twbsPagination) { + $paginationControl.twbsPagination('destroy'); + } + + if (recordCount && rowsPerPage) { + const totalPageNumber = Math.ceil(recordCount / rowsPerPage); + + // Initialize plugin + $paginationControl.twbsPagination({ + totalPages: totalPageNumber, + visiblePages: visiblePages, + onPageClick: function (event, page) { + // Update currentPage + // Decrease page by 1 to set currentPage + // Since reactive table current page index starts by 0 + instance.parent.currentPage.set(page - 1); + } + }); + } + }); +}); + +Template.worklistPagination.helpers({ + recordCount() { + const instance = Template.instance(); + return instance.parent.recordCount.get(); + } +}); + +Template.worklistPagination.events({ + 'change .js-select-rows-per-page'(event, instance) { + const rowsPerPage = $(event.currentTarget).val(); + + // Update rowsPerPage of parent + instance.parent.rowsPerPage.set(parseInt(rowsPerPage, 10)); + } +}); diff --git a/Packages/worklist/client/components/worklistPagination/worklistPagination.styl b/Packages/worklist/client/components/worklistPagination/worklistPagination.styl new file mode 100644 index 000000000..1cb183ff9 --- /dev/null +++ b/Packages/worklist/client/components/worklistPagination/worklistPagination.styl @@ -0,0 +1,39 @@ +@import "{design}/app" + +.worklistPagination + font-size: 13px + font-weight: normal !important + + .rows-per-page + padding-top: 20px + + label + font-weight: normal + + select + background-color: $primaryBackgroundColor + color: white + + .page-number + text-align: right + + label + font-weight: normal + + ul#pagination + + li + a + padding: 4px 8px + background-color: $primaryBackgroundColor + color: white + + &:hover + color: $activeColor + + .active + + a + background-color: $uiGrayDarker + color: white + diff --git a/Packages/worklist/client/components/worklistResult/worklistResult.html b/Packages/worklist/client/components/worklistResult/worklistResult.html index 3fe695877..b74813f4b 100644 --- a/Packages/worklist/client/components/worklistResult/worklistResult.html +++ b/Packages/worklist/client/components/worklistResult/worklistResult.html @@ -92,6 +92,10 @@ {{/each}} + + + {{> worklistPagination }} + {{#if session "showLoadingText"}} {{>loadingText}} {{ else }} diff --git a/Packages/worklist/client/components/worklistResult/worklistResult.js b/Packages/worklist/client/components/worklistResult/worklistResult.js index 5edb2c79c..828081518 100644 --- a/Packages/worklist/client/components/worklistResult/worklistResult.js +++ b/Packages/worklist/client/components/worklistResult/worklistResult.js @@ -6,19 +6,37 @@ Template.worklistResult.helpers({ * by Patient name and Study Date in Ascending order. */ studies() { - const sortOption = Session.get('sortOption'); - if (sortOption) { - return WorklistStudies.find({}, { - sort: sortOption - }); + const instance = Template.instance(); + let studies; + let sortOption = { + patientName: 1, + studyDate: 1 + }; + + // Update sort option if session is defined + if (Session.get('sortOption')) { + sortOption = Session.get('sortOption'); } - return WorklistStudies.find({}, { - sort: { - patientName: 1, - studyDate: 1 - } - }); + // Pagination parameters + const rowsPerPage = instance.rowsPerPage.get(); + const currentPage = instance.currentPage.get(); + const offset = rowsPerPage * currentPage; + const limit = offset + rowsPerPage; + + studies = WorklistStudies.find({}, { + sort: sortOption + }).fetch(); + + if (!studies) { + return; + } + + // Update record count + instance.recordCount.set(studies.length); + + // Limit studies + return studies.slice(offset, limit); }, numberOfStudies() { @@ -163,6 +181,15 @@ Template.worklistResult.onCreated(() => { instance.sortOption = new ReactiveVar(); instance.sortingColumns = new ReactiveDict(); + // Pagination parameters + + // Rows per page is 25 as default + instance.rowsPerPage = new ReactiveVar(25); + + // Set currentPage indexed 0 + instance.currentPage = new ReactiveVar(0); + instance.recordCount = new ReactiveVar(); + // Set sortOption const sortOptionSession = Session.get('sortOption'); if (sortOptionSession) { diff --git a/Packages/worklist/client/lib/jquery.twbsPagination/jquery.twbsPagination.min.js b/Packages/worklist/client/lib/jquery.twbsPagination/jquery.twbsPagination.min.js new file mode 100644 index 000000000..7cc71f9c4 --- /dev/null +++ b/Packages/worklist/client/lib/jquery.twbsPagination/jquery.twbsPagination.min.js @@ -0,0 +1,9 @@ +/* + * jQuery Bootstrap Pagination v1.3.1 + * https://github.com/esimakin/twbs-pagination + * + * Copyright 2014-2015 Eugene Simakin + * Released under Apache 2.0 license + * http://apache.org/licenses/LICENSE-2.0.html + */ +!function(a,b,c,d){"use strict";var e=a.fn.twbsPagination,f=function(c,d){if(this.$element=a(c),this.options=a.extend({},a.fn.twbsPagination.defaults,d),this.options.startPage<1||this.options.startPage>this.options.totalPages)throw new Error("Start page option is incorrect");if(this.options.totalPages=parseInt(this.options.totalPages),isNaN(this.options.totalPages))throw new Error("Total pages option is not correct!");if(this.options.visiblePages=parseInt(this.options.visiblePages),isNaN(this.options.visiblePages))throw new Error("Visible pages option is not correct!");if(this.options.totalPages"),this.$listContainer.addClass(this.options.paginationClass),"UL"!==g&&this.$element.append(this.$listContainer),this.render(this.getPages(this.options.startPage)),this.setupEvents(),this.options.initiateStartPageClick&&this.$element.trigger("page",this.options.startPage),this};f.prototype={constructor:f,destroy:function(){return this.$element.empty(),this.$element.removeData("twbs-pagination"),this.$element.off("page"),this},show:function(a){if(1>a||a>this.options.totalPages)throw new Error("Page is incorrect.");return this.render(this.getPages(a)),this.setupEvents(),this.$element.trigger("page",a),this},buildListItems:function(a){var b=[];if(this.options.first&&b.push(this.buildItem("first",1)),this.options.prev){var c=a.currentPage>1?a.currentPage-1:this.options.loop?this.options.totalPages:1;b.push(this.buildItem("prev",c))}for(var d=0;d"),e=a(""),f=null;switch(b){case"page":f=c,d.addClass(this.options.pageClass);break;case"first":f=this.options.first,d.addClass(this.options.firstClass);break;case"prev":f=this.options.prev,d.addClass(this.options.prevClass);break;case"next":f=this.options.next,d.addClass(this.options.nextClass);break;case"last":f=this.options.last,d.addClass(this.options.lastClass)}return d.data("page",c),d.data("page-type",b),d.append(e.attr("href",this.makeHref(c)).html(f)),d},getPages:function(a){var b=[],c=Math.floor(this.options.visiblePages/2),d=a-c+1-this.options.visiblePages%2,e=a+c;0>=d&&(d=1,e=this.options.visiblePages),e>this.options.totalPages&&(d=this.options.totalPages-this.options.visiblePages+1,e=this.options.totalPages);for(var f=d;e>=f;)b.push(f),f++;return{currentPage:a,numeric:b}},render:function(b){var c=this;this.$listContainer.children().remove(),this.$listContainer.append(this.buildListItems(b)),this.$listContainer.children().each(function(){var d=a(this),e=d.data("page-type");switch(e){case"page":d.data("page")===b.currentPage&&d.addClass(c.options.activeClass);break;case"first":d.toggleClass(c.options.disabledClass,1===b.currentPage);break;case"last":d.toggleClass(c.options.disabledClass,b.currentPage===c.options.totalPages);break;case"prev":d.toggleClass(c.options.disabledClass,!c.options.loop&&1===b.currentPage);break;case"next":d.toggleClass(c.options.disabledClass,!c.options.loop&&b.currentPage===c.options.totalPages)}})},setupEvents:function(){var b=this;this.$listContainer.find("li").each(function(){var c=a(this);return c.off(),c.hasClass(b.options.disabledClass)||c.hasClass(b.options.activeClass)?void c.on("click",!1):void c.click(function(a){!b.options.href&&a.preventDefault(),b.show(parseInt(c.data("page")))})})},makeHref:function(a){return this.options.href?this.options.href.replace(this.options.hrefVariable,a):"#"}},a.fn.twbsPagination=function(b){var c,e=Array.prototype.slice.call(arguments,1),g=a(this),h=g.data("twbs-pagination"),i="object"==typeof b&&b;return h||g.data("twbs-pagination",h=new f(this,i)),"string"==typeof b&&(c=h[b].apply(h,e)),c===d?g:c},a.fn.twbsPagination.defaults={totalPages:0,startPage:1,visiblePages:5,initiateStartPageClick:!0,href:!1,hrefVariable:"{{number}}",first:"First",prev:"Previous",next:"Next",last:"Last",loop:!1,onPageClick:null,paginationClass:"pagination",nextClass:"next",prevClass:"prev",lastClass:"last",firstClass:"first",pageClass:"page",activeClass:"active",disabledClass:"disabled"},a.fn.twbsPagination.Constructor=f,a.fn.twbsPagination.noConflict=function(){return a.fn.twbsPagination=e,this}}(window.jQuery,window,document); \ No newline at end of file diff --git a/Packages/worklist/package.js b/Packages/worklist/package.js index 520b5106e..214f38c0d 100644 --- a/Packages/worklist/package.js +++ b/Packages/worklist/package.js @@ -69,6 +69,10 @@ Package.onUse(function (api) { api.addFiles('client/components/progressDialog/progressDialog.html', 'client'); api.addFiles('client/components/progressDialog/progressDialog.styl', 'client'); api.addFiles('client/components/progressDialog/progressDialog.js', 'client'); + + api.addFiles('client/components/worklistPagination/worklistPagination.html', 'client'); + api.addFiles('client/components/worklistPagination/worklistPagination.styl', 'client'); + api.addFiles('client/components/worklistPagination/worklistPagination.js', 'client'); // Client-side library functions api.addFiles('client/lib/getStudyMetadata.js', 'client'); @@ -79,6 +83,7 @@ Package.onUse(function (api) { api.addFiles('client/lib/worklist.js', 'client'); api.addFiles('client/lib/queryStudies.js', 'client'); api.addFiles('client/lib/importStudies.js', 'client'); + api.addFiles('client/lib/jquery.twbsPagination/jquery.twbsPagination.min.js', 'client'); // Server-side functions api.addFiles('server/publications.js', 'server');