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');