From b14ba5b55eae8bc5e77beef53f3e1c74090318f9 Mon Sep 17 00:00:00 2001 From: Garren Smith Date: Tue, 17 Sep 2013 16:23:32 +0200 Subject: add typeahead view --- src/fauxton/app/addons/replication/views.js | 534 +++++++++++++------------- src/fauxton/app/modules/databases/views.js | 36 +- src/fauxton/app/modules/documents/views.js | 6 +- src/fauxton/app/modules/fauxton/components.js | 138 +++++++ src/fauxton/app/modules/fauxton/paginate.js | 92 ----- 5 files changed, 408 insertions(+), 398 deletions(-) create mode 100644 src/fauxton/app/modules/fauxton/components.js delete mode 100644 src/fauxton/app/modules/fauxton/paginate.js diff --git a/src/fauxton/app/addons/replication/views.js b/src/fauxton/app/addons/replication/views.js index bd3daa157..f4b96fd40 100644 --- a/src/fauxton/app/addons/replication/views.js +++ b/src/fauxton/app/addons/replication/views.js @@ -11,303 +11,285 @@ // the License. define([ - "app", - "api", - "addons/replication/resources" + "app", + "api", + "modules/fauxton/components", + "addons/replication/resources" ], -function(app, FauxtonAPI, replication) { +function(app, FauxtonAPI, Components, replication) { var View = {}, - Events ={}, - pollingInfo ={ - rate: 5, - intervalId: null - }; + Events ={}, + pollingInfo ={ + rate: 5, + intervalId: null + }; _.extend(Events, Backbone.Events); - -// NOTES: http://wiki.apache.org/couchdb/Replication -// Replication form view is huge -// ----------------------------------- -// afterRender: autocomplete on the target input field -// beforeRender: add the status table -// disableFields: disable non active fields on submit -// enableFields: enable field when radio btns are clicked -// establish: get the DB list for autocomplete -// formValidation: make sure fields aren't empty -// showProgress: make a call to active_tasks model and show only replication types. Poll every 5 seconds. (make this it's own view) -// startReplication: saves to the model, starts replication -// submit: form submit handler -// swapFields: change to and from target -// toggleAdvancedOptions: toggle advanced + // NOTES: http://wiki.apache.org/couchdb/Replication + + // Replication form view is huge + // ----------------------------------- + // afterRender: autocomplete on the target input field + // beforeRender: add the status table + // disableFields: disable non active fields on submit + // enableFields: enable field when radio btns are clicked + // establish: get the DB list for autocomplete + // formValidation: make sure fields aren't empty + // showProgress: make a call to active_tasks model and show only replication types. Poll every 5 seconds. (make this it's own view) + // startReplication: saves to the model, starts replication + // submit: form submit handler + // swapFields: change to and from target + // toggleAdvancedOptions: toggle advanced View.ReplicationForm = FauxtonAPI.View.extend({ - template: "addons/replication/templates/form", - events: { - "submit #replication": "validate", - "click .btn-group .btn": "showFields", - "click .swap": "swapFields", - "click .options": "toggleAdvancedOptions" - }, - initialize: function(options){ - this.status = options.status; - this.selectedDB = options.selectedDB; - this.newRepModel = new replication.Replicate({}); - }, - afterRender: function(){ - var dbLimit = 30; - var ajaxReq; - //re-using what we have on DB search - this.$el.find("input#to_name").typeahead({ - source: function(query, process) { - var url = [ - app.host, - "/_all_dbs?startkey=%22", - query, - "%22&endkey=%22", - query, - "\u9999%22&limit=", - dbLimit - ].join(''); - if (ajaxReq) ajaxReq.abort(); - ajaxReq = $.ajax({ - url: url, - dataType: 'json', - success: function(data) { - process(data); - } - }); - } + template: "addons/replication/templates/form", + events: { + "submit #replication": "validate", + "click .btn-group .btn": "showFields", + "click .swap": "swapFields", + "click .options": "toggleAdvancedOptions" + }, + initialize: function(options){ + this.status = options.status; + this.selectedDB = options.selectedDB; + this.newRepModel = new replication.Replicate({}); + }, + afterRender: function(){ + this.dbSearchTypeahead = new Components.DbSearchTypeahead({ + dbLimit: 30, + el: "input#to_name" }); - }, + this.dbSearchTypeahead.render(); - beforeRender: function(){ - this.insertView("#replicationStatus", new View.ReplicationList({ - collection: this.status - })); - }, - cleanup: function(){ - clearInterval(pollingInfo.intervalId); - }, - enableFields: function(){ - this.$el.find('input','select').attr('disabled',false); - }, - disableFields: function(){ - this.$el.find('input:hidden','select:hidden').attr('disabled',true); - }, - showFields: function(e){ - var $currentTarget = this.$(e.currentTarget), - targetVal = $currentTarget.val(); + }, - if (targetVal === "local"){ - $currentTarget.parents('.form_set').addClass('local'); - }else{ - $currentTarget.parents('.form_set').removeClass('local'); - } - }, - establish: function(){ - return [ this.collection.fetch(), this.status.fetch()]; - }, - validate: function(e){ - e.preventDefault(); - var notification; - if (this.formValidation()){ - notification = FauxtonAPI.addNotification({ - msg: "Please enter every field.", - type: "error", - clear: true - }); - }else if (this.$('input#to_name').is(':visible') && !this.$('input[name=create_target]').is(':checked')){ - var alreadyExists = this.collection.where({"name":this.$('input#to_name').val()}); - if (alreadyExists.length === 0){ - notification = FauxtonAPI.addNotification({ - msg: "This database doesn't exist. Check create target if you want to create it.", - type: "error", - clear: true - }); - } - }else{ - this.submit(e); - } - }, - formValidation: function(e){ - var $remote = this.$el.find('input:visible'), + beforeRender: function(){ + this.insertView("#replicationStatus", new View.ReplicationList({ + collection: this.status + })); + }, + cleanup: function(){ + clearInterval(pollingInfo.intervalId); + }, + enableFields: function(){ + this.$el.find('input','select').attr('disabled',false); + }, + disableFields: function(){ + this.$el.find('input:hidden','select:hidden').attr('disabled',true); + }, + showFields: function(e){ + var $currentTarget = this.$(e.currentTarget), + targetVal = $currentTarget.val(); + + if (targetVal === "local"){ + $currentTarget.parents('.form_set').addClass('local'); + }else{ + $currentTarget.parents('.form_set').removeClass('local'); + } + }, + establish: function(){ + return [ this.collection.fetch(), this.status.fetch()]; + }, + validate: function(e){ + e.preventDefault(); + var notification; + if (this.formValidation()){ + notification = FauxtonAPI.addNotification({ + msg: "Please enter every field.", + type: "error", + clear: true + }); + }else if (this.$('input#to_name').is(':visible') && !this.$('input[name=create_target]').is(':checked')){ + var alreadyExists = this.collection.where({"name":this.$('input#to_name').val()}); + if (alreadyExists.length === 0){ + notification = FauxtonAPI.addNotification({ + msg: "This database doesn't exist. Check create target if you want to create it.", + type: "error", + clear: true + }); + } + }else{ + this.submit(e); + } + }, + formValidation: function(e){ + var $remote = this.$el.find('input:visible'), error = false; for(var i=0; i<$remote.length; i++){ - if ($remote[i].value =="http://" || $remote[i].value ===""){ - error = true; - } + if ($remote[i].value =="http://" || $remote[i].value ===""){ + error = true; + } } - return error; - }, - serialize: function(){ - return { - databases: this.collection.toJSON(), - selectedDB: this.selectedDB - }; - }, - startReplication: function(json){ - var that = this; - this.newRepModel.save(json,{ - success: function(resp){ - var notification = FauxtonAPI.addNotification({ - msg: "Replication from "+resp.get('source')+" to "+ resp.get('target')+" has begun.", - type: "success", - clear: true - }); - that.updateButtonText(false); - Events.trigger('update:tasks'); - }, - error: function(model, xhr, options){ - var errorMessage = JSON.parse(xhr.responseText); - var notification = FauxtonAPI.addNotification({ - msg: errorMessage.reason, - type: "error", - clear: true - }); - that.updateButtonText(false); - } - }); - this.enableFields(); - }, - updateButtonText: function(wait){ - var $button = this.$('#replication button[type=submit]'); - if(wait){ - $button.text('Starting replication...').attr('disabled', true); - } else { - $button.text('Replication').attr('disabled', false); - } - }, - submit: function(e){ - this.disableFields(); - var formJSON = {}; - _.map(this.$(e.currentTarget).serializeArray(), function(formData){ - if(formData.value !== ''){ - formJSON[formData.name] = (formData.value ==="true"? true: formData.value.replace(/\s/g, '').toLowerCase()); - - } - }); + return error; + }, + serialize: function(){ + return { + databases: this.collection.toJSON(), + selectedDB: this.selectedDB + }; + }, + startReplication: function(json){ + var that = this; + this.newRepModel.save(json,{ + success: function(resp){ + var notification = FauxtonAPI.addNotification({ + msg: "Replication from "+resp.get('source')+" to "+ resp.get('target')+" has begun.", + type: "success", + clear: true + }); + that.updateButtonText(false); + Events.trigger('update:tasks'); + }, + error: function(model, xhr, options){ + var errorMessage = JSON.parse(xhr.responseText); + var notification = FauxtonAPI.addNotification({ + msg: errorMessage.reason, + type: "error", + clear: true + }); + that.updateButtonText(false); + } + }); + this.enableFields(); + }, + updateButtonText: function(wait){ + var $button = this.$('#replication button[type=submit]'); + if(wait){ + $button.text('Starting replication...').attr('disabled', true); + } else { + $button.text('Replication').attr('disabled', false); + } + }, + submit: function(e){ + this.disableFields(); + var formJSON = {}; + _.map(this.$(e.currentTarget).serializeArray(), function(formData){ + if(formData.value !== ''){ + formJSON[formData.name] = (formData.value ==="true"? true: formData.value.replace(/\s/g, '').toLowerCase()); + } + }); - this.updateButtonText(true); - this.startReplication(formJSON); - }, - swapFields: function(e){ - e.preventDefault(); - //WALL O' VARIABLES - var $fromSelect = this.$('#from_name'), - $toSelect = this.$('#to_name'), - $toInput = this.$('#to_url'), - $fromInput = this.$('#from_url'), - fromSelectVal = $fromSelect.val(), - fromInputVal = $fromInput.val(), - toSelectVal = $toSelect.val(), - toInputVal = $toInput.val(); + this.updateButtonText(true); + this.startReplication(formJSON); + }, + swapFields: function(e){ + e.preventDefault(); + //WALL O' VARIABLES + var $fromSelect = this.$('#from_name'), + $toSelect = this.$('#to_name'), + $toInput = this.$('#to_url'), + $fromInput = this.$('#from_url'), + fromSelectVal = $fromSelect.val(), + fromInputVal = $fromInput.val(), + toSelectVal = $toSelect.val(), + toInputVal = $toInput.val(); - $fromSelect.val(toSelectVal); - $toSelect.val(fromSelectVal); + $fromSelect.val(toSelectVal); + $toSelect.val(fromSelectVal); - $fromInput.val(toInputVal); - $toInput.val(fromInputVal); - } + $fromInput.val(toInputVal); + $toInput.val(fromInputVal); + } }); -View.ReplicationList = FauxtonAPI.View.extend({ - tagName: "ul", - initialize: function(){ - Events.bind('update:tasks', this.establish, this); - this.listenTo(this.collection, "reset", this.render); - this.$el.prepend("
  • Active Replication Tasks

  • "); - }, - establish: function(){ - return [this.collection.fetch({reset: true})]; - }, - setPolling: function(){ - var that = this; - this.cleanup(); - pollingInfo.intervalId = setInterval(function() { - that.establish(); - }, pollingInfo.rate*1000); - }, - cleanup: function(){ - clearInterval(pollingInfo.intervalId); - }, - beforeRender: function(){ - this.collection.forEach(function(item) { - this.insertView(new View.replicationItem({ - model: item - })); - }, this); - }, - showHeader: function(){ - if (this.collection.length > 0){ - this.$el.parent().addClass('showHeader'); - } else { - this.$el.parent().removeClass('showHeader'); - } - }, - afterRender: function(){ - this.showHeader(); - this.setPolling(); - } -}); + View.ReplicationList = FauxtonAPI.View.extend({ + tagName: "ul", + initialize: function(){ + Events.bind('update:tasks', this.establish, this); + this.listenTo(this.collection, "reset", this.render); + this.$el.prepend("
  • Active Replication Tasks

  • "); + }, + establish: function(){ + return [this.collection.fetch({reset: true})]; + }, + setPolling: function(){ + var that = this; + this.cleanup(); + pollingInfo.intervalId = setInterval(function() { + that.establish(); + }, pollingInfo.rate*1000); + }, + cleanup: function(){ + clearInterval(pollingInfo.intervalId); + }, + beforeRender: function(){ + this.collection.forEach(function(item) { + this.insertView(new View.replicationItem({ + model: item + })); + }, this); + }, + showHeader: function(){ + if (this.collection.length > 0){ + this.$el.parent().addClass('showHeader'); + } else { + this.$el.parent().removeClass('showHeader'); + } + }, + afterRender: function(){ + this.showHeader(); + this.setPolling(); + } + }); - //make this a table row item. - View.replicationItem = FauxtonAPI.View.extend({ - tagName: "li", - className: "row", - template: "addons/replication/templates/progress", - events: { - "click .cancel": "cancelReplication" - }, - initialize: function(){ - this.newRepModel = new replication.Replicate({}); - }, - establish: function(){ - return [this.model.fetch()]; - }, - cancelReplication: function(e){ - //need to pass "cancel": true with source & target - var $currentTarget = this.$(e.currentTarget), - repID = $currentTarget.attr('data-rep-id'); - this.newRepModel.save({ - "replication_id": repID, - "cancel": true - }, - { - success: function(model, xhr, options){ - var notification = FauxtonAPI.addNotification({ - msg: "Replication stopped.", - type: "success", - clear: true - }); - }, - error: function(model, xhr, options){ - var errorMessage = JSON.parse(xhr.responseText); - var notification = FauxtonAPI.addNotification({ - msg: errorMessage.reason, - type: "error", - clear: true - }); - } - }); - }, - afterRender: function(){ - if (this.model.get('continuous')){ - this.$el.addClass('continuous'); - } - }, - serialize: function(){ - return { - progress: this.model.get('progress'), - target: this.model.get('target'), - source: this.model.get('source'), - continuous: this.model.get('continuous'), - repid: this.model.get('replication_id') - }; - } - }); + //make this a table row item. + View.replicationItem = FauxtonAPI.View.extend({ + tagName: "li", + className: "row", + template: "addons/replication/templates/progress", + events: { + "click .cancel": "cancelReplication" + }, + initialize: function(){ + this.newRepModel = new replication.Replicate({}); + }, + establish: function(){ + return [this.model.fetch()]; + }, + cancelReplication: function(e){ + //need to pass "cancel": true with source & target + var $currentTarget = this.$(e.currentTarget), + repID = $currentTarget.attr('data-rep-id'); + this.newRepModel.save({ + "replication_id": repID, + "cancel": true + }, + { + success: function(model, xhr, options){ + var notification = FauxtonAPI.addNotification({ + msg: "Replication stopped.", + type: "success", + clear: true + }); + }, + error: function(model, xhr, options){ + var errorMessage = JSON.parse(xhr.responseText); + var notification = FauxtonAPI.addNotification({ + msg: errorMessage.reason, + type: "error", + clear: true + }); + } + }); + }, + afterRender: function(){ + if (this.model.get('continuous')){ + this.$el.addClass('continuous'); + } + }, + serialize: function(){ + return { + progress: this.model.get('progress'), + target: this.model.get('target'), + source: this.model.get('source'), + continuous: this.model.get('continuous'), + repid: this.model.get('replication_id') + }; + } + }); return View; }); diff --git a/src/fauxton/app/modules/databases/views.js b/src/fauxton/app/modules/databases/views.js index ef7584127..749f79c57 100644 --- a/src/fauxton/app/modules/databases/views.js +++ b/src/fauxton/app/modules/databases/views.js @@ -13,11 +13,11 @@ define([ "app", - "modules/fauxton/paginate", - "api" + "modules/fauxton/components", + "api", ], -function(app, Paginate, FauxtonAPI) { +function(app, Components, FauxtonAPI) { var Views = {}; Views.Item = FauxtonAPI.View.extend({ @@ -83,7 +83,7 @@ function(app, Paginate, FauxtonAPI) { })); }, this); - this.insertView("#database-pagination", new Paginate.Pagination({ + this.insertView("#database-pagination", new Components.Pagination({ page: this.page, perPage: this.perPage, total: this.collection.length, @@ -98,30 +98,12 @@ function(app, Paginate, FauxtonAPI) { }, afterRender: function() { - var dbLimit = this.dbLimit; - var ajaxReq; - - this.$el.find("input.search-query").typeahead({ - source: function(query, process) { - var url = [ - app.host, - "/_all_dbs?startkey=%22", - query, - "%22&endkey=%22", - query, - "\u9999%22&limit=", - dbLimit - ].join(''); - if (ajaxReq) ajaxReq.abort(); - ajaxReq = $.ajax({ - url: url, - dataType: 'json', - success: function(data) { - process(data); - } - }); - } + this.dbSearchTypeahead = new Components.DbSearchTypeahead({ + dbLimit: this.dbLimit, + el: "input.search-query" }); + + this.dbSearchTypeahead.render(); }, selectAll: function(evt){ diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js index 40f610ed0..36c6eeb06 100644 --- a/src/fauxton/app/modules/documents/views.js +++ b/src/fauxton/app/modules/documents/views.js @@ -14,7 +14,7 @@ define([ "app", "api", - "modules/fauxton/paginate", + "modules/fauxton/components", "modules/documents/resources", "modules/pouchdb/base", @@ -30,7 +30,7 @@ define([ ], -function(app, FauxtonAPI, Paginate, Documents, pouchdb, Codemirror, JSHint, resizeColumns) { +function(app, FauxtonAPI, Components, Documents, pouchdb, Codemirror, JSHint, resizeColumns) { var Views = {}; Views.Tabs = FauxtonAPI.View.extend({ @@ -520,7 +520,7 @@ function(app, FauxtonAPI, Paginate, Documents, pouchdb, Codemirror, JSHint, resi addPagination: function () { var collection = this.collection; - this.pagination = new Paginate.IndexPagination({ + this.pagination = new Components.IndexPagination({ collection: this.collection, scrollToSelector: '#dashboard-content', previousUrlfn: function () { diff --git a/src/fauxton/app/modules/fauxton/components.js b/src/fauxton/app/modules/fauxton/components.js new file mode 100644 index 000000000..10e08dc57 --- /dev/null +++ b/src/fauxton/app/modules/fauxton/components.js @@ -0,0 +1,138 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +define([ + "app", + // Libs + "api" +], + +function(app, FauxtonAPI) { + var Components = app.module(); + + Components.Pagination = FauxtonAPI.View.extend({ + template: "templates/fauxton/pagination", + + initialize: function(options) { + this.page = parseInt(options.page, 10); + this.perPage = options.perPage; + this.total = options.total; + this.totalPages = Math.ceil(this.total / this.perPage); + this.urlFun = options.urlFun; + }, + + serialize: function() { + return { + page: this.page, + perPage: this.perPage, + total: this.total, + totalPages: this.totalPages, + urlFun: this.urlFun + }; + } + }); + + Components.IndexPagination = FauxtonAPI.View.extend({ + template: "templates/fauxton/index_pagination", + events: { + "click a": 'scrollTo', + "click a#next": 'nextClicked', + "click a#previous": 'previousClicked' + }, + + previousIds: [], + + scrollTo: function () { + if (!this.scrollToSelector) { return; } + $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow'); + }, + + initialize: function (options) { + this.previousUrlfn = options.previousUrlfn; + this.nextUrlfn = options.nextUrlfn; + this.canShowPreviousfn = options.canShowPreviousfn; + this.canShowNextfn = options.canShowNextfn; + this.scrollToSelector = options.scrollToSelector; + _.bindAll(this); + }, + + previousClicked: function (event) { + event.preventDefault(); + FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false}); + FauxtonAPI.triggerRouteEvent('paginate', 'previous'); + }, + + nextClicked: function (event) { + event.preventDefault(); + this.previousIds.push(this.collection.first().id); + FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false}); + FauxtonAPI.triggerRouteEvent('paginate', 'next'); + }, + + serialize: function () { + return { + canShowNextfn: this.canShowNextfn, + canShowPreviousfn: this.canShowPreviousfn, + }; + } + + }); + + //TODO allow more of the typeahead options. + //Current this just does what we need but we + //need to support the other typeahead options. + Components.Typeahead = FauxtonAPI.View.extend({ + + initialize: function (options) { + this.source = options.source; + _.bindAll(this); + }, + + afterRender: function () { + this.$el.typeahead({ + source: this.source + }); + } + + }); + + Components.DbSearchTypeahead = Components.Typeahead.extend({ + initialize: function (options) { + this.dbLimit = options.dbLimit || 30; + _.bindAll(this); + }, + source: function(query, process) { + var url = [ + app.host, + "/_all_dbs?startkey=%22", + query, + "%22&endkey=%22", + query, + "\u9999%22&limit=", + this.dbLimit + ].join(''); + + if (this.ajaxReq) { this.ajaxReq.abort(); } + + this.ajaxReq = $.ajax({ + url: url, + dataType: 'json', + success: function(data) { + process(data); + } + }); + } + }); + + return Components; +}); + diff --git a/src/fauxton/app/modules/fauxton/paginate.js b/src/fauxton/app/modules/fauxton/paginate.js deleted file mode 100644 index 074fb479a..000000000 --- a/src/fauxton/app/modules/fauxton/paginate.js +++ /dev/null @@ -1,92 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -define([ - "app", - // Libs - "api" -], - -function(app, FauxtonAPI) { - var Paginate = app.module(); - - Paginate.Pagination = FauxtonAPI.View.extend({ - template: "templates/fauxton/pagination", - - initialize: function(options) { - this.page = parseInt(options.page, 10); - this.perPage = options.perPage; - this.total = options.total; - this.totalPages = Math.ceil(this.total / this.perPage); - this.urlFun = options.urlFun; - }, - - serialize: function() { - return { - page: this.page, - perPage: this.perPage, - total: this.total, - totalPages: this.totalPages, - urlFun: this.urlFun - }; - } - }); - - Paginate.IndexPagination = FauxtonAPI.View.extend({ - template: "templates/fauxton/index_pagination", - events: { - "click a": 'scrollTo', - "click a#next": 'nextClicked', - "click a#previous": 'previousClicked' - }, - - previousIds: [], - - scrollTo: function () { - if (!this.scrollToSelector) { return; } - $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow'); - }, - - initialize: function (options) { - this.previousUrlfn = options.previousUrlfn; - this.nextUrlfn = options.nextUrlfn; - this.canShowPreviousfn = options.canShowPreviousfn; - this.canShowNextfn = options.canShowNextfn; - this.scrollToSelector = options.scrollToSelector; - _.bindAll(this); - }, - - previousClicked: function (event) { - event.preventDefault(); - FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false}); - FauxtonAPI.triggerRouteEvent('paginate', 'previous'); - }, - - nextClicked: function (event) { - event.preventDefault(); - this.previousIds.push(this.collection.first().id); - FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false}); - FauxtonAPI.triggerRouteEvent('paginate', 'next'); - }, - - serialize: function () { - return { - canShowNextfn: this.canShowNextfn, - canShowPreviousfn: this.canShowPreviousfn, - }; - } - - }); - - return Paginate; -}); - -- cgit v1.2.1