1/* 2 * pagination.js 2.1.4 3 * A jQuery plugin to provide simple yet fully customisable pagination. 4 * https://github.com/superRaytin/paginationjs 5 * 6 * Homepage: http://pagination.js.org 7 * 8 * Copyright 2014-2100, superRaytin 9 * Released under the MIT license. 10 */ 11 12(function(global, $) { 13 14 if (typeof $ === 'undefined') { 15 throwError('Pagination requires jQuery.'); 16 } 17 18 var pluginName = 'pagination'; 19 20 var pluginHookMethod = 'addHook'; 21 22 var eventPrefix = '__pagination-'; 23 24 // Conflict, use backup 25 if ($.fn.pagination) { 26 pluginName = 'pagination2'; 27 } 28 29 $.fn[pluginName] = function(options) { 30 31 if (typeof options === 'undefined') { 32 return this; 33 } 34 35 var container = $(this); 36 37 var attributes = $.extend({}, $.fn[pluginName].defaults, options); 38 39 var pagination = { 40 41 initialize: function() { 42 var self = this; 43 44 // Cache attributes of current instance 45 if (!container.data('pagination')) { 46 container.data('pagination', {}); 47 } 48 49 if (self.callHook('beforeInit') === false) return; 50 51 // Pagination has been initialized, destroy it 52 if (container.data('pagination').initialized) { 53 $('.paginationjs', container).remove(); 54 } 55 56 // Whether to disable Pagination at the initialization 57 self.disabled = !!attributes.disabled; 58 59 // Model will be passed to the callback function 60 var model = self.model = { 61 pageRange: attributes.pageRange, 62 pageSize: attributes.pageSize 63 }; 64 65 // dataSource`s type is unknown, parse it to find true data 66 self.parseDataSource(attributes.dataSource, function(dataSource) { 67 68 // Currently in asynchronous mode 69 self.isAsync = Helpers.isString(dataSource); 70 if (Helpers.isArray(dataSource)) { 71 model.totalNumber = attributes.totalNumber = dataSource.length; 72 } 73 74 // Currently in asynchronous mode and a totalNumberLocator is specified 75 self.isDynamicTotalNumber = self.isAsync && attributes.totalNumberLocator; 76 77 // There is only one page 78 if (attributes.hideWhenLessThanOnePage) { 79 if (self.getTotalPage() <= 1) return; 80 } 81 82 var el = self.render(true); 83 84 // Add extra className to the pagination element 85 if (attributes.className) { 86 el.addClass(attributes.className); 87 } 88 89 model.el = el; 90 91 // Append/prepend pagination element to the container 92 container[attributes.position === 'bottom' ? 'append' : 'prepend'](el); 93 94 // Bind events 95 self.observer(); 96 97 // Pagination is currently initialized 98 container.data('pagination').initialized = true; 99
100 // Will be invoked after initialized 101 self.callHook('afterInit', el); 102 }); 103 }, 104 105 render: function(isBoot) { 106 var self = this; 107 var model = self.model; 108 var el = model.el || $('<div class="paginationjs"></div>'); 109 var isForced = isBoot !== true; 110 111 self.callHook('beforeRender', isForced); 112 113 var currentPage = model.pageNumber || attributes.pageNumber; 114 var pageRange = attributes.pageRange; 115 var totalPage = self.getTotalPage(); 116 117 var rangeStart = currentPage - pageRange; 118 var rangeEnd = currentPage + pageRange; 119 120 if (rangeEnd > totalPage) { 121 rangeEnd = totalPage; 122 rangeStart = totalPage - pageRange * 2; 123 rangeStart = rangeStart < 1 ? 1 : rangeStart; 124 } 125 126 if (rangeStart <= 1) { 127 rangeStart = 1; 128 rangeEnd = Math.min(pageRange * 2 + 1, totalPage); 129 } 130 131 el.html(self.generateHTML({ 132 currentPage: currentPage, 133 pageRange: pageRange, 134 rangeStart: rangeStart, 135 rangeEnd: rangeEnd 136 })); 137 138 self.callHook('afterRender', isForced); 139 140 return el; 141 }, 142 143 // Generate HTML content from the template 144 generateHTML: function(args) { 145 var self = this; 146 var currentPage = args.currentPage; 147 var totalPage = self.getTotalPage(); 148 var rangeStart = args.rangeStart; 149 var rangeEnd = args.rangeEnd; 150 151 var totalNumber = self.getTotalNumber(); 152 153 var showPrevious = attributes.showPrevious; 154 var showNext = attributes.showNext; 155 var showPageNumbers = attributes.showPageNumbers; 156 var showNavigator = attributes.showNavigator; 157 var showGoInput = attributes.showGoInput; 158 var showGoButton = attributes.showGoButton; 159 160 var pageLink = attributes.pageLink; 161 var prevText = attributes.prevText; 162 var nextText = attributes.nextText; 163 var ellipsisText = attributes.ellipsisText; 164 var goButtonText = attributes.goButtonText; 165 166 var classPrefix = attributes.classPrefix; 167 var activeClassName = attributes.activeClassName; 168 var disableClassName = attributes.disableClassName; 169 var ulClassName = attributes.ulClassName; 170 171 var html = ''; 172 var goInput = '<input type="text" class="J-paginationjs-go-pagenumber">'; 173 var goButton = '<input type="button" class="J-paginationjs-go-button" value="' + goButtonText + '">'; 174 var formattedString; 175 var i; 176 177 var formatNavigator = $.isFunction(attributes.formatNavigator) ? attributes.formatNavigator(currentPage, totalPage, totalNumber) : attributes.formatNavigator; 178 var formatGoInput = $.isFunction(attributes.formatGoInput) ? attributes.formatGoInput(goInput, currentPage, totalPage, totalNumber) : attributes.formatGoInput; 179 var formatGoButton = $.isFunction(attributes.formatGoButton) ? attributes.formatGoButton(goButton, currentPage, totalPage, totalNumber) : attributes.formatGoButton; 180 181 var autoHidePrevious = $.isFunction(attributes.autoHidePrevious) ? attributes.autoHidePrevious() : attributes.autoHidePrevious; 182 var autoHideNext = $.isFunction(attributes.autoHideNext) ? attributes.autoHideNext() : attributes.autoHideNext; 183 184 var header = $.isFunction(attributes.header) ? attributes.header(currentPage, totalPage, totalNumber) : attributes.header; 185 var footer = $.isFunction(attributes.footer) ? attributes.footer(currentPage, totalPage, totalNumber) : attributes.footer; 186 187 // Whether to display header 188 if (header) { 189 formattedString = self.replaceVariables(header, { 190 currentPage: currentPage, 191 totalPage: totalPage, 192 totalNumber: totalNumber 193 }); 194 html += formattedString; 195 } 196 197 if (showPrevious || showPageNumbers || showNext) { 198 html += '<div class="paginationjs-pages">'; 199 200 if (ulClassName) { 201 html += '<ul class="' + ulClassName + '">'; 202 } else { 203 html += '<ul>'; 204 } 205 206 // Whether to display the Previous button 207 if (showPrevious) { 208 if (currentPage <= 1) { 209 if (!autoHidePrevious) { 210 html += '<li class="' + classPrefix + '-prev ' + disableClassName + '"><a>' + prevText + '<\/a><\/li>'; 211 } 212 } else { 213 html += '<li class="' + classPrefix + '-prev J-paginationjs-previous" data-num="' + (currentPage - 1) + '" title="Previous page"><a href="' + pageLink + '">' + prevText + '<\/a><\/li>'; 214 } 215 } 216 217 // Whether to display the pages 218 if (showPageNumbers) { 219 if (rangeStart <= 3) { 220 for (i = 1; i < rangeStart; i++) { 221 if (i == currentPage) { 222 html += '<li class="' + classPrefix + '-page J-paginationjs-page ' + activeClassName + '" data-num="' + i + '"><a>' + i + '<\/a><\/li>'; 223 } else { 224 html += '<li class="' + classPrefix + '-page J-paginationjs-page" data-num="' + i + '"><a href="' + pageLink + '">' + i + '<\/a><\/li>'; 225 } 226 } 227 } else { 228 if (attributes.showFirstOnEllipsisShow) { 229 html += '<li class="' + classPrefix + '-page ' + classPrefix + '-first J-paginationjs-page" data-num="1"><a href="' + pageLink + '">1<\/a><\/li>'; 230 } 231 html += '<li class="' + classPrefix + '-ellipsis ' + disableClassName + '"><a>' + ellipsisText + '<\/a><\/li>'; 232 } 233 234 for (i = rangeStart; i <= rangeEnd; i++) { 235 if (i == currentPage) { 236 html += '<li class="' + classPrefix + '-page J-paginationjs-page ' + activeClassName + '" data-num="' + i + '"><a>' + i + '<\/a><\/li>'; 237 } else { 238 html += '<li class="' + classPrefix + '-page J-paginationjs-page" data-num="' + i + '"><a href="' + pageLink + '">' + i + '<\/a><\/li>'; 239 } 240 } 241 242 if (rangeEnd >= totalPage - 2) { 243 for (i = rangeEnd + 1; i <= totalPage; i++) { 244 html += '<li class="' + classPrefix + '-page J-paginationjs-page" data-num="' + i + '"><a href="' + pageLink + '">' + i + '<\/a><\/li>'; 245 } 246 } else { 247 html += '<li class="' + classPrefix + '-ellipsis ' + disableClassName + '"><a>' + ellipsisText + '<\/a><\/li>'; 248 249 if (attributes.showLastOnEllipsisShow) { 250 html += '<li class="' + classPrefix + '-page ' + classPrefix + '-last J-paginationjs-page" data-num="' + totalPage + '"><a href="' + pageLink + '">' + totalPage + '<\/a><\/li>'; 251 } 252 } 253 } 254 255 // Whether to display the Next button 256 if (showNext) { 257 if (currentPage >= totalPage) { 258 if (!autoHideNext) { 259 html += '<li class="' + classPrefix + '-next ' + disableClassName + '"><a>' + nextText + '<\/a><\/li>'; 260 } 261 } else { 262 html += '<li class="' + classPrefix + '-next J-paginationjs-next" data-num="' + (currentPage + 1) + '" title="Next page"><a href="' + pageLink + '">' + nextText + '<\/a><\/li>'; 263 } 264 } 265 html += '<\/ul><\/div>'; 266 } 267 268 // Whether to display the navigator 269 if (showNavigator) { 270 if (formatNavigator) { 271 formattedString = self.replaceVariables(formatNavigator, { 272 currentPage: currentPage, 273 totalPage: totalPage, 274 totalNumber: totalNumber 275 }); 276 html += '<div class="' + classPrefix + '-nav J-paginationjs-nav">' + formattedString + '<\/div>'; 277 } 278 } 279 280 // Whether to display the Go input 281 if (showGoInput) { 282 if (formatGoInput) { 283 formattedString = self.replaceVariables(formatGoInput, { 284 currentPage: currentPage, 285 totalPage: totalPage, 286 totalNumber: totalNumber, 287 input: goInput 288 }); 289 html += '<div class="' + classPrefix + '-go-input">' + formattedString + '</div>'; 290 } 291 } 292 293 // Whether to display the Go button 294 if (showGoButton) { 295 if (formatGoButton) { 296 formattedString = self.replaceVariables(formatGoButton, { 297 currentPage: currentPage, 298 totalPage: totalPage, 299 totalNumber: totalNumber, 300 button: goButton 301 }); 302 html += '<div class="' + classPrefix + '-go-button">' + formattedString + '</div>'; 303 } 304 } 305 306 // Whether to display footer 307 if (footer) { 308 formattedString = self.replaceVariables(footer, { 309 currentPage: currentPage, 310 totalPage: totalPage, 311 totalNumber: totalNumber 312 }); 313 html += formattedString; 314 } 315 316 return html; 317 }, 318 319 // Find totalNumber from the remote response 320 // Only available in asynchronous mode 321 findTotalNumberFromRemoteResponse: function(response) { 322 var self = this; 323 self.model.totalNumber = attributes.totalNumberLocator(response); 324 }, 325 326 // Go to the specified page 327 go: function(number, callback) { 328 var self = this; 329 var model = self.model; 330 331 if (self.disabled) return; 332 333 var pageNumber = number; 334 pageNumber = parseInt(pageNumber); 335 336 // Page number is out of bounds 337 if (!pageNumber || pageNumber < 1) return; 338 339 var pageSize = attributes.pageSize; 340 var totalNumber = self.getTotalNumber(); 341 var totalPage = self.getTotalPage(); 342 343 // Page number is out of bounds 344 if (totalNumber > 0) { 345 if (pageNumber > totalPage) return; 346 } 347 348 // Pick data fragment in synchronous mode 349 if (!self.isAsync) { 350 render(self.getDataFragment(pageNumber)); 351 return; 352 } 353 354 var postData = {}; 355 var alias = attributes.alias || {}; 356 postData[alias.pageSize ? alias.pageSize : 'pageSize'] = pageSize; 357 postData[alias.pageNumber ? alias.pageNumber : 'pageNumber'] = pageNumber; 358 359 var ajaxParams = $.isFunction(attributes.ajax) ? attributes.ajax() : attributes.ajax; 360 var formatAjaxParams = { 361 type: 'get', 362 cache: false, 363 data: {}, 364 contentType: 'application/x-www-form-urlencoded; charset=UTF-8', 365 dataType: 'json', 366 async: true 367 }; 368 369 $.extend(true, formatAjaxParams, ajaxParams); 370 $.extend(formatAjaxParams.data, postData); 371 372 formatAjaxParams.url = attributes.dataSource; 373 formatAjaxParams.success = function(response) { 374 if (self.isDynamicTotalNumber) { 375 self.findTotalNumberFromRemoteResponse(response); 376 } else { 377 self.model.totalNumber = attributes.totalNumber; 378 } 379 render(self.filterDataByLocator(response)); 380 }; 381 formatAjaxParams.error = function(jqXHR, textStatus, errorThrown) { 382 attributes.formatAjaxError && attributes.formatAjaxError(jqXHR, textStatus, errorThrown); 383 self.enable(); 384 }; 385 386 self.disable(); 387 388 $.ajax(formatAjaxParams); 389 390 function render(data) {
391 // Will be invoked before paging 392 if (self.callHook('beforePaging', pageNumber) === false) return false; 393 394 // Pagination direction 395 model.direction = typeof model.pageNumber === 'undefined' ? 0 : (pageNumber > model.pageNumber ? 1 : -1); 396 397 model.pageNumber = pageNumber; 398 399 self.render(); 400 401 if (self.disabled && self.isAsync) { 402 // enable pagination 403 self.enable(); 404 } 405 406 // cache model data 407 container.data('pagination').model = model; 408 409 // format result data before callback invoked 410 if (attributes.formatResult) { 411 var cloneData = $.extend(true, [], data); 412 if (!Helpers.isArray(data = attributes.formatResult(cloneData))) { 413 data = cloneData; 414 } 415 } 416 417 container.data('pagination').currentPageData = data; 418 419 // invoke callback 420 self.doCallback(data, callback); 421 422 self.callHook('afterPaging', pageNumber); 423 424 // pageNumber now is the first page 425 if (pageNumber == 1) { 426 self.callHook('afterIsFirstPage'); 427 } 428 429 // pageNumber now is the last page 430 if (pageNumber == self.getTotalPage()) { 431 self.callHook('afterIsLastPage'); 432 } 433 } 434 }, 435 436 doCallback: function(data, customCallback) { 437 var self = this; 438 var model = self.model; 439 440 if ($.isFunction(customCallback)) { 441 customCallback(data, model); 442 } else if ($.isFunction(attributes.callback)) { 443 attributes.callback(data, model); 444 } 445 }, 446 447 destroy: function() { 448 // Before destroy 449 if (this.callHook('beforeDestroy') === false) return; 450 451 this.model.el.remove(); 452 container.off(); 453 454 // Remove style element 455 $('#paginationjs-style').remove(); 456 457 // After destroyed 458 this.callHook('afterDestroy'); 459 }, 460 461 previous: function(callback) { 462 this.go(this.model.pageNumber - 1, callback); 463 }, 464 465 next: function(callback) { 466 this.go(this.model.pageNumber + 1, callback); 467 }, 468 469 disable: function() { 470 var self = this; 471 var source = self.isAsync ? 'async' : 'sync'; 472 473 // Before disabled 474 if (self.callHook('beforeDisable', source) === false) return; 475 476 self.disabled = true; 477 self.model.disabled = true; 478 479 // After disabled 480 self.callHook('afterDisable', source); 481 }, 482 483 enable: function() { 484 var self = this; 485 var source = self.isAsync ? 'async' : 'sync'; 486 487 // Before enabled 488 if (self.callHook('beforeEnable', source) === false) return; 489 490 self.disabled = false; 491 self.model.disabled = false; 492 493 // After enabled 494 self.callHook('afterEnable', source); 495 }, 496 497 refresh: function(callback) { 498 this.go(this.model.pageNumber, callback); 499 }, 500 501 show: function() { 502 var self = this; 503 504 if (self.model.el.is(':visible')) return; 505 506 self.model.el.show(); 507 }, 508 509 hide: function() { 510 var self = this; 511 512 if (!self.model.el.is(':visible')) return; 513 514 self.model.el.hide(); 515 }, 516 517 // Parse variables in the template 518 replaceVariables: function(template, variables) { 519 var formattedString; 520 521 for (var key in variables) { 522 var value = variables[key]; 523 var regexp = new RegExp('<%=\\s*' + key + '\\s*%>', 'img'); 524 525 formattedString = (formattedString || template).replace(regexp, value); 526 } 527 528 return formattedString; 529 }, 530 531 // Get data fragment 532 getDataFragment: function(number) { 533 var pageSize = attributes.pageSize; 534 var dataSource = attributes.dataSource; 535 var totalNumber = this.getTotalNumber(); 536 537 var start = pageSize * (number - 1) + 1; 538 var end = Math.min(number * pageSize, totalNumber); 539 540 return dataSource.slice(start - 1, end); 541 }, 542 543 // Get total number 544 getTotalNumber: function() { 545 return this.model.totalNumber || attributes.totalNumber || 0; 546 }, 547 548 // Get total page 549 getTotalPage: function() { 550 return Math.ceil(this.getTotalNumber() / attributes.pageSize); 551 }, 552 553 // Get locator 554 getLocator: function(locator) { 555 var result; 556 557 if (typeof locator === 'string') { 558 result = locator; 559 } else if ($.isFunction(locator)) { 560 result = locator(); 561 } else { 562 throwError('"locator" is incorrect. (String | Function)'); 563 } 564 565 return result; 566 }, 567 568 // Filter data by "locator" 569 filterDataByLocator: function(dataSource) { 570 var locator = this.getLocator(attributes.locator); 571 var filteredData; 572 573 // Datasource is an Object, use "locator" to locate the true data 574 if (Helpers.isObject(dataSource)) { 575 try { 576 $.each(locator.split('.'), function(index, item) { 577 filteredData = (filteredData ? filteredData : dataSource)[item]; 578 }); 579 } 580 catch (e) { 581 } 582 583 if (!filteredData) { 584 throwError('dataSource.' + locator + ' is undefined.'); 585 } else if (!Helpers.isArray(filteredData)) { 586 throwError('dataSource.' + locator + ' must be an Array.'); 587 } 588 } 589 590 return filteredData || dataSource; 591 }, 592 593 // Parse dataSource 594 parseDataSource: function(dataSource, callback) { 595 var self = this; 596 597 if (Helpers.isObject(dataSource)) { 598 callback(attributes.dataSource = self.filterDataByLocator(dataSource)); 599 } else if (Helpers.isArray(dataSource)) { 600 callback(attributes.dataSource = dataSource); 601 } else if ($.isFunction(dataSource)) { 602 attributes.dataSource(function(data) { 603 if (!Helpers.isArray(data)) { 604 throwError('The parameter of "done" Function should be an Array.'); 605 } 606 self.parseDataSource.call(self, data, callback); 607 }); 608 } else if (typeof dataSource === 'string') { 609 if (/^https?|file:/.test(dataSource)) { 610 attributes.ajaxDataType = 'jsonp'; 611 } 612 callback(dataSource); 613 } else { 614 throwError('Unexpected type of "dataSource".'); 615 } 616 }, 617 618 callHook: function(hook) { 619 var paginationData = container.data('pagination'); 620 var result; 621 622 var args = Array.prototype.slice.apply(arguments); 623 args.shift(); 624 625 if (attributes[hook] && $.isFunction(attributes[hook])) { 626 if (attributes[hook].apply(global, args) === false) { 627 result = false; 628 } 629 } 630 631 if (paginationData.hooks && paginationData.hooks[hook]) { 632 $.each(paginationData.hooks[hook], function(index, item) { 633 if (item.apply(global, args) === false) { 634 result = false; 635 } 636 }); 637 } 638 639 return result !== false; 640 }, 641 642 observer: function() { 643 var self = this; 644 var el = self.model.el; 645 646 // Go to specified page number 647 container.on(eventPrefix + 'go', function(event, pageNumber, done) { 648 pageNumber = parseInt($.trim(pageNumber)); 649 650 if (!pageNumber) return; 651 652 if (!$.isNumeric(pageNumber)) { 653 throwError('"pageNumber" is incorrect. (Number)'); 654 } 655 656 self.go(pageNumber, done); 657 }); 658 659 // Page number button click 660 el.delegate('.J-paginationjs-page', 'click', function(event) { 661 var current = $(event.currentTarget); 662 var pageNumber = $.trim(current.attr('data-num')); 663 664 if (!pageNumber || current.hasClass(attributes.disableClassName) || current.hasClass(attributes.activeClassName)) return; 665 666 // Before page button clicked 667 if (self.callHook('beforePageOnClick', event, pageNumber) === false) return false; 668 669 self.go(pageNumber); 670 671 // After page button clicked 672 self.callHook('afterPageOnClick', event, pageNumber); 673 674 if (!attributes.pageLink) return false; 675 }); 676 677 // Previous button click 678 el.delegate('.J-paginationjs-previous', 'click', function(event) { 679 var current = $(event.currentTarget); 680 var pageNumber = $.trim(current.attr('data-num')); 681 682 if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 683 684 // Before previous clicked 685 if (self.callHook('beforePreviousOnClick', event, pageNumber) === false) return false; 686 687 self.go(pageNumber); 688 689 // After previous clicked 690 self.callHook('afterPreviousOnClick', event, pageNumber); 691 692 if (!attributes.pageLink) return false; 693 }); 694 695 // Next button click 696 el.delegate('.J-paginationjs-next', 'click', function(event) { 697 var current = $(event.currentTarget); 698 var pageNumber = $.trim(current.attr('data-num')); 699 700 if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 701 702 // Before next clicked 703 if (self.callHook('beforeNextOnClick', event, pageNumber) === false) return false; 704 705 self.go(pageNumber); 706 707 // After next clicked 708 self.callHook('afterNextOnClick', event, pageNumber); 709 710 if (!attributes.pageLink) return false; 711 }); 712 713 // Go button click 714 el.delegate('.J-paginationjs-go-button', 'click', function(event) { 715 var pageNumber = $('.J-paginationjs-go-pagenumber', el).val(); 716 717 // Before Go button clicked 718 if (self.callHook('beforeGoButtonOnClick', event, pageNumber) === false) return false; 719 720 container.trigger(eventPrefix + 'go', pageNumber); 721 722 // After Go button clicked 723 self.callHook('afterGoButtonOnClick', event, pageNumber); 724 }); 725 726 // go input enter 727 el.delegate('.J-paginationjs-go-pagenumber', 'keyup', function(event) { 728 if (event.which === 13) { 729 var pageNumber = $(event.currentTarget).val(); 730 731 // Before Go input enter 732 if (self.callHook('beforeGoInputOnEnter', event, pageNumber) === false) return false; 733 734 container.trigger(eventPrefix + 'go', pageNumber); 735 736 // Regains focus 737 $('.J-paginationjs-go-pagenumber', el).focus(); 738 739 // After Go input enter 740 self.callHook('afterGoInputOnEnter', event, pageNumber); 741 } 742 }); 743 744 // Previous page 745 container.on(eventPrefix + 'previous', function(event, done) { 746 self.previous(done); 747 }); 748 749 // Next page 750 container.on(eventPrefix + 'next', function(event, done) { 751 self.next(done); 752 }); 753 754 // Disable 755 container.on(eventPrefix + 'disable', function() { 756 self.disable(); 757 }); 758 759 // Enable 760 container.on(eventPrefix + 'enable', function() { 761 self.enable(); 762 }); 763 764 // Refresh 765 container.on(eventPrefix + 'refresh', function(event, done) { 766 self.refresh(done); 767 }); 768 769 // Show 770 container.on(eventPrefix + 'show', function() { 771 self.show(); 772 }); 773 774 // Hide 775 container.on(eventPrefix + 'hide', function() { 776 self.hide(); 777 }); 778 779 // Destroy
780 container.on(eventPrefix + 'destroy', function() { 781 self.destroy(); 782 }); 783 784 // Whether to load the default page 785 var validTotalPage = Math.max(self.getTotalPage(), 1) 786 var defaultPageNumber = attributes.pageNumber; 787 // Default pageNumber should be 1 when totalNumber is dynamic 788 if (self.isDynamicTotalNumber) { 789 defaultPageNumber = 1; 790 } 791 if (attributes.triggerPagingOnInit) { 792 container.trigger(eventPrefix + 'go', Math.min(defaultPageNumber, validTotalPage)); 793 } 794 } 795 }; 796 797 // Pagination has been initialized 798 if (container.data('pagination') && container.data('pagination').initialized === true) { 799 // Handle events 800 if ($.isNumeric(options)) { 801 // eg: container.pagination(5) 802 container.trigger.call(this, eventPrefix + 'go', options, arguments[1]); 803 return this; 804 } else if (typeof options === 'string') { 805 var args = Array.prototype.slice.apply(arguments); 806 args[0] = eventPrefix + args[0]; 807 808 switch (options) { 809 case 'previous': 810 case 'next': 811 case 'go': 812 case 'disable': 813 case 'enable': 814 case 'refresh': 815 case 'show': 816 case 'hide': 817 case 'destroy': 818 container.trigger.apply(this, args); 819 break; 820 // Get selected page number 821 case 'getSelectedPageNum': 822 if (container.data('pagination').model) { 823 return container.data('pagination').model.pageNumber; 824 } else { 825 return container.data('pagination').attributes.pageNumber; 826 } 827 // Get total page 828 case 'getTotalPage': 829 return Math.ceil(container.data('pagination').model.totalNumber / container.data('pagination').model.pageSize); 830 // Get data of selected page 831 case 'getSelectedPageData': 832 return container.data('pagination').currentPageData; 833 // Whether pagination has been disabled 834 case 'isDisabled': 835 return container.data('pagination').model.disabled === true; 836 default: 837 throwError('Unknown action: ' + options); 838 } 839 return this; 840 } else { 841 // Uninstall the old instance before initializing a new one 842 uninstallPlugin(container); 843 } 844 } else { 845 if (!Helpers.isObject(options)) throwError('Illegal options'); 846 } 847 848 // Check parameters 849 parameterChecker(attributes); 850 851 pagination.initialize(); 852 853 return this; 854 }; 855 856 // Instance defaults 857 $.fn[pluginName].defaults = { 858 859 // Data source 860 // Array | String | Function | Object 861 //dataSource: '', 862 863 // String | Function 864 //locator: 'data', 865 866 // Find totalNumber from remote response, the totalNumber will be ignored when totalNumberLocator is specified 867 // Function 868 //totalNumberLocator: function() {}, 869 870 // Total entries 871 totalNumber: 0, 872 873 // Default page 874 pageNumber: 1, 875 876 // entries of per page 877 pageSize: 10, 878 879 // Page range (pages on both sides of the current page) 880 pageRange: 2, 881 882 // Whether to display the 'Previous' button 883 showPrevious: true, 884 885 // Whether to display the 'Next' button 886 showNext: true, 887 888 // Whether to display the page buttons 889 showPageNumbers: true, 890 891 showNavigator: false, 892 893 // Whether to display the 'Go' input 894 showGoInput: false, 895 896 // Whether to display the 'Go' button 897 showGoButton: false, 898 899 // Page link 900 pageLink: '', 901 902 // 'Previous' text 903 prevText: '«', 904 905 // 'Next' text 906 nextText: '»', 907 908 // Ellipsis text 909 ellipsisText: '...', 910 911 // 'Go' button text 912 goButtonText: 'Go', 913 914 // Additional className for Pagination element 915 //className: '', 916 917 classPrefix: 'paginationjs', 918 919 // Default active class 920 activeClassName: 'active', 921 922 // Default disable class 923 disableClassName: 'disabled', 924 925 //ulClassName: '', 926 927 // Whether to insert inline style 928 inlineStyle: true, 929 930 formatNavigator: '<%= currentPage %> / <%= totalPage %>', 931 932 formatGoInput: '<%= input %>', 933 934 formatGoButton: '<%= button %>', 935 936 // Pagination element's position in the container 937 position: 'bottom', 938 939 // Auto hide previous button when current page is the first page 940 autoHidePrevious: false, 941 942 // Auto hide next button when current page is the last page 943 autoHideNext: false, 944 945 //header: '', 946 947 //footer: '', 948 949 // Aliases for custom pagination parameters 950 //alias: {}, 951 952 // Whether to trigger pagination at initialization 953 triggerPagingOnInit: true, 954 955 // Whether to hide pagination when less than one page 956 hideWhenLessThanOnePage: false, 957 958 showFirstOnEllipsisShow: true, 959 960 showLastOnEllipsisShow: true, 961 962 // Pagination callback 963 callback: function() {} 964 }; 965 966 // Hook register 967 $.fn[pluginHookMethod] = function(hook, callback) { 968 if (arguments.length < 2) { 969 throwError('Missing argument.'); 970 } 971 972 if (!$.isFunction(callback)) { 973 throwError('callback must be a function.'); 974 } 975 976 var container = $(this); 977 var paginationData = container.data('pagination'); 978 979 if (!paginationData) { 980 container.data('pagination', {}); 981 paginationData = container.data('pagination'); 982 } 983 984 !paginationData.hooks && (paginationData.hooks = {}); 985 986 //paginationData.hooks[hook] = callback; 987 paginationData.hooks[hook] = paginationData.hooks[hook] || []; 988 paginationData.hooks[hook].push(callback); 989 990 }; 991 992 // Static method 993 $[pluginName] = function(selector, options) { 994 if (arguments.length < 2) { 995 throwError('Requires two parameters.'); 996 } 997 998 var container; 999
1000 // 'selector' is a jQuery object 1001 if (typeof selector !== 'string' && selector instanceof jQuery) { 1002 container = selector; 1003 } else { 1004 container = $(selector); 1005 } 1006 1007 if (!container.length) return; 1008 1009 container.pagination(options); 1010 1011 return container; 1012 }; 1013 1014 // ============================================================ 1015 // helpers 1016 // ============================================================ 1017 1018 var Helpers = {}; 1019 1020 // Throw error 1021 function throwError(content) { 1022 throw new Error('Pagination: ' + content); 1023 } 1024 1025 // Check parameters 1026 function parameterChecker(args) { 1027 if (!args.dataSource) { 1028 throwError('"dataSource" is required.'); 1029 } 1030 1031 if (typeof args.dataSource === 'string') { 1032 if (args.totalNumberLocator === undefined) { 1033 if (args.totalNumber === undefined) { 1034 throwError('"totalNumber" is required.'); 1035 } else if (!$.isNumeric(args.totalNumber)) { 1036 throwError('"totalNumber" is incorrect. (Number)'); 1037 } 1038 } else { 1039 if (!$.isFunction(args.totalNumberLocator)) { 1040 throwError('"totalNumberLocator" should be a Function.'); 1041 } 1042 } 1043 } else if (Helpers.isObject(args.dataSource)) { 1044 if (typeof args.locator === 'undefined') { 1045 throwError('"dataSource" is an Object, please specify "locator".'); 1046 } else if (typeof args.locator !== 'string' && !$.isFunction(args.locator)) { 1047 throwError('' + args.locator + ' is incorrect. (String | Function)'); 1048 } 1049 } 1050 1051 if (args.formatResult !== undefined && !$.isFunction(args.formatResult)) { 1052 throwError('"formatResult" should be a Function.'); 1053 } 1054 } 1055 1056 // uninstall plugin 1057 function uninstallPlugin(target) { 1058 var events = ['go', 'previous', 'next', 'disable', 'enable', 'refresh', 'show', 'hide', 'destroy']; 1059 1060 // off events of old instance 1061 $.each(events, function(index, value) { 1062 target.off(eventPrefix + value); 1063 }); 1064 1065 // reset pagination data 1066 target.data('pagination', {}); 1067 1068 // remove old 1069 $('.paginationjs', target).remove(); 1070 } 1071 1072 // Object type detection 1073 function getObjectType(object, tmp) { 1074 return ( (tmp = typeof(object)) == "object" ? object == null && "null" || Object.prototype.toString.call(object).slice(8, -1) : tmp ).toLowerCase(); 1075 } 1076 1077 $.each(['Object', 'Array', 'String'], function(index, name) { 1078 Helpers['is' + name] = function(object) { 1079 return getObjectType(object) === name.toLowerCase(); 1080 }; 1081 }); 1082 1083 /* 1084 * export via AMD or CommonJS 1085 * */ 1086 if (typeof define === 'function' && define.amd) { 1087 define(function() { 1088 return $; 1089 }); 1090 } 1091 1092})(this, window.jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.