Changeset 26948 for extensions/UserAdvManager
- Timestamp:
- Jan 24, 2014, 6:36:41 PM (10 years ago)
- Location:
- extensions/UserAdvManager/branches/2.6
- Files:
-
- 5 added
- 1 deleted
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/UserAdvManager/branches/2.6/admin/UAM_admin.php
r25745 r26948 169 169 $conf_UAM_ConfirmMail = unserialize($conf['UserAdvManager_ConfirmMail']); 170 170 171 if (((isset($conf_UAM[' 1']) and ($conf_UAM['1'] == 'false' or $conf_UAM['1'] == 'local')) or ($_POST['UAM_Confirm_Mail'] == 'false' or $_POST['UAM_Confirm_Mail'] == 'local')) and $_POST['UAM_GTAutoMail'] == 'true')171 if (((isset($conf_UAM['CONFIRM_MAIL']) and ($conf_UAM['CONFIRM_MAIL'] == 'false' or $conf_UAM['CONFIRM_MAIL'] == 'local')) or ($_POST['UAM_Confirm_Mail'] == 'false' or $_POST['UAM_Confirm_Mail'] == 'local')) and $_POST['UAM_GTAutoMail'] == 'true') 172 172 { 173 173 $newvalue = 'false'; -
extensions/UserAdvManager/branches/2.6/admin/template/ghosttracker.tpl
r21747 r26948 2 2 {combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 3 3 {combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager. js'}4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 5 5 6 6 {combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} … … 19 19 {ldelim} 20 20 $("#sorting") 21 .tablesorter({ldelim}sortList:[[4,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim} {rdelim}{rdelim})22 .tablesorterPager({ldelim}container: $("#pager"), p ositionFixed: false, size: 20, totalPages: 0{rdelim});21 .tablesorter({ldelim}sortList:[[4,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim},2: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 22 .tablesorterPager({ldelim}container: $("#pager"), page: 0, size: 20, output: '{ldelim}page{rdelim} / {ldelim}totalPages{rdelim}',{rdelim}); 23 23 {rdelim}); 24 24 </script> … … 28 28 </div> 29 29 30 <form method="post" action=""class="general">30 <form method="post" class="general"> 31 31 <fieldset> 32 32 <legend>{'UAM_GT_Init'|@translate}</legend> … … 39 39 </fieldset> 40 40 41 {if count($users) > 0} 41 42 <fieldset> 42 43 <legend class="cluetip" title="{'UAM_GhostTracker_Title'|translate}|{'UAM_gtTitle_d'|translate}">{'UAM_GhostTracker_Title'|@translate}</legend> 43 {if count($users) > 0} 44 <table id="sorting" class="table2" width="97%" summary=""> 44 <table id="sorting" class="table2"> 45 45 <thead> 46 46 <tr class="throw"> … … 58 58 <td><input type="checkbox" name="selection[]" value="{$user.ID}" {$user.CHECKED} id="selection-{$user.ID}"/></td> 59 59 <td><label for="selection-{$user.ID}">{$user.USERNAME}</label></td> 60 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" /></a></td>60 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" alt=""/></a></td> 61 61 <td>{$user.EMAIL}</td> 62 62 {if $user.REMINDER == l10n('UAM_Reminder_Sent_NOK')} … … 75 75 </table> 76 76 <div id="pager" class="pager"> 77 <form> 78 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first"/> 79 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev"/> 77 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first" alt=""/> 78 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev" alt=""/> 80 79 <input type="text" class="pagedisplay"/> 81 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" />82 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" />83 <select class="pagesize" >80 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" alt=""/> 81 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" alt=""/> 82 <select class="pagesize" title="{'UAM_Select page size'|@translate}"> 84 83 <option value="10">10</option> 85 84 <option selected="selected" value="20">20</option> … … 87 86 <option value="40">40</option> 88 87 </select> 89 </form>88 <select class="gotoPage" title="{'UAM_Select page number'|@translate}"></select> 90 89 </div> 91 90 <br/> … … 104 103 </fieldset> 105 104 {else} 105 <fieldset> 106 <legend class="cluetip" title="{'UAM_GhostTracker_Title'|translate}|{'UAM_gtTitle_d'|translate}">{'UAM_GhostTracker_Title'|@translate}</legend> 106 107 <div> 107 108 {'UAM_No_Ghosts'|@translate} 108 109 </div> 110 </fieldset> 109 111 {/if} 110 112 </form> -
extensions/UserAdvManager/branches/2.6/admin/template/global.tpl
r25092 r26948 151 151 </div> 152 152 153 <form method="post" action=""class="general">153 <form method="post" class="general"> 154 154 155 155 <p> … … 181 181 <label for="UAM_Username_Char_true"><input id="UAM_Username_Char_true" type="radio" value="true" {$UAM_USERNAME_CHAR_TRUE} name="UAM_Username_Char"/> 182 182 {'UAM_Username_Char_true'|@translate} 183 </label> 183 184 <div class="uam_leftmargin"> 184 185 <input type="text" name="UAM_Username_List" value="{$UAM_USERNAME_CHAR_LIST}" size="20" style="text-align: center;"/> 185 186 </div> 186 </label>187 187 </li> 188 188 … … 297 297 <textarea class="uam_textfields" name="UAM_AdminValidationMail_Subject" id="UAM_AdminValidationMail_Subject" rows="5" {$TAG_INPUT_ENABLED}>{$UAM_ADMINVALIDATIONMAIL_SUBJECT}</textarea> 298 298 </li> 299 <li style="list-style-type: none;"> 299 300 <ul> 300 301 <li> … … 305 306 </li> 306 307 </ul> 308 </li> 307 309 </ul> 308 310 <ul> … … 313 315 <textarea class="uam_textfields" name="UAM_ConfirmMail_Subject" id="UAM_ConfirmMail_Subject" rows="5" {$TAG_INPUT_ENABLED}>{$UAM_CONFIRMMAIL_SUBJECT}</textarea> 314 316 </li> 317 <li style="list-style-type: none;"> 315 318 <ul> 316 319 <li> … … 325 328 </li> 326 329 </ul> 330 </li> 327 331 <!-- 328 332 {* if 'FCK_PATH'|@defined *} … … 332 336 {* /if *} 333 337 --> 338 <li style="list-style-type: none;"> 334 339 <br/><hr/><br/> 340 </li> 335 341 <li> 336 342 <label class="cluetip" title="{'UAM_confirmmail_custom_Txt1'|translate}|{'UAM_confirmmail_custom1_d'|translate}"> … … 340 346 </li> 341 347 {if 'FCK_PATH'|@defined} 348 <li style="list-style-type: none;"> 342 349 <div style="text-align:right;"> 343 350 <a href="#" onClick="toogleEditor('UAM_ConfirmMail_Custom_Txt1'); return false;">FCK Editor On/Off</a> 344 351 </div> 352 </li> 345 353 {/if} 346 354 <li> … … 351 359 </li> 352 360 {if 'FCK_PATH'|@defined} 361 <li style="list-style-type: none;"> 353 362 <div style="text-align:right;"> 354 363 <a href="#" onClick="toogleEditor('UAM_ConfirmMail_Custom_Txt2'); return false;">FCK Editor On/Off</a> 355 364 </div> 365 </li> 356 366 {/if} 357 367 </ul> … … 377 387 <textarea class="uam_textfields" name="UAM_CustomRejectConnexion_Text" id="UAM_CustomRejectConnexion_Text" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_REJECTCONNECT_TEXT}</textarea> 378 388 {if 'FCK_PATH'|@defined} 389 <li style="list-style-type: none;"> 379 390 <div style="text-align:right;"> 380 391 <a href="#" onClick="toogleEditor('UAM_CustomRejectConnexion_Text'); return false;">FCK Editor On/Off</a> 381 392 </div> 393 </li> 382 394 {/if} 383 395 </li> … … 388 400 <fieldset id="UAM_Change" style="display: none"> 389 401 <ul> 402 <li style="list-style-type: none;"> 390 403 <div id="uam_notice">{'UAM_Confirm_grpstat_notice'|@translate}</div> 404 </li> 405 <li style="list-style-type: none;"> 391 406 <br/> 407 </li> 392 408 <li> 393 409 <label class="cluetip" title="{'UAM_confirmgrpTitle'|translate}|{'UAM_confirmgrpTitle_d'|translate}"> … … 395 411 </label> 396 412 </li> 413 <li style="list-style-type: none;"> 397 414 <ul> 398 415 <li> … … 413 430 </li> 414 431 </ul> 432 </li> 415 433 <li> 416 434 <label class="cluetip" title="{'UAM_confirmstatTitle'|translate}|{'UAM_confirmstatTitle_d'|translate}"> … … 418 436 </label> 419 437 </li> 438 <li style="list-style-type: none;"> 420 439 <ul> 421 440 <li> … … 436 455 </li> 437 456 </ul> 457 </li> 438 458 <li> 439 459 <label class="cluetip" title="{'UAM_confirmlevelTitle'|translate}|{'UAM_confirmlevelTitle_d'|translate}"> … … 441 461 </label> 442 462 </li> 463 <li style="list-style-type: none;"> 443 464 <ul> 444 465 <li> … … 459 480 </li> 460 481 </ul> 482 </li> 461 483 </ul> 462 484 </fieldset> … … 467 489 {'UAM_ValidationLimit_Info'|@translate} 468 490 </label> 469 <label for="UAM_ConfirmMail_TimeOut_false" ><input id="UAM_ConfirmMail_TimeOut_false" type="radio" value="false" {$UAM_CONFIRMMAIL_TIMEOUT_FALSE} name="UAM_ConfirmMail_TimeOut"/> 491 <label for="UAM_ConfirmMail_TimeOut_false" > 492 <input id="UAM_ConfirmMail_TimeOut_false" type="radio" value="false" {$UAM_CONFIRMMAIL_TIMEOUT_FALSE} name="UAM_ConfirmMail_TimeOut"/> 470 493 {'UAM_Disable'|@translate} 471 494 </label> 472 <label for="UAM_ConfirmMail_TimeOut_true" ><input id="UAM_ConfirmMail_TimeOut_true" type="radio" value="true" {$UAM_CONFIRMMAIL_TIMEOUT_TRUE} name="UAM_ConfirmMail_TimeOut"/> 495 <label for="UAM_ConfirmMail_TimeOut_true" > 496 <input id="UAM_ConfirmMail_TimeOut_true" type="radio" value="true" {$UAM_CONFIRMMAIL_TIMEOUT_TRUE} name="UAM_ConfirmMail_TimeOut"/> 473 497 {'UAM_ConfirmMail_TimeOut_true'|@translate} 474 < input type="text" name="UAM_ConfirmMail_Delay" value="{$UAM_CONFIRMMAIL_DELAY}" size="5" style="text-align: center;"/>475 </label>498 </label> 499 <input type="text" name="UAM_ConfirmMail_Delay" value="{$UAM_CONFIRMMAIL_DELAY}" size="5" style="text-align: center;"/> 476 500 </li> 477 501 <li> … … 486 510 </label> 487 511 </li> 488 <a id="show_UAM_ConfirmMail" >{'UAM_Customize_messagesandmails'|translate}</a> 489 <a id="hide_UAM_ConfirmMail" style="display: none">{'hide details'|translate}</a> 512 <li style="list-style-type: none;"> 513 <a id="show_UAM_ConfirmMail" >{'UAM_Customize_messagesandmails'|translate}</a> 514 <a id="hide_UAM_ConfirmMail" style="display: none">{'hide details'|translate}</a> 515 </li> 490 516 <fieldset id="UAM_ConfirmMail" style="display: none"> 491 517 <ul> … … 550 576 {'UAM_Enable'|@translate} 551 577 </label> 552 </li>553 578 <ul> 554 579 <li> … … 575 600 </li> 576 601 </ul> 602 </li> 577 603 </ul> 578 604 </fieldset> … … 593 619 {'UAM_GhostTracker'|@translate} 594 620 </label> 595 <label for "UAM_GhostUser_Tracker_false">621 <label for="UAM_GhostUser_Tracker_false"> 596 622 <input id="UAM_GhostUser_Tracker_false" type="radio" value="false" {$UAM_GHOSTRACKER_FALSE} name="UAM_GhostUser_Tracker"/> 597 623 {'UAM_Disable'|@translate} 598 624 </label> 599 <label for "UAM_GhostUser_Tracker_true">625 <label for="UAM_GhostUser_Tracker_true"> 600 626 <input id="UAM_GhostUser_Tracker_true" type="radio" value="true" {$UAM_GHOSTRACKER_TRUE} name="UAM_GhostUser_Tracker"/> 601 627 {'UAM_GhostTracker_true'|@translate} 628 </label> 602 629 <input type="text" name="UAM_GhostTracker_DayLimit" value="{$UAM_GHOSTRACKER_DAYLIMIT}" size="5" style="text-align: center;"/> 603 </label>604 630 605 631 </li> … … 636 662 </ul> 637 663 </fieldset> 638 <br ><hr><br>664 <br/><hr/><br/> 639 665 <ul> 640 666 <li> … … 642 668 {'UAM_GTAuto'|@translate} 643 669 </label> 644 670 645 671 <label for="UAM_GTAuto_false"><input id="UAM_GTAuto_false" type="radio" value="false" {$UAM_GTAUTO_FALSE} name="UAM_GTAuto"/> 646 672 {'UAM_Disable'|@translate} 647 673 </label> 648 674 649 675 <label for="UAM_GTAuto_true"><input id="UAM_GTAuto_true" type="radio" value="true" {$UAM_GTAUTO_TRUE} name="UAM_GTAuto"/> 650 676 {'UAM_Enable'|@translate} 651 677 </label> 652 653 </li> 678 654 679 <ul id="UAM_GTAUTO" {if $UAM_GTAUTO_FALSE}style="display: none"{/if}> 655 680 <li> … … 657 682 {'UAM_GTAutoDel'|@translate} 658 683 </label> 659 684 660 685 <textarea class="uam_textfields" name="UAM_GTAutoDelText" id="UAM_GTAutoDelText" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_GTAUTODEL_TEXT}</textarea> 661 662 686 663 687 {if 'FCK_PATH'|@defined} 664 688 <div style="text-align:right;"> … … 667 691 {/if} 668 692 </li> 669 693 670 694 <li> 671 695 <label class="cluetip" title="{'UAM_GTAutoGp'|translate}|{'UAM_GTAutoGpTitle_d'|translate}"> 672 696 {'UAM_GTAutoGp'|@translate} 673 697 </label> 674 698 675 699 <ul> 676 700 <li> … … 681 705 {html_options name="UAM_Downgrade_Group" options=$Downgrade_Group.group_options selected=$Downgrade_Group.group_selected} 682 706 </div> 683 684 707 </li> 685 708 … … 691 714 {html_options name="UAM_Downgrade_Status" options=$Downgrade_Status.Status_options selected=$Downgrade_Status.Status_selected} 692 715 </div> 693 694 716 </li> 695 717 696 718 <li> 697 719 <label> … … 701 723 {html_options name="UAM_Downgrade_Level" options=$Downgrade_Level.Level_options selected=$Downgrade_Level.Level_selected} 702 724 </div> 703 704 725 </li> 705 726 </ul> 706 727 707 728 <ul> 708 729 <li> … … 717 738 {'UAM_Enable'|@translate} 718 739 </label> 719 740 720 741 <li> 721 742 <label class="cluetip" title="{'UAM_GTAutomail_Subject'|translate}|{'UAM_GTAutomail_Subject_d'|translate}"> 722 743 {'UAM_GTAutomail_Subject'|@translate} 723 744 </label> 724 745 725 746 <textarea class="uam_textfields" name="UAM_GTAutoMail_Subject" id="UAM_GTAutoMail_Subject" rows="5" {$TAG_INPUT_ENABLED}>{$UAM_GTAUTOMAIL_SUBJECT}</textarea> 726 727 747 </li> 728 729 <ul> 730 <li> 731 <label class="cluetip" title="{'UAM_GTAutomail_Text'|translate}|{'UAM_GTAutomail_Text_d'|translate}"> 732 {'UAM_GTAutomail_Text'|@translate} 733 </label> 734 735 <textarea class="uam_textfields" name="UAM_GTAutoMailText" id="UAM_GTAutoMailText" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_GTAUTOMAILTEXT}</textarea> 736 748 <li style="list-style-type: none;"> 749 <ul> 750 <li> 751 <label class="cluetip" title="{'UAM_GTAutomail_Text'|translate}|{'UAM_GTAutomail_Text_d'|translate}"> 752 {'UAM_GTAutomail_Text'|@translate} 753 </label> 754 755 <textarea class="uam_textfields" name="UAM_GTAutoMailText" id="UAM_GTAutoMailText" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_GTAUTOMAILTEXT}</textarea> 737 756 </li> 738 757 </ul> 758 </li> 739 759 </li> 740 760 </ul> 741 761 </li> 742 762 </ul> 743 </ ul>763 </li> 744 764 </ul> 745 765 </div> … … 787 807 788 808 <textarea class="uam_textfields" name="UAM_InfoMail_Subject" id="UAM_InfoMail_Subject" rows="5" {$TAG_INPUT_ENABLED}>{$UAM_INFOMAIL_SUBJECT}</textarea> 789 790 </li> 791 792 <ul>793 <li>794 <label class="cluetip" title="{'UAM_MailInfo_Text'|translate}|{'UAM_infotxtTitle_d'|translate}">795 {'UAM_MailInfo_Text'|@translate}796 </label>797 798 <textarea class="uam_textfields" name="UAM_MailInfo_Text" id="UAM_MailInfo_Text" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_MAILINFO_TEXT}</textarea>799 800 </ li>801 </ ul>809 </li> 810 811 <li style="list-style-type: none;"> 812 <ul> 813 <li> 814 <label class="cluetip" title="{'UAM_MailInfo_Text'|translate}|{'UAM_infotxtTitle_d'|translate}"> 815 {'UAM_MailInfo_Text'|@translate} 816 </label> 817 818 <textarea class="uam_textfields" name="UAM_MailInfo_Text" id="UAM_MailInfo_Text" rows="10" {$TAG_INPUT_ENABLED}>{$UAM_MAILINFO_TEXT}</textarea> 819 </li> 820 </ul> 821 </li> 802 822 <!-- 803 823 {* if 'FCK_PATH'|@defined *} … … 811 831 812 832 <ul> 813 814 815 816 </label> 817 <label for="UAM_AddURL2Mail_false"><input id="UAM_AddURL2Mail_false" value="false" {$UAM_ADDURL2MAIL_FALSE} name="UAM_AddURL2Mail" type="radio"/>818 {'UAM_Disable'|@translate}819 </label>820 <label for="UAM_AddURL2Mail_true"><input id="UAM_AddURL2Mail_true" value="true" {$UAM_ADDURL2MAIL_TRUE} name="UAM_AddURL2Mail" type="radio"/>821 {'UAM_Enable'|@translate}822 </label>823 833 <li> 834 <label class="cluetip" title="{'UAM_AddURL2Mail'|translate}|{'UAM_AddURL2Mail_d'|translate}"> 835 {'UAM_AddURL2Mail'|@translate} 836 </label> 837 <label for="UAM_AddURL2Mail_false"><input id="UAM_AddURL2Mail_false" value="false" {$UAM_ADDURL2MAIL_FALSE} name="UAM_AddURL2Mail" type="radio"/> 838 {'UAM_Disable'|@translate} 839 </label> 840 <label for="UAM_AddURL2Mail_true"><input id="UAM_AddURL2Mail_true" value="true" {$UAM_ADDURL2MAIL_TRUE} name="UAM_AddURL2Mail" type="radio"/> 841 {'UAM_Enable'|@translate} 842 </label> 843 </li> 824 844 <li> 825 845 <label class="cluetip" title="{'UAM_Tracking registered users'|translate}|{'UAM_Tracking registered users_d'|translate}"> 826 846 {'UAM_Tracking registered users'|@translate} 827 847 </label> 828 848 829 849 <label for="UAM_Add_LastVisit_Column_false"><input id="UAM_Add_LastVisit_Column_false" value="false" {$UAM_ADDLASTVISIT_FALSE} name="UAM_Add_LastVisit_Column" type="radio"/> 830 850 {'UAM_Disable'|@translate} … … 838 858 {'UAM_RedirToProfile'|@translate} 839 859 </label> 840 860 841 861 <label for="UAM_RedirToProfile_false"><input id="UAM_RedirToProfile_false" value="false" {$UAM_REDIRTOPROFILE_FALSE} name="UAM_RedirToProfile" type="radio"/> 842 862 {'UAM_Disable'|@translate} … … 852 872 {'UAM_CustomPasswRetr'|@translate} 853 873 </label> 854 874 855 875 <label for="UAM_CustomPasswRetr_false"><input id="UAM_CustomPasswRetr_false" value="false" {$UAM_CUSTOMPASSWRETR_FALSE} name="UAM_CustomPasswRetr" type="radio"/> 856 876 {'UAM_Disable'|@translate} … … 868 888 869 889 <p> 870 <input class="submit" type="submit" value="{'UAM_submit'|@translate}" name="submit" {$TAG_INPUT_ENABLED} > <input class="submit" type="submit" value="{'UAM_audit'|@translate}" name="audit"/>890 <input class="submit" type="submit" value="{'UAM_submit'|@translate}" name="submit" {$TAG_INPUT_ENABLED} /> <input class="submit" type="submit" value="{'UAM_audit'|@translate}" name="audit"/> 871 891 </p> 872 892 </form> 873 893 874 894 875 <div id="instruction Tips" class="instructionBlock" >895 <div id="instructionBkp" class="instructionBlock" > 876 896 <div id="Backup_header" class="instructionBlockHeaderCollapsed" onclick="uam_blockToggleDisplay('Backup_header', 'Backup')"> 877 897 <span class="cluetip" title="{'UAM_DumpTxt'|translate}|{'UAM_DumpTitle_d'|translate}">{'UAM_DumpTxt'|@translate}</span> 878 898 </div> 879 899 880 900 <div id="Backup" class="instructionBlockContent" style="display:none"> 881 <fieldset>882 <form method="post" action="" class="general">883 <p>884 {'UAM_Dump_Download'|@translate} 885 <input type="checkbox" name="dump_download" value="true" {$UAM_DUMP_DOWNLOAD}/>886 887 <input class="submit" type="submit" value="{'UAM_Save'|@translate}" name="save" {$TAG_INPUT_ENABLED}/>888 </p>889 </form>890 </fieldset>891 <fieldset>892 <form method="post" action="" class="general">893 <p>894 {'UAM_Restore'|@translate}895 <input class="submit" type="submit" value="{'UAM_Restore_File'|@translate}" name="restore" {$TAG_INPUT_ENABLED}/>896 </p>897 </form>898 </fieldset>901 <fieldset> 902 <form method="post" class="general"> 903 <p> 904 {'UAM_Dump_Download'|@translate} 905 <input type="checkbox" name="dump_download" value="true" {$UAM_DUMP_DOWNLOAD}/> 906 907 <input class="submit" type="submit" value="{'UAM_Save'|@translate}" name="save" {$TAG_INPUT_ENABLED}/> 908 </p> 909 </form> 910 </fieldset> 911 <fieldset> 912 <form method="post" class="general"> 913 <p> 914 {'UAM_Restore'|@translate} 915 <input class="submit" type="submit" value="{'UAM_Restore_File'|@translate}" name="restore" {$TAG_INPUT_ENABLED}/> 916 </p> 917 </form> 918 </fieldset> 899 919 </div> 900 901 920 </div> 902 921 … … 906 925 <span class="cluetip" title="{'UAM_Title4'|translate}|{'UAM_tipsTitle_d'|translate}">{'UAM_Title4'|@translate}</span> 907 926 </div> 908 927 909 928 <div id="Tips" class="instructionBlockContent" style="display:none"> 910 929 <fieldset> … … 930 949 </fieldset> 931 950 </div> 932 933 951 </div> 934 952 -
extensions/UserAdvManager/branches/2.6/admin/template/js/jquery.metadata.js
r6378 r26948 2 2 * Metadata - jQuery plugin for parsing metadata from elements 3 3 * 4 * Copyright (c) 2006 John Resig, Yehuda Katz, J �örn Zaefferer, Paul McLanahan4 * Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan 5 5 * 6 6 * Dual licensed under the MIT and GPL licenses: 7 7 * http://www.opensource.org/licenses/mit-license.php 8 8 * http://www.gnu.org/licenses/gpl.html 9 *10 * Revision: $Id$11 9 * 12 10 */ … … 19 17 * 20 18 * attr: Inside an attribute. The name parameter indicates *which* attribute. 21 * 19 * 22 20 * class: Inside the class attribute, wrapped in curly braces: { } 23 * 21 * 24 22 * elem: Inside a child element (e.g. a script tag). The 25 23 * name parameter indicates *which* element. 26 * 24 * 27 25 * The metadata for an element is loaded the first time the element is accessed via jQuery. 28 26 * 29 27 * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements 30 28 * matched by expr, then redefine the metadata type and run another $(expr) for other elements. 31 * 29 * 32 30 * @name $.metadata.setType 33 31 * … … 36 34 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 37 35 * @desc Reads metadata from the class attribute 38 * 36 * 39 37 * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p> 40 38 * @before $.metadata.setType("attr", "data") 41 39 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 42 40 * @desc Reads metadata from a "data" attribute 43 * 41 * 44 42 * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p> 45 43 * @before $.metadata.setType("elem", "script") 46 44 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 47 45 * @desc Reads metadata from a nested script element 48 * 46 * 49 47 * @param String type The encoding type 50 48 * @param String name The name of the attribute to be used to get metadata (optional) … … 62 60 type: 'class', 63 61 name: 'metadata', 64 cre: /( {.*})/,62 cre: /(\{.*\})/, 65 63 single: 'metadata' 66 64 }, … … 70 68 }, 71 69 get: function( elem, opts ){ 72 var settings = $.extend({},this.defaults,opts); 70 var data, m, e, attr, 71 settings = $.extend({},this.defaults,opts); 73 72 // check for empty string in single property 74 if ( !settings.single.length ) settings.single = 'metadata';75 76 vardata = $.data(elem, settings.single);73 if ( !settings.single.length ) { settings.single = 'metadata'; } 74 75 data = $.data(elem, settings.single); 77 76 // returned cached data if it already exists 78 if ( data ) return data;79 77 if ( data ) { return data; } 78 80 79 data = "{}"; 81 82 if ( settings.type == "class" ) { 83 var m = settings.cre.exec( elem.className ); 84 if ( m ) 85 data = m[1]; 86 } else if ( settings.type == "elem" ) { 87 if( !elem.getElementsByTagName ) 88 return undefined; 89 var e = elem.getElementsByTagName(settings.name); 90 if ( e.length ) 91 data = $.trim(e[0].innerHTML); 92 } else if ( elem.getAttribute != undefined ) { 93 var attr = elem.getAttribute( settings.name ); 94 if ( attr ) 95 data = attr; 80 81 if ( settings.type === "class" ) { 82 m = settings.cre.exec( elem.className ); 83 if ( m ) { data = m[1]; } 84 } else if ( settings.type === "elem" ) { 85 if( !elem.getElementsByTagName ) { return undefined; } 86 e = elem.getElementsByTagName(settings.name); 87 if ( e.length ) { data = $.trim(e[0].innerHTML); } 88 } else if ( elem.getAttribute !== undefined ) { 89 attr = elem.getAttribute( settings.name ); 90 if ( attr ) { data = attr; } 96 91 } 97 98 if ( data.indexOf( '{' ) <0 ) 99 data = "{" + data + "}"; 100 92 93 if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; } 94 101 95 data = eval("(" + data + ")"); 102 96 103 97 $.data( elem, settings.single, data ); 104 98 return data; -
extensions/UserAdvManager/branches/2.6/admin/template/js/jquery.tablesorter.js
r8875 r26948 1 /* 2 * 3 * TableSorter 2.0 - Client-side table sorting with ease! 4 * Version 2.0.5b 5 * @requires jQuery v1.2.3 6 * 7 * Copyright (c) 2007 Christian Bach 8 * Examples and docs at: http://tablesorter.com 9 * Dual licensed under the MIT and GPL licenses: 10 * http://www.opensource.org/licenses/mit-license.php 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 */ 14 /** 15 * 16 * @description Create a sortable table with multi-column sorting capabilitys 17 * 18 * @example $('table').tablesorter(); 19 * @desc Create a simple tablesorter interface. 20 * 21 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] }); 22 * @desc Create a tablesorter interface and sort on the first and secound column column headers. 23 * 24 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } }); 25 * 26 * @desc Create a tablesorter interface and disableing the first and second column headers. 27 * 28 * 29 * @example $('table').tablesorter({ headers: { 0: {sorter:"integer"}, 1: {sorter:"currency"} } }); 30 * 31 * @desc Create a tablesorter interface and set a column parser for the first 32 * and second column. 33 * 34 * 35 * @param Object 36 * settings An object literal containing key/value pairs to provide 37 * optional settings. 38 * 39 * 40 * @option String cssHeader (optional) A string of the class name to be appended 41 * to sortable tr elements in the thead of the table. Default value: 42 * "header" 43 * 44 * @option String cssAsc (optional) A string of the class name to be appended to 45 * sortable tr elements in the thead on a ascending sort. Default value: 46 * "headerSortUp" 47 * 48 * @option String cssDesc (optional) A string of the class name to be appended 49 * to sortable tr elements in the thead on a descending sort. Default 50 * value: "headerSortDown" 51 * 52 * @option String sortInitialOrder (optional) A string of the inital sorting 53 * order can be asc or desc. Default value: "asc" 54 * 55 * @option String sortMultisortKey (optional) A string of the multi-column sort 56 * key. Default value: "shiftKey" 57 * 58 * @option String textExtraction (optional) A string of the text-extraction 59 * method to use. For complex html structures inside td cell set this 60 * option to "complex", on large tables the complex option can be slow. 61 * Default value: "simple" 62 * 63 * @option Object headers (optional) An array containing the forces sorting 64 * rules. This option let's you specify a default sorting rule. Default 65 * value: null 66 * 67 * @option Array sortList (optional) An array containing the forces sorting 68 * rules. This option let's you specify a default sorting rule. Default 69 * value: null 70 * 71 * @option Array sortForce (optional) An array containing forced sorting rules. 72 * This option let's you specify a default sorting rule, which is 73 * prepended to user-selected rules. Default value: null 74 * 75 * @option Boolean sortLocaleCompare (optional) Boolean flag indicating whatever 76 * to use String.localeCampare method or not. Default set to true. 77 * 78 * 79 * @option Array sortAppend (optional) An array containing forced sorting rules. 80 * This option let's you specify a default sorting rule, which is 81 * appended to user-selected rules. Default value: null 82 * 83 * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter 84 * should apply fixed widths to the table columns. This is usefull when 85 * using the pager companion plugin. This options requires the dimension 86 * jquery plugin. Default value: false 87 * 88 * @option Boolean cancelSelection (optional) Boolean flag indicating if 89 * tablesorter should cancel selection of the table headers text. 90 * Default value: true 91 * 92 * @option Boolean debug (optional) Boolean flag indicating if tablesorter 93 * should display debuging information usefull for development. 94 * 95 * @type jQuery 96 * 97 * @name tablesorter 98 * 99 * @cat Plugins/Tablesorter 100 * 101 * @author Christian Bach/christian.bach@polyester.se 102 */ 103 104 (function ($) { 105 $.extend({ 106 tablesorter: new 107 function () { 108 109 var parsers = [], 110 widgets = []; 111 112 this.defaults = { 113 cssHeader: "header", 114 cssAsc: "headerSortUp", 115 cssDesc: "headerSortDown", 116 cssChildRow: "expand-child", 117 sortInitialOrder: "asc", 118 sortMultiSortKey: "shiftKey", 119 sortForce: null, 120 sortAppend: null, 121 sortLocaleCompare: true, 122 textExtraction: "simple", 123 parsers: {}, widgets: [], 124 widgetZebra: { 125 css: ["even", "odd"] 126 }, headers: {}, widthFixed: false, 127 cancelSelection: true, 128 sortList: [], 129 headerList: [], 130 dateFormat: "us", 131 decimal: '/\.|\,/g', 132 onRenderHeader: null, 133 selectorHeaders: 'thead th', 134 debug: false 135 }; 136 137 /* debuging utils */ 138 139 function benchmark(s, d) { 140 log(s + "," + (new Date().getTime() - d.getTime()) + "ms"); 141 } 142 143 this.benchmark = benchmark; 144 145 function log(s) { 146 if (typeof console != "undefined" && typeof console.debug != "undefined") { 147 console.log(s); 148 } else { 149 alert(s); 150 } 151 } 152 153 /* parsers utils */ 154 155 function buildParserCache(table, $headers) { 156 157 if (table.config.debug) { 158 var parsersDebug = ""; 159 } 160 161 if (table.tBodies.length == 0) return; // In the case of empty tables 162 var rows = table.tBodies[0].rows; 163 164 if (rows[0]) { 165 166 var list = [], 167 cells = rows[0].cells, 168 l = cells.length; 169 170 for (var i = 0; i < l; i++) { 171 172 var p = false; 173 174 if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) { 175 176 p = getParserById($($headers[i]).metadata().sorter); 177 178 } else if ((table.config.headers[i] && table.config.headers[i].sorter)) { 179 180 p = getParserById(table.config.headers[i].sorter); 181 } 182 if (!p) { 183 184 p = detectParserForColumn(table, rows, -1, i); 185 } 186 187 if (table.config.debug) { 188 parsersDebug += "column:" + i + " parser:" + p.id + "\n"; 189 } 190 191 list.push(p); 192 } 193 } 194 195 if (table.config.debug) { 196 log(parsersDebug); 197 } 198 199 return list; 200 }; 201 202 function detectParserForColumn(table, rows, rowIndex, cellIndex) { 203 var l = parsers.length, 204 node = false, 205 nodeValue = false, 206 keepLooking = true; 207 while (nodeValue == '' && keepLooking) { 208 rowIndex++; 209 if (rows[rowIndex]) { 210 node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex); 211 nodeValue = trimAndGetNodeText(table.config, node); 212 if (table.config.debug) { 213 log('Checking if value was empty on row:' + rowIndex); 214 } 215 } else { 216 keepLooking = false; 217 } 218 } 219 for (var i = 1; i < l; i++) { 220 if (parsers[i].is(nodeValue, table, node)) { 221 return parsers[i]; 222 } 223 } 224 // 0 is always the generic parser (text) 225 return parsers[0]; 226 } 227 228 function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) { 229 return rows[rowIndex].cells[cellIndex]; 230 } 231 232 function trimAndGetNodeText(config, node) { 233 return $.trim(getElementText(config, node)); 234 } 235 236 function getParserById(name) { 237 var l = parsers.length; 238 for (var i = 0; i < l; i++) { 239 if (parsers[i].id.toLowerCase() == name.toLowerCase()) { 240 return parsers[i]; 241 } 242 } 243 return false; 244 } 245 246 /* utils */ 247 248 function buildCache(table) { 249 250 if (table.config.debug) { 251 var cacheTime = new Date(); 252 } 253 254 var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0, 255 totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0, 256 parsers = table.config.parsers, 257 cache = { 258 row: [], 259 normalized: [] 260 }; 261 262 for (var i = 0; i < totalRows; ++i) { 263 264 /** Add the table data to main data array */ 265 var c = $(table.tBodies[0].rows[i]), 266 cols = []; 267 268 // if this is a child row, add it to the last row's children and 269 // continue to the next row 270 if (c.hasClass(table.config.cssChildRow)) { 271 cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c); 272 // go to the next for loop 273 continue; 274 } 275 276 cache.row.push(c); 277 278 for (var j = 0; j < totalCells; ++j) { 279 cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j])); 280 } 281 282 cols.push(cache.normalized.length); // add position for rowCache 283 cache.normalized.push(cols); 284 cols = null; 285 }; 286 287 if (table.config.debug) { 288 benchmark("Building cache for " + totalRows + " rows:", cacheTime); 289 } 290 291 return cache; 292 }; 293 294 function getElementText(config, node) { 295 296 var text = ""; 297 298 if (!node) return ""; 299 300 if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false; 301 302 if (config.textExtraction == "simple") { 303 if (config.supportsTextContent) { 304 text = node.textContent; 305 } else { 306 if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) { 307 text = node.childNodes[0].innerHTML; 308 } else { 309 text = node.innerHTML; 310 } 311 } 312 } else { 313 if (typeof(config.textExtraction) == "function") { 314 text = config.textExtraction(node); 315 } else { 316 text = $(node).text(); 317 } 318 } 319 return text; 320 } 321 322 function appendToTable(table, cache) { 323 324 if (table.config.debug) { 325 var appendTime = new Date() 326 } 327 328 var c = cache, 329 r = c.row, 330 n = c.normalized, 331 totalRows = n.length, 332 checkCell = (n[0].length - 1), 333 tableBody = $(table.tBodies[0]), 334 rows = []; 335 336 337 for (var i = 0; i < totalRows; i++) { 338 var pos = n[i][checkCell]; 339 340 rows.push(r[pos]); 341 342 if (!table.config.appender) { 343 344 //var o = ; 345 var l = r[pos].length; 346 for (var j = 0; j < l; j++) { 347 tableBody[0].appendChild(r[pos][j]); 348 } 349 350 // 351 } 352 } 353 354 355 356 if (table.config.appender) { 357 358 table.config.appender(table, rows); 359 } 360 361 rows = null; 362 363 if (table.config.debug) { 364 benchmark("Rebuilt table:", appendTime); 365 } 366 367 // apply table widgets 368 applyWidget(table); 369 370 // trigger sortend 371 setTimeout(function () { 372 $(table).trigger("sortEnd"); 373 }, 0); 374 375 }; 376 377 function buildHeaders(table) { 378 379 if (table.config.debug) { 380 var time = new Date(); 381 } 382 383 var meta = ($.metadata) ? true : false; 384 385 var header_index = computeTableHeaderCellIndexes(table); 386 387 $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) { 388 389 this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; 390 // this.column = index; 391 this.order = formatSortingOrder(table.config.sortInitialOrder); 392 393 394 this.count = this.order; 395 396 if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true; 397 if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index); 398 399 if (!this.sortDisabled) { 400 var $th = $(this).addClass(table.config.cssHeader); 401 if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th); 402 } 403 404 // add cell to headerList 405 table.config.headerList[index] = this; 406 }); 407 408 if (table.config.debug) { 409 benchmark("Built headers:", time); 410 log($tableHeaders); 411 } 412 413 return $tableHeaders; 414 415 }; 416 417 // from: 418 // http://www.javascripttoolbox.com/lib/table/examples.php 419 // http://www.javascripttoolbox.com/temp/table_cellindex.html 420 421 422 function computeTableHeaderCellIndexes(t) { 423 var matrix = []; 424 var lookup = {}; 425 var thead = t.getElementsByTagName('THEAD')[0]; 426 var trs = thead.getElementsByTagName('TR'); 427 428 for (var i = 0; i < trs.length; i++) { 429 var cells = trs[i].cells; 430 for (var j = 0; j < cells.length; j++) { 431 var c = cells[j]; 432 433 var rowIndex = c.parentNode.rowIndex; 434 var cellId = rowIndex + "-" + c.cellIndex; 435 var rowSpan = c.rowSpan || 1; 436 var colSpan = c.colSpan || 1 437 var firstAvailCol; 438 if (typeof(matrix[rowIndex]) == "undefined") { 439 matrix[rowIndex] = []; 440 } 441 // Find first available column in the first row 442 for (var k = 0; k < matrix[rowIndex].length + 1; k++) { 443 if (typeof(matrix[rowIndex][k]) == "undefined") { 444 firstAvailCol = k; 445 break; 446 } 447 } 448 lookup[cellId] = firstAvailCol; 449 for (var k = rowIndex; k < rowIndex + rowSpan; k++) { 450 if (typeof(matrix[k]) == "undefined") { 451 matrix[k] = []; 452 } 453 var matrixrow = matrix[k]; 454 for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) { 455 matrixrow[l] = "x"; 456 } 457 } 458 } 459 } 460 return lookup; 461 } 462 463 function checkCellColSpan(table, rows, row) { 464 var arr = [], 465 r = table.tHead.rows, 466 c = r[row].cells; 467 468 for (var i = 0; i < c.length; i++) { 469 var cell = c[i]; 470 471 if (cell.colSpan > 1) { 472 arr = arr.concat(checkCellColSpan(table, headerArr, row++)); 473 } else { 474 if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) { 475 arr.push(cell); 476 } 477 // headerArr[row] = (i+row); 478 } 479 } 480 return arr; 481 }; 482 483 function checkHeaderMetadata(cell) { 484 if (($.metadata) && ($(cell).metadata().sorter === false)) { 485 return true; 486 }; 487 return false; 488 } 489 490 function checkHeaderOptions(table, i) { 491 if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { 492 return true; 493 }; 494 return false; 495 } 496 497 function checkHeaderOptionsSortingLocked(table, i) { 498 if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder; 499 return false; 500 } 501 502 function applyWidget(table) { 503 var c = table.config.widgets; 504 var l = c.length; 505 for (var i = 0; i < l; i++) { 506 507 getWidgetById(c[i]).format(table); 508 } 509 510 } 511 512 function getWidgetById(name) { 513 var l = widgets.length; 514 for (var i = 0; i < l; i++) { 515 if (widgets[i].id.toLowerCase() == name.toLowerCase()) { 516 return widgets[i]; 517 } 518 } 519 }; 520 521 function formatSortingOrder(v) { 522 if (typeof(v) != "Number") { 523 return (v.toLowerCase() == "desc") ? 1 : 0; 524 } else { 525 return (v == 1) ? 1 : 0; 526 } 527 } 528 529 function isValueInArray(v, a) { 530 var l = a.length; 531 for (var i = 0; i < l; i++) { 532 if (a[i][0] == v) { 533 return true; 534 } 535 } 536 return false; 537 } 538 539 function setHeadersCss(table, $headers, list, css) { 540 // remove all header information 541 $headers.removeClass(css[0]).removeClass(css[1]); 542 543 var h = []; 544 $headers.each(function (offset) { 545 if (!this.sortDisabled) { 546 h[this.column] = $(this); 547 } 548 }); 549 550 var l = list.length; 551 for (var i = 0; i < l; i++) { 552 h[list[i][0]].addClass(css[list[i][1]]); 553 } 554 } 555 556 function fixColumnWidth(table, $headers) { 557 var c = table.config; 558 if (c.widthFixed) { 559 var colgroup = $('<colgroup>'); 560 $("tr:first td", table.tBodies[0]).each(function () { 561 colgroup.append($('<col>').css('width', $(this).width())); 562 }); 563 $(table).prepend(colgroup); 564 }; 565 } 566 567 function updateHeaderSortCount(table, sortList) { 568 var c = table.config, 569 l = sortList.length; 570 for (var i = 0; i < l; i++) { 571 var s = sortList[i], 572 o = c.headerList[s[0]]; 573 o.count = s[1]; 574 o.count++; 575 } 576 } 577 578 /* sorting methods */ 579 580 function multisort(table, sortList, cache) { 581 582 if (table.config.debug) { 583 var sortTime = new Date(); 584 } 585 586 var dynamicExp = "var sortWrapper = function(a,b) {", 587 l = sortList.length; 588 589 // TODO: inline functions. 590 for (var i = 0; i < l; i++) { 591 592 var c = sortList[i][0]; 593 var order = sortList[i][1]; 594 // var s = (getCachedSortType(table.config.parsers,c) == "text") ? 595 // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? 596 // "sortNumeric" : "sortNumericDesc"); 597 // var s = (table.config.parsers[c].type == "text") ? ((order == 0) 598 // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ? 599 // makeSortNumeric(c) : makeSortNumericDesc(c)); 600 var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c)); 601 var e = "e" + i; 602 603 dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c 604 // + "]); "; 605 dynamicExp += "if(" + e + ") { return " + e + "; } "; 606 dynamicExp += "else { "; 607 608 } 609 610 // if value is the same keep orignal order 611 var orgOrderCol = cache.normalized[0].length - 1; 612 dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];"; 613 614 for (var i = 0; i < l; i++) { 615 dynamicExp += "}; "; 616 } 617 618 dynamicExp += "return 0; "; 619 dynamicExp += "}; "; 620 621 if (table.config.debug) { 622 benchmark("Evaling expression:" + dynamicExp, new Date()); 623 } 624 625 eval(dynamicExp); 626 627 cache.normalized.sort(sortWrapper); 628 629 if (table.config.debug) { 630 benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime); 631 } 632 633 return cache; 634 }; 635 636 function makeSortFunction(type, direction, index) { 637 var a = "a[" + index + "]", 638 b = "b[" + index + "]"; 639 if (type == 'text' && direction == 'asc') { 640 return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));"; 641 } else if (type == 'text' && direction == 'desc') { 642 return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));"; 643 } else if (type == 'numeric' && direction == 'asc') { 644 return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));"; 645 } else if (type == 'numeric' && direction == 'desc') { 646 return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));"; 647 } 648 }; 649 650 function makeSortText(i) { 651 return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));"; 652 }; 653 654 function makeSortTextDesc(i) { 655 return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));"; 656 }; 657 658 function makeSortNumeric(i) { 659 return "a[" + i + "]-b[" + i + "];"; 660 }; 661 662 function makeSortNumericDesc(i) { 663 return "b[" + i + "]-a[" + i + "];"; 664 }; 665 666 function sortText(a, b) { 667 if (table.config.sortLocaleCompare) return a.localeCompare(b); 668 return ((a < b) ? -1 : ((a > b) ? 1 : 0)); 669 }; 670 671 function sortTextDesc(a, b) { 672 if (table.config.sortLocaleCompare) return b.localeCompare(a); 673 return ((b < a) ? -1 : ((b > a) ? 1 : 0)); 674 }; 675 676 function sortNumeric(a, b) { 677 return a - b; 678 }; 679 680 function sortNumericDesc(a, b) { 681 return b - a; 682 }; 683 684 function getCachedSortType(parsers, i) { 685 return parsers[i].type; 686 }; /* public methods */ 687 this.construct = function (settings) { 688 return this.each(function () { 689 // if no thead or tbody quit. 690 if (!this.tHead || !this.tBodies) return; 691 // declare 692 var $this, $document, $headers, cache, config, shiftDown = 0, 693 sortOrder; 694 // new blank config object 695 this.config = {}; 696 // merge and extend. 697 config = $.extend(this.config, $.tablesorter.defaults, settings); 698 // store common expression for speed 699 $this = $(this); 700 // save the settings where they read 701 $.data(this, "tablesorter", config); 702 // build headers 703 $headers = buildHeaders(this); 704 // try to auto detect column type, and store in tables config 705 this.config.parsers = buildParserCache(this, $headers); 706 // build the cache for the tbody cells 707 cache = buildCache(this); 708 // get the css class names, could be done else where. 709 var sortCSS = [config.cssDesc, config.cssAsc]; 710 // fixate columns if the users supplies the fixedWidth option 711 fixColumnWidth(this); 712 // apply event handling to headers 713 // this is to big, perhaps break it out? 714 $headers.click( 715 716 function (e) { 717 var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0; 718 if (!this.sortDisabled && totalRows > 0) { 719 // Only call sortStart if sorting is 720 // enabled. 721 $this.trigger("sortStart"); 722 // store exp, for speed 723 var $cell = $(this); 724 // get current column index 725 var i = this.column; 726 // get current column sort order 727 this.order = this.count++ % 2; 728 // always sort on the locked order. 729 if(this.lockedOrder) this.order = this.lockedOrder; 730 731 // user only whants to sort on one 732 // column 733 if (!e[config.sortMultiSortKey]) { 734 // flush the sort list 735 config.sortList = []; 736 if (config.sortForce != null) { 737 var a = config.sortForce; 738 for (var j = 0; j < a.length; j++) { 739 if (a[j][0] != i) { 740 config.sortList.push(a[j]); 741 } 742 } 743 } 744 // add column to sort list 745 config.sortList.push([i, this.order]); 746 // multi column sorting 747 } else { 748 // the user has clicked on an all 749 // ready sortet column. 750 if (isValueInArray(i, config.sortList)) { 751 // revers the sorting direction 752 // for all tables. 753 for (var j = 0; j < config.sortList.length; j++) { 754 var s = config.sortList[j], 755 o = config.headerList[s[0]]; 756 if (s[0] == i) { 757 o.count = s[1]; 758 o.count++; 759 s[1] = o.count % 2; 760 } 761 } 762 } else { 763 // add column to sort list array 764 config.sortList.push([i, this.order]); 765 } 766 }; 767 setTimeout(function () { 768 // set css for headers 769 setHeadersCss($this[0], $headers, config.sortList, sortCSS); 770 appendToTable( 771 $this[0], multisort( 772 $this[0], config.sortList, cache) 773 ); 774 }, 1); 775 // stop normal event by returning false 776 return false; 777 } 778 // cancel selection 779 }).mousedown(function () { 780 if (config.cancelSelection) { 781 this.onselectstart = function () { 782 return false 783 }; 784 return false; 785 } 786 }); 787 // apply easy methods that trigger binded events 788 $this.bind("update", function () { 789 var me = this; 790 setTimeout(function () { 791 // rebuild parsers. 792 me.config.parsers = buildParserCache( 793 me, $headers); 794 // rebuild the cache map 795 cache = buildCache(me); 796 }, 1); 797 }).bind("updateCell", function (e, cell) { 798 var config = this.config; 799 // get position from the dom. 800 var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex]; 801 // update cache 802 cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format( 803 getElementText(config, cell), cell); 804 }).bind("sorton", function (e, list) { 805 $(this).trigger("sortStart"); 806 config.sortList = list; 807 // update and store the sortlist 808 var sortList = config.sortList; 809 // update header count index 810 updateHeaderSortCount(this, sortList); 811 // set css for headers 812 setHeadersCss(this, $headers, sortList, sortCSS); 813 // sort the table and append it to the dom 814 appendToTable(this, multisort(this, sortList, cache)); 815 }).bind("appendCache", function () { 816 appendToTable(this, cache); 817 }).bind("applyWidgetId", function (e, id) { 818 getWidgetById(id).format(this); 819 }).bind("applyWidgets", function () { 820 // apply widgets 821 applyWidget(this); 822 }); 823 if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { 824 config.sortList = $(this).metadata().sortlist; 825 } 826 // if user has supplied a sort list to constructor. 827 if (config.sortList.length > 0) { 828 $this.trigger("sorton", [config.sortList]); 829 } 830 // apply widgets 831 applyWidget(this); 832 }); 833 }; 834 this.addParser = function (parser) { 835 var l = parsers.length, 836 a = true; 837 for (var i = 0; i < l; i++) { 838 if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) { 839 a = false; 840 } 841 } 842 if (a) { 843 parsers.push(parser); 844 }; 845 }; 846 this.addWidget = function (widget) { 847 widgets.push(widget); 848 }; 849 this.formatFloat = function (s) { 850 var i = parseFloat(s); 851 return (isNaN(i)) ? 0 : i; 852 }; 853 this.formatInt = function (s) { 854 var i = parseInt(s); 855 return (isNaN(i)) ? 0 : i; 856 }; 857 this.isDigit = function (s, config) { 858 // replace all an wanted chars and match. 859 return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, ''))); 860 }; 861 this.clearTableBody = function (table) { 862 if ($.browser.msie) { 863 function empty() { 864 while (this.firstChild) 865 this.removeChild(this.firstChild); 866 } 867 empty.apply(table.tBodies[0]); 868 } else { 869 table.tBodies[0].innerHTML = ""; 870 } 871 }; 872 } 873 }); 874 875 // extend plugin scope 876 $.fn.extend({ 877 tablesorter: $.tablesorter.construct 878 }); 879 880 // make shortcut 881 var ts = $.tablesorter; 882 883 // add default parsers 884 ts.addParser({ 885 id: "text", 886 is: function (s) { 887 return true; 888 }, format: function (s) { 889 return $.trim(s.toLocaleLowerCase()); 890 }, type: "text" 891 }); 892 893 ts.addParser({ 894 id: "digit", 895 is: function (s, table) { 896 var c = table.config; 897 return $.tablesorter.isDigit(s, c); 898 }, format: function (s) { 899 return $.tablesorter.formatFloat(s); 900 }, type: "numeric" 901 }); 902 903 ts.addParser({ 904 id: "currency", 905 is: function (s) { 906 return /^[£$€?.]/.test(s); 907 }, format: function (s) { 908 return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), "")); 909 }, type: "numeric" 910 }); 911 912 ts.addParser({ 913 id: "ipAddress", 914 is: function (s) { 915 return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s); 916 }, format: function (s) { 917 var a = s.split("."), 918 r = "", 919 l = a.length; 920 for (var i = 0; i < l; i++) { 921 var item = a[i]; 922 if (item.length == 2) { 923 r += "0" + item; 924 } else { 925 r += item; 926 } 927 } 928 return $.tablesorter.formatFloat(r); 929 }, type: "numeric" 930 }); 931 932 ts.addParser({ 933 id: "url", 934 is: function (s) { 935 return /^(https?|ftp|file):\/\/$/.test(s); 936 }, format: function (s) { 937 return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')); 938 }, type: "text" 939 }); 940 941 ts.addParser({ 942 id: "isoDate", 943 is: function (s) { 944 return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s); 945 }, format: function (s) { 946 return $.tablesorter.formatFloat((s != "") ? new Date(s.replace( 947 new RegExp(/-/g), "/")).getTime() : "0"); 948 }, type: "numeric" 949 }); 950 951 ts.addParser({ 952 id: "percent", 953 is: function (s) { 954 return /\%$/.test($.trim(s)); 955 }, format: function (s) { 956 return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), "")); 957 }, type: "numeric" 958 }); 959 960 ts.addParser({ 961 id: "usLongDate", 962 is: function (s) { 963 return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)); 964 }, format: function (s) { 965 return $.tablesorter.formatFloat(new Date(s).getTime()); 966 }, type: "numeric" 967 }); 968 969 ts.addParser({ 970 id: "shortDate", 971 is: function (s) { 972 return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s); 973 }, format: function (s, table) { 974 var c = table.config; 975 s = s.replace(/\-/g, "/"); 976 if (c.dateFormat == "us") { 977 // reformat the string in ISO format 978 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2"); 979 } else if (c.dateFormat == "uk") { 980 // reformat the string in ISO format 981 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1"); 982 } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") { 983 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3"); 984 } 985 return $.tablesorter.formatFloat(new Date(s).getTime()); 986 }, type: "numeric" 987 }); 988 ts.addParser({ 989 id: "time", 990 is: function (s) { 991 return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s); 992 }, format: function (s) { 993 return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime()); 994 }, type: "numeric" 995 }); 996 ts.addParser({ 997 id: "metadata", 998 is: function (s) { 999 return false; 1000 }, format: function (s, table, cell) { 1001 var c = table.config, 1002 p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; 1003 return $(cell).metadata()[p]; 1004 }, type: "numeric" 1005 }); 1006 // add default widgets 1007 ts.addWidget({ 1008 id: "zebra", 1009 format: function (table) { 1010 if (table.config.debug) { 1011 var time = new Date(); 1012 } 1013 var $tr, row = -1, 1014 odd; 1015 // loop through the visible rows 1016 $("tr:visible", table.tBodies[0]).each(function (i) { 1017 $tr = $(this); 1018 // style children rows the same way the parent 1019 // row was styled 1020 if (!$tr.hasClass(table.config.cssChildRow)) row++; 1021 odd = (row % 2 == 0); 1022 $tr.removeClass( 1023 table.config.widgetZebra.css[odd ? 0 : 1]).addClass( 1024 table.config.widgetZebra.css[odd ? 1 : 0]) 1025 }); 1026 if (table.config.debug) { 1027 $.tablesorter.benchmark("Applying Zebra widget", time); 1028 } 1029 } 1030 }); 1 /**! 2 * TableSorter 2.14.5 - Client-side table sorting with ease! 3 * @requires jQuery v1.2.6+ 4 * 5 * Copyright (c) 2007 Christian Bach 6 * Examples and docs at: http://tablesorter.com 7 * Dual licensed under the MIT and GPL licenses: 8 * http://www.opensource.org/licenses/mit-license.php 9 * http://www.gnu.org/licenses/gpl.html 10 * 11 * @type jQuery 12 * @name tablesorter 13 * @cat Plugins/Tablesorter 14 * @author Christian Bach/christian.bach@polyester.se 15 * @contributor Rob Garrison/https://github.com/Mottie/tablesorter 16 */ 17 /*jshint browser:true, jquery:true, unused:false, expr: true */ 18 /*global console:false, alert:false */ 19 !(function($) { 20 "use strict"; 21 $.extend({ 22 /*jshint supernew:true */ 23 tablesorter: new function() { 24 25 var ts = this; 26 27 ts.version = "2.14.5"; 28 29 ts.parsers = []; 30 ts.widgets = []; 31 ts.defaults = { 32 33 // *** appearance 34 theme : 'default', // adds tablesorter-{theme} to the table for styling 35 widthFixed : false, // adds colgroup to fix widths of columns 36 showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered. 37 38 headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> (class from cssIcon) 39 onRenderTemplate : null, // function(index, template){ return template; }, (template is a string) 40 onRenderHeader : null, // function(index){}, (nothing to return) 41 42 // *** functionality 43 cancelSelection : true, // prevent text selection in the header 44 tabIndex : true, // add tabindex to header for keyboard accessibility 45 dateFormat : 'mmddyyyy', // other options: "ddmmyyy" or "yyyymmdd" 46 sortMultiSortKey : 'shiftKey', // key used to select additional columns 47 sortResetKey : 'ctrlKey', // key used to remove sorting on a column 48 usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89" 49 delayInit : false, // if false, the parsed table contents will not update until the first sort 50 serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used. 51 52 // *** sort options 53 headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. 54 ignoreCase : true, // ignore case while sorting 55 sortForce : null, // column(s) first sorted; always applied 56 sortList : [], // Initial sort order; applied initially; updated when manually sorted 57 sortAppend : null, // column(s) sorted last; always applied 58 sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained 59 60 sortInitialOrder : 'asc', // sort direction on first click 61 sortLocaleCompare: false, // replace equivalent character (accented characters) 62 sortReset : false, // third click on the header will reset column to default - unsorted 63 sortRestart : false, // restart sort to "sortInitialOrder" when clicking on previously unsorted columns 64 65 emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero 66 stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero 67 textExtraction : 'simple', // text extraction method/function - function(node, table, cellIndex){} 68 textSorter : null, // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText] 69 numberSorter : null, // choose overall numeric sorter function(a, b, direction, maxColumnValue) 70 71 // *** widget options 72 widgets: [], // method to add widgets, e.g. widgets: ['zebra'] 73 widgetOptions : { 74 zebra : [ 'even', 'odd' ] // zebra widget alternating row class names 75 }, 76 initWidgets : true, // apply widgets on tablesorter initialization 77 78 // *** callbacks 79 initialized : null, // function(table){}, 80 81 // *** extra css class names 82 tableClass : '', 83 cssAsc : '', 84 cssDesc : '', 85 cssHeader : '', 86 cssHeaderRow : '', 87 cssProcessing : '', // processing icon applied to header during sort/filter 88 89 cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent 90 cssIcon : 'tablesorter-icon', // if this class exists, a <i> will be added to the header automatically 91 cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!) 92 93 // *** selectors 94 selectorHeaders : '> thead th, > thead td', 95 selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort 96 selectorRemove : '.remove-me', 97 98 // *** advanced 99 debug : false, 100 101 // *** Internal variables 102 headerList: [], 103 empties: {}, 104 strings: {}, 105 parsers: [] 106 107 // deprecated; but retained for backwards compatibility 108 // widgetZebra: { css: ["even", "odd"] } 109 110 }; 111 112 // internal css classes - these will ALWAYS be added to 113 // the table and MUST only contain one class name - fixes #381 114 ts.css = { 115 table : 'tablesorter', 116 childRow : 'tablesorter-childRow', 117 header : 'tablesorter-header', 118 headerRow : 'tablesorter-headerRow', 119 icon : 'tablesorter-icon', 120 info : 'tablesorter-infoOnly', 121 processing : 'tablesorter-processing', 122 sortAsc : 'tablesorter-headerAsc', 123 sortDesc : 'tablesorter-headerDesc' 124 }; 125 126 /* debuging utils */ 127 function log() { 128 var s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : arguments[0]; 129 if (typeof console !== "undefined" && typeof console.log !== "undefined") { 130 console.log(s); 131 } else { 132 alert(s); 133 } 134 } 135 136 function benchmark(s, d) { 137 log(s + " (" + (new Date().getTime() - d.getTime()) + "ms)"); 138 } 139 140 ts.log = log; 141 ts.benchmark = benchmark; 142 143 // $.isEmptyObject from jQuery v1.4 144 function isEmptyObject(obj) { 145 /*jshint forin: false */ 146 for (var name in obj) { 147 return false; 148 } 149 return true; 150 } 151 152 function getElementText(table, node, cellIndex) { 153 if (!node) { return ""; } 154 var c = table.config, 155 t = c.textExtraction, text = ""; 156 if (t === "simple") { 157 if (c.supportsTextContent) { 158 text = node.textContent; // newer browsers support this 159 } else { 160 text = $(node).text(); 161 } 162 } else { 163 if (typeof t === "function") { 164 text = t(node, table, cellIndex); 165 } else if (typeof t === "object" && t.hasOwnProperty(cellIndex)) { 166 text = t[cellIndex](node, table, cellIndex); 167 } else { 168 text = c.supportsTextContent ? node.textContent : $(node).text(); 169 } 170 } 171 return $.trim(text); 172 } 173 174 function detectParserForColumn(table, rows, rowIndex, cellIndex) { 175 var cur, 176 i = ts.parsers.length, 177 node = false, 178 nodeValue = '', 179 keepLooking = true; 180 while (nodeValue === '' && keepLooking) { 181 rowIndex++; 182 if (rows[rowIndex]) { 183 node = rows[rowIndex].cells[cellIndex]; 184 nodeValue = getElementText(table, node, cellIndex); 185 if (table.config.debug) { 186 log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); 187 } 188 } else { 189 keepLooking = false; 190 } 191 } 192 while (--i >= 0) { 193 cur = ts.parsers[i]; 194 // ignore the default text parser because it will always be true 195 if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node)) { 196 return cur; 197 } 198 } 199 // nothing found, return the generic parser (text) 200 return ts.getParserById('text'); 201 } 202 203 function buildParserCache(table) { 204 var c = table.config, 205 // update table bodies in case we start with an empty table 206 tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'), 207 rows, list, l, i, h, ch, p, time, parsersDebug = ""; 208 if ( tb.length === 0) { 209 return c.debug ? log('*Empty table!* Not building a parser cache') : ''; 210 } else if (c.debug) { 211 time = new Date(); 212 log('Detecting parsers for each column'); 213 } 214 rows = tb[0].rows; 215 if (rows[0]) { 216 list = []; 217 l = rows[0].cells.length; 218 for (i = 0; i < l; i++) { 219 // tons of thanks to AnthonyM1229 for working out the following selector (issue #74) to make this work in IE8! 220 // More fixes to this selector to work properly in iOS and jQuery 1.8+ (issue #132 & #174) 221 h = c.$headers.filter(':not([colspan])'); 222 h = h.add( c.$headers.filter('[colspan="1"]') ) // ie8 fix 223 .filter('[data-column="' + i + '"]:last'); 224 ch = c.headers[i]; 225 // get column parser 226 p = ts.getParserById( ts.getData(h, ch, 'sorter') ); 227 // empty cells behaviour - keeping emptyToBottom for backwards compatibility 228 c.empties[i] = ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ); 229 // text strings behaviour in numerical sorts 230 c.strings[i] = ts.getData(h, ch, 'string') || c.stringTo || 'max'; 231 if (!p) { 232 p = detectParserForColumn(table, rows, -1, i); 233 } 234 if (c.debug) { 235 parsersDebug += "column:" + i + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n"; 236 } 237 list.push(p); 238 } 239 } 240 if (c.debug) { 241 log(parsersDebug); 242 benchmark("Completed detecting parsers", time); 243 } 244 c.parsers = list; 245 } 246 247 /* utils */ 248 function buildCache(table) { 249 var b = table.tBodies, 250 tc = table.config, 251 totalRows, 252 totalCells, 253 parsers = tc.parsers, 254 t, v, i, j, k, c, cols, cacheTime, colMax = []; 255 tc.cache = {}; 256 // if no parsers found, return - it's an empty table. 257 if (!parsers) { 258 return tc.debug ? log('*Empty table!* Not building a cache') : ''; 259 } 260 if (tc.debug) { 261 cacheTime = new Date(); 262 } 263 // processing icon 264 if (tc.showProcessing) { 265 ts.isProcessing(table, true); 266 } 267 for (k = 0; k < b.length; k++) { 268 tc.cache[k] = { row: [], normalized: [] }; 269 // ignore tbodies with class name from c.cssInfoBlock 270 if (!$(b[k]).hasClass(tc.cssInfoBlock)) { 271 totalRows = (b[k] && b[k].rows.length) || 0; 272 totalCells = (b[k].rows[0] && b[k].rows[0].cells.length) || 0; 273 for (i = 0; i < totalRows; ++i) { 274 /** Add the table data to main data array */ 275 c = $(b[k].rows[i]); 276 cols = []; 277 // if this is a child row, add it to the last row's children and continue to the next row 278 if (c.hasClass(tc.cssChildRow)) { 279 tc.cache[k].row[tc.cache[k].row.length - 1] = tc.cache[k].row[tc.cache[k].row.length - 1].add(c); 280 // go to the next for loop 281 continue; 282 } 283 tc.cache[k].row.push(c); 284 for (j = 0; j < totalCells; ++j) { 285 t = getElementText(table, c[0].cells[j], j); 286 // allow parsing if the string is empty, previously parsing would change it to zero, 287 // in case the parser needs to extract data from the table cell attributes 288 v = parsers[j].format(t, table, c[0].cells[j], j); 289 cols.push(v); 290 if ((parsers[j].type || '').toLowerCase() === "numeric") { 291 colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0); // determine column max value (ignore sign) 292 } 293 } 294 cols.push(tc.cache[k].normalized.length); // add position for rowCache 295 tc.cache[k].normalized.push(cols); 296 } 297 tc.cache[k].colMax = colMax; 298 } 299 } 300 if (tc.showProcessing) { 301 ts.isProcessing(table); // remove processing icon 302 } 303 if (tc.debug) { 304 benchmark("Building cache for " + totalRows + " rows", cacheTime); 305 } 306 } 307 308 // init flag (true) used by pager plugin to prevent widget application 309 function appendToTable(table, init) { 310 var c = table.config, 311 wo = c.widgetOptions, 312 b = table.tBodies, 313 rows = [], 314 c2 = c.cache, 315 r, n, totalRows, checkCell, $bk, $tb, 316 i, j, k, l, pos, appendTime; 317 if (isEmptyObject(c2)) { return; } // empty table - fixes #206/#346 318 if (c.debug) { 319 appendTime = new Date(); 320 } 321 for (k = 0; k < b.length; k++) { 322 $bk = $(b[k]); 323 if ($bk.length && !$bk.hasClass(c.cssInfoBlock)) { 324 // get tbody 325 $tb = ts.processTbody(table, $bk, true); 326 r = c2[k].row; 327 n = c2[k].normalized; 328 totalRows = n.length; 329 checkCell = totalRows ? (n[0].length - 1) : 0; 330 for (i = 0; i < totalRows; i++) { 331 pos = n[i][checkCell]; 332 rows.push(r[pos]); 333 // removeRows used by the pager plugin; don't render if using ajax - fixes #411 334 if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) { 335 l = r[pos].length; 336 for (j = 0; j < l; j++) { 337 $tb.append(r[pos][j]); 338 } 339 } 340 } 341 // restore tbody 342 ts.processTbody(table, $tb, false); 343 } 344 } 345 if (c.appender) { 346 c.appender(table, rows); 347 } 348 if (c.debug) { 349 benchmark("Rebuilt table", appendTime); 350 } 351 // apply table widgets; but not before ajax completes 352 if (!init && !c.appender) { ts.applyWidget(table); } 353 // trigger sortend 354 $(table).trigger("sortEnd", table); 355 $(table).trigger("updateComplete", table); 356 } 357 358 // computeTableHeaderCellIndexes from: 359 // http://www.javascripttoolbox.com/lib/table/examples.php 360 // http://www.javascripttoolbox.com/temp/table_cellindex.html 361 function computeThIndexes(t) { 362 var matrix = [], 363 lookup = {}, 364 cols = 0, // determine the number of columns 365 trs = $(t).find('thead:eq(0), tfoot').children('tr'), // children tr in tfoot - see issue #196 366 i, j, k, l, c, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow; 367 for (i = 0; i < trs.length; i++) { 368 cells = trs[i].cells; 369 for (j = 0; j < cells.length; j++) { 370 c = cells[j]; 371 rowIndex = c.parentNode.rowIndex; 372 cellId = rowIndex + "-" + c.cellIndex; 373 rowSpan = c.rowSpan || 1; 374 colSpan = c.colSpan || 1; 375 if (typeof(matrix[rowIndex]) === "undefined") { 376 matrix[rowIndex] = []; 377 } 378 // Find first available column in the first row 379 for (k = 0; k < matrix[rowIndex].length + 1; k++) { 380 if (typeof(matrix[rowIndex][k]) === "undefined") { 381 firstAvailCol = k; 382 break; 383 } 384 } 385 lookup[cellId] = firstAvailCol; 386 cols = Math.max(firstAvailCol, cols); 387 // add data-column 388 $(c).attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex 389 for (k = rowIndex; k < rowIndex + rowSpan; k++) { 390 if (typeof(matrix[k]) === "undefined") { 391 matrix[k] = []; 392 } 393 matrixrow = matrix[k]; 394 for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { 395 matrixrow[l] = "x"; 396 } 397 } 398 } 399 } 400 // may not be accurate if # header columns !== # tbody columns 401 t.config.columns = cols + 1; // add one because it's a zero-based index 402 return lookup; 403 } 404 405 function formatSortingOrder(v) { 406 // look for "d" in "desc" order; return true 407 return (/^d/i.test(v) || v === 1); 408 } 409 410 function buildHeaders(table) { 411 var header_index = computeThIndexes(table), ch, $t, 412 h, i, t, lock, time, c = table.config; 413 c.headerList = []; 414 c.headerContent = []; 415 if (c.debug) { 416 time = new Date(); 417 } 418 // add icon if cssIcon option exists 419 i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : ''; 420 c.$headers = $(table).find(c.selectorHeaders).each(function(index) { 421 $t = $(this); 422 ch = c.headers[index]; 423 c.headerContent[index] = $(this).html(); // save original header content 424 // set up header template 425 t = c.headerTemplate.replace(/\{content\}/g, $(this).html()).replace(/\{icon\}/g, i); 426 if (c.onRenderTemplate) { 427 h = c.onRenderTemplate.apply($t, [index, t]); 428 if (h && typeof h === 'string') { t = h; } // only change t if something is returned 429 } 430 $(this).html('<div class="tablesorter-header-inner">' + t + '</div>'); // faster than wrapInner 431 432 if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index]); } 433 434 this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; 435 this.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; 436 this.count = -1; // set to -1 because clicking on the header automatically adds one 437 this.lockedOrder = false; 438 lock = ts.getData($t, ch, 'lockedOrder') || false; 439 if (typeof lock !== 'undefined' && lock !== false) { 440 this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; 441 } 442 $t.addClass(ts.css.header + ' ' + c.cssHeader); 443 // add cell to headerList 444 c.headerList[index] = this; 445 // add to parent in case there are multiple rows 446 $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow); 447 // allow keyboard cursor to focus on element 448 if (c.tabIndex) { $t.attr("tabindex", 0); } 449 }); 450 // enable/disable sorting 451 updateHeader(table); 452 if (c.debug) { 453 benchmark("Built headers:", time); 454 log(c.$headers); 455 } 456 } 457 458 function commonUpdate(table, resort, callback) { 459 var c = table.config; 460 // remove rows/elements before update 461 c.$table.find(c.selectorRemove).remove(); 462 // rebuild parsers 463 buildParserCache(table); 464 // rebuild the cache map 465 buildCache(table); 466 checkResort(c.$table, resort, callback); 467 } 468 469 function updateHeader(table) { 470 var s, c = table.config; 471 c.$headers.each(function(index, th){ 472 s = ts.getData( th, c.headers[index], 'sorter' ) === 'false'; 473 th.sortDisabled = s; 474 $(th)[ s ? 'addClass' : 'removeClass' ]('sorter-false'); 475 }); 476 } 477 478 function setHeadersCss(table) { 479 var f, i, j, l, 480 c = table.config, 481 list = c.sortList, 482 css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc], 483 // find the footer 484 $t = $(table).find('tfoot tr').children().removeClass(css.join(' ')); 485 // remove all header information 486 c.$headers.removeClass(css.join(' ')); 487 l = list.length; 488 for (i = 0; i < l; i++) { 489 // direction = 2 means reset! 490 if (list[i][1] !== 2) { 491 // multicolumn sorting updating - choose the :last in case there are nested columns 492 f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (l === 1 ? ':last' : '') ); 493 if (f.length) { 494 for (j = 0; j < f.length; j++) { 495 if (!f[j].sortDisabled) { 496 f.eq(j).addClass(css[list[i][1]]); 497 // add sorted class to footer, if it exists 498 if ($t.length) { 499 $t.filter('[data-column="' + list[i][0] + '"]').eq(j).addClass(css[list[i][1]]); 500 } 501 } 502 } 503 } 504 } 505 } 506 } 507 508 // automatically add col group, and column sizes if set 509 function fixColumnWidth(table) { 510 if (table.config.widthFixed && $(table).find('colgroup').length === 0) { 511 var colgroup = $('<colgroup>'), 512 overallWidth = $(table).width(); 513 // only add col for visible columns - fixes #371 514 $(table.tBodies[0]).find("tr:first").children("td:visible").each(function() { 515 colgroup.append($('<col>').css('width', parseInt(($(this).width()/overallWidth)*1000, 10)/10 + '%')); 516 }); 517 $(table).prepend(colgroup); 518 } 519 } 520 521 function updateHeaderSortCount(table, list) { 522 var s, t, o, c = table.config, 523 sl = list || c.sortList; 524 c.sortList = []; 525 $.each(sl, function(i,v){ 526 // ensure all sortList values are numeric - fixes #127 527 s = [ parseInt(v[0], 10), parseInt(v[1], 10) ]; 528 // make sure header exists 529 o = c.$headers[s[0]]; 530 if (o) { // prevents error if sorton array is wrong 531 c.sortList.push(s); 532 t = $.inArray(s[1], o.order); // fixes issue #167 533 o.count = t >= 0 ? t : s[1] % (c.sortReset ? 3 : 2); 534 } 535 }); 536 } 537 538 function getCachedSortType(parsers, i) { 539 return (parsers && parsers[i]) ? parsers[i].type || '' : ''; 540 } 541 542 function initSort(table, cell, e){ 543 var a, i, j, o, s, 544 c = table.config, 545 k = !e[c.sortMultiSortKey], 546 $this = $(table); 547 // Only call sortStart if sorting is enabled 548 $this.trigger("sortStart", table); 549 // get current column sort order 550 cell.count = e[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); 551 // reset all sorts on non-current column - issue #30 552 if (c.sortRestart) { 553 i = cell; 554 c.$headers.each(function() { 555 // only reset counts on columns that weren't just clicked on and if not included in a multisort 556 if (this !== i && (k || !$(this).is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc))) { 557 this.count = -1; 558 } 559 }); 560 } 561 // get current column index 562 i = cell.column; 563 // user only wants to sort on one column 564 if (k) { 565 // flush the sort list 566 c.sortList = []; 567 if (c.sortForce !== null) { 568 a = c.sortForce; 569 for (j = 0; j < a.length; j++) { 570 if (a[j][0] !== i) { 571 c.sortList.push(a[j]); 572 } 573 } 574 } 575 // add column to sort list 576 o = cell.order[cell.count]; 577 if (o < 2) { 578 c.sortList.push([i, o]); 579 // add other columns if header spans across multiple 580 if (cell.colSpan > 1) { 581 for (j = 1; j < cell.colSpan; j++) { 582 c.sortList.push([i + j, o]); 583 } 584 } 585 } 586 // multi column sorting 587 } else { 588 // get rid of the sortAppend before adding more - fixes issue #115 589 if (c.sortAppend && c.sortList.length > 1) { 590 if (ts.isValueInArray(c.sortAppend[0][0], c.sortList)) { 591 c.sortList.pop(); 592 } 593 } 594 // the user has clicked on an already sorted column 595 if (ts.isValueInArray(i, c.sortList)) { 596 // reverse the sorting direction 597 for (j = 0; j < c.sortList.length; j++) { 598 s = c.sortList[j]; 599 o = c.$headers[s[0]]; 600 if (s[0] === i) { 601 // o.count seems to be incorrect when compared to cell.count 602 s[1] = o.order[cell.count]; 603 if (s[1] === 2) { 604 c.sortList.splice(j,1); 605 o.count = -1; 606 } 607 } 608 } 609 } else { 610 // add column to sort list array 611 o = cell.order[cell.count]; 612 if (o < 2) { 613 c.sortList.push([i, o]); 614 // add other columns if header spans across multiple 615 if (cell.colSpan > 1) { 616 for (j = 1; j < cell.colSpan; j++) { 617 c.sortList.push([i + j, o]); 618 } 619 } 620 } 621 } 622 } 623 if (c.sortAppend !== null) { 624 a = c.sortAppend; 625 for (j = 0; j < a.length; j++) { 626 if (a[j][0] !== i) { 627 c.sortList.push(a[j]); 628 } 629 } 630 } 631 // sortBegin event triggered immediately before the sort 632 $this.trigger("sortBegin", table); 633 // setTimeout needed so the processing icon shows up 634 setTimeout(function(){ 635 // set css for headers 636 setHeadersCss(table); 637 multisort(table); 638 appendToTable(table); 639 }, 1); 640 } 641 642 // sort multiple columns 643 function multisort(table) { /*jshint loopfunc:true */ 644 var i, k, num, col, colMax, cache, lc, 645 order, orgOrderCol, sortTime, sort, x, y, 646 dir = 0, 647 c = table.config, 648 cts = c.textSorter || '', 649 sortList = c.sortList, 650 l = sortList.length, 651 bl = table.tBodies.length; 652 if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346 653 return; 654 } 655 if (c.debug) { sortTime = new Date(); } 656 for (k = 0; k < bl; k++) { 657 colMax = c.cache[k].colMax; 658 cache = c.cache[k].normalized; 659 lc = cache.length; 660 orgOrderCol = (cache && cache[0]) ? cache[0].length - 1 : 0; 661 cache.sort(function(a, b) { 662 // cache is undefined here in IE, so don't use it! 663 for (i = 0; i < l; i++) { 664 col = sortList[i][0]; 665 order = sortList[i][1]; 666 // sort direction, true = asc, false = desc 667 dir = order === 0; 668 669 if (c.sortStable && a[col] === b[col] && l === 1) { 670 return a[orgOrderCol] - b[orgOrderCol]; 671 } 672 673 // fallback to natural sort since it is more robust 674 num = /n/i.test(getCachedSortType(c.parsers, col)); 675 if (num && c.strings[col]) { 676 // sort strings in numerical columns 677 if (typeof (c.string[c.strings[col]]) === 'boolean') { 678 num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1); 679 } else { 680 num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0; 681 } 682 // fall back to built-in numeric sort 683 // var sort = $.tablesorter["sort" + s](table, a[c], b[c], c, colMax[c], dir); 684 sort = c.numberSorter ? c.numberSorter(x[col], y[col], dir, colMax[col], table) : 685 ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); 686 } else { 687 // set a & b depending on sort direction 688 x = dir ? a : b; 689 y = dir ? b : a; 690 // text sort function 691 if (typeof(cts) === 'function') { 692 // custom OVERALL text sorter 693 sort = cts(x[col], y[col], dir, col, table); 694 } else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) { 695 // custom text sorter for a SPECIFIC COLUMN 696 sort = cts[col](x[col], y[col], dir, col, table); 697 } else { 698 // fall back to natural sort 699 sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); 700 } 701 } 702 if (sort) { return sort; } 703 } 704 return a[orgOrderCol] - b[orgOrderCol]; 705 }); 706 } 707 if (c.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time", sortTime); } 708 } 709 710 function resortComplete($table, callback){ 711 var c = $table[0].config; 712 if (c.pager && !c.pager.ajax) { 713 $table.trigger('updateComplete'); 714 } 715 if (typeof callback === "function") { 716 callback($table[0]); 717 } 718 } 719 720 function checkResort($table, flag, callback) { 721 // don't try to resort if the table is still processing 722 // this will catch spamming of the updateCell method 723 if (flag !== false && !$table[0].isProcessing) { 724 $table.trigger("sorton", [$table[0].config.sortList, function(){ 725 resortComplete($table, callback); 726 }]); 727 } else { 728 resortComplete($table, callback); 729 } 730 } 731 732 function bindEvents(table){ 733 var c = table.config, 734 $this = c.$table, 735 j, downTime; 736 // apply event handling to headers 737 c.$headers 738 // http://stackoverflow.com/questions/5312849/jquery-find-self; 739 .find(c.selectorSort).add( c.$headers.filter(c.selectorSort) ) 740 .unbind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter') 741 .bind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter', function(e, external) { 742 // only recognize left clicks or enter 743 if ( ((e.which || e.button) !== 1 && !/sort|keypress/.test(e.type)) || (e.type === 'keypress' && e.which !== 13) ) { 744 return; 745 } 746 // ignore long clicks (prevents resizable widget from initializing a sort) 747 if (e.type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return; } 748 // set timer on mousedown 749 if (e.type === 'mousedown') { 750 downTime = new Date().getTime(); 751 return e.target.tagName === "INPUT" ? '' : !c.cancelSelection; 752 } 753 if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } 754 // jQuery v1.2.6 doesn't have closest() 755 var $cell = /TH|TD/.test(this.tagName) ? $(this) : $(this).parents('th, td').filter(':first'), cell = $cell[0]; 756 if (!cell.sortDisabled) { 757 initSort(table, cell, e); 758 } 759 }); 760 if (c.cancelSelection) { 761 // cancel selection 762 c.$headers 763 .attr('unselectable', 'on') 764 .bind('selectstart', false) 765 .css({ 766 'user-select': 'none', 767 'MozUserSelect': 'none' // not needed for jQuery 1.8+ 768 }); 769 } 770 // apply easy methods that trigger bound events 771 $this 772 .unbind('sortReset update updateRows updateCell updateAll addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave '.split(' ').join('.tablesorter ')) 773 .bind("sortReset.tablesorter", function(e){ 774 e.stopPropagation(); 775 c.sortList = []; 776 setHeadersCss(table); 777 multisort(table); 778 appendToTable(table); 779 }) 780 .bind("updateAll.tablesorter", function(e, resort, callback){ 781 e.stopPropagation(); 782 ts.refreshWidgets(table, true, true); 783 ts.restoreHeaders(table); 784 buildHeaders(table); 785 bindEvents(table); 786 commonUpdate(table, resort, callback); 787 }) 788 .bind("update.tablesorter updateRows.tablesorter", function(e, resort, callback) { 789 e.stopPropagation(); 790 // update sorting (if enabled/disabled) 791 updateHeader(table); 792 commonUpdate(table, resort, callback); 793 }) 794 .bind("updateCell.tablesorter", function(e, cell, resort, callback) { 795 e.stopPropagation(); 796 $this.find(c.selectorRemove).remove(); 797 // get position from the dom 798 var l, row, icell, 799 $tb = $this.find('tbody'), 800 // update cache - format: function(s, table, cell, cellIndex) 801 // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); 802 tbdy = $tb.index( $(cell).parents('tbody').filter(':first') ), 803 $row = $(cell).parents('tr').filter(':first'); 804 cell = $(cell)[0]; // in case cell is a jQuery object 805 // tbody may not exist if update is initialized while tbody is removed for processing 806 if ($tb.length && tbdy >= 0) { 807 row = $tb.eq(tbdy).find('tr').index( $row ); 808 icell = cell.cellIndex; 809 l = c.cache[tbdy].normalized[row].length - 1; 810 c.cache[tbdy].row[table.config.cache[tbdy].normalized[row][l]] = $row; 811 c.cache[tbdy].normalized[row][icell] = c.parsers[icell].format( getElementText(table, cell, icell), table, cell, icell ); 812 checkResort($this, resort, callback); 813 } 814 }) 815 .bind("addRows.tablesorter", function(e, $row, resort, callback) { 816 e.stopPropagation(); 817 if (isEmptyObject(c.cache)) { 818 // empty table, do an update instead - fixes #450 819 updateHeader(table); 820 commonUpdate(table, resort, callback); 821 } else { 822 var i, rows = $row.filter('tr').length, 823 dat = [], l = $row[0].cells.length, 824 tbdy = $this.find('tbody').index( $row.parents('tbody').filter(':first') ); 825 // fixes adding rows to an empty table - see issue #179 826 if (!c.parsers) { 827 buildParserCache(table); 828 } 829 // add each row 830 for (i = 0; i < rows; i++) { 831 // add each cell 832 for (j = 0; j < l; j++) { 833 dat[j] = c.parsers[j].format( getElementText(table, $row[i].cells[j], j), table, $row[i].cells[j], j ); 834 } 835 // add the row index to the end 836 dat.push(c.cache[tbdy].row.length); 837 // update cache 838 c.cache[tbdy].row.push([$row[i]]); 839 c.cache[tbdy].normalized.push(dat); 840 dat = []; 841 } 842 // resort using current settings 843 checkResort($this, resort, callback); 844 } 845 }) 846 .bind("sorton.tablesorter", function(e, list, callback, init) { 847 var c = table.config; 848 e.stopPropagation(); 849 $this.trigger("sortStart", this); 850 // update header count index 851 updateHeaderSortCount(table, list); 852 // set css for headers 853 setHeadersCss(table); 854 // fixes #346 855 if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } 856 $this.trigger("sortBegin", this); 857 // sort the table and append it to the dom 858 multisort(table); 859 appendToTable(table, init); 860 if (typeof callback === "function") { 861 callback(table); 862 } 863 }) 864 .bind("appendCache.tablesorter", function(e, callback, init) { 865 e.stopPropagation(); 866 appendToTable(table, init); 867 if (typeof callback === "function") { 868 callback(table); 869 } 870 }) 871 .bind("applyWidgetId.tablesorter", function(e, id) { 872 e.stopPropagation(); 873 ts.getWidgetById(id).format(table, c, c.widgetOptions); 874 }) 875 .bind("applyWidgets.tablesorter", function(e, init) { 876 e.stopPropagation(); 877 // apply widgets 878 ts.applyWidget(table, init); 879 }) 880 .bind("refreshWidgets.tablesorter", function(e, all, dontapply){ 881 e.stopPropagation(); 882 ts.refreshWidgets(table, all, dontapply); 883 }) 884 .bind("destroy.tablesorter", function(e, c, cb){ 885 e.stopPropagation(); 886 ts.destroy(table, c, cb); 887 }); 888 } 889 890 /* public methods */ 891 ts.construct = function(settings) { 892 return this.each(function() { 893 var table = this, 894 // merge & extend config options 895 c = $.extend(true, {}, ts.defaults, settings); 896 // create a table from data (build table widget) 897 if (!table.hasInitialized && ts.buildTable && this.tagName !== 'TABLE') { 898 // return the table (in case the original target is the table's container) 899 ts.buildTable(table, c); 900 } 901 ts.setup(table, c); 902 }); 903 }; 904 905 ts.setup = function(table, c) { 906 // if no thead or tbody, or tablesorter is already present, quit 907 if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) { 908 return c.debug ? log('stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : ''; 909 } 910 911 var k = '', 912 $this = $(table), 913 m = $.metadata; 914 // initialization flag 915 table.hasInitialized = false; 916 // table is being processed flag 917 table.isProcessing = true; 918 // make sure to store the config object 919 table.config = c; 920 // save the settings where they read 921 $.data(table, "tablesorter", c); 922 if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } 923 924 // constants 925 c.supportsTextContent = $('<span>x</span>')[0].textContent === 'x'; 926 // removing this in version 3 (only supports jQuery 1.7+) 927 c.supportsDataObject = (function(version) { 928 version[0] = parseInt(version[0], 10); 929 return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4); 930 })($.fn.jquery.split(".")); 931 // digit sort text location; keeping max+/- for backwards compatibility 932 c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; 933 // add table theme class only if there isn't already one there 934 if (!/tablesorter\-/.test($this.attr('class'))) { 935 k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); 936 } 937 c.$table = $this.addClass(ts.css.table + ' ' + c.tableClass + k); 938 c.$tbodies = $this.children('tbody:not(.' + c.cssInfoBlock + ')'); 939 c.widgetInit = {}; // keep a list of initialized widgets 940 // build headers 941 buildHeaders(table); 942 // fixate columns if the users supplies the fixedWidth option 943 // do this after theme has been applied 944 fixColumnWidth(table); 945 // try to auto detect column type, and store in tables config 946 buildParserCache(table); 947 // build the cache for the tbody cells 948 // delayInit will delay building the cache until the user starts a sort 949 if (!c.delayInit) { buildCache(table); } 950 // bind all header events and methods 951 bindEvents(table); 952 // get sort list from jQuery data or metadata 953 // in jQuery < 1.4, an error occurs when calling $this.data() 954 if (c.supportsDataObject && typeof $this.data().sortlist !== 'undefined') { 955 c.sortList = $this.data().sortlist; 956 } else if (m && ($this.metadata() && $this.metadata().sortlist)) { 957 c.sortList = $this.metadata().sortlist; 958 } 959 // apply widget init code 960 ts.applyWidget(table, true); 961 // if user has supplied a sort list to constructor 962 if (c.sortList.length > 0) { 963 $this.trigger("sorton", [c.sortList, {}, !c.initWidgets]); 964 } else if (c.initWidgets) { 965 // apply widget format 966 ts.applyWidget(table); 967 } 968 969 // show processesing icon 970 if (c.showProcessing) { 971 $this 972 .unbind('sortBegin.tablesorter sortEnd.tablesorter') 973 .bind('sortBegin.tablesorter sortEnd.tablesorter', function(e) { 974 ts.isProcessing(table, e.type === 'sortBegin'); 975 }); 976 } 977 978 // initialized 979 table.hasInitialized = true; 980 table.isProcessing = false; 981 if (c.debug) { 982 ts.benchmark("Overall initialization time", $.data( table, 'startoveralltimer')); 983 } 984 $this.trigger('tablesorter-initialized', table); 985 if (typeof c.initialized === 'function') { c.initialized(table); } 986 }; 987 988 // *** Process table *** 989 // add processing indicator 990 ts.isProcessing = function(table, toggle, $ths) { 991 table = $(table); 992 var c = table[0].config, 993 // default to all headers 994 $h = $ths || table.find('.' + ts.css.header); 995 if (toggle) { 996 if (c.sortList.length > 0) { 997 // get headers from the sortList 998 $h = $h.filter(function(){ 999 // get data-column from attr to keep compatibility with jQuery 1.2.6 1000 return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList); 1001 }); 1002 } 1003 $h.addClass(ts.css.processing + ' ' + c.cssProcessing); 1004 } else { 1005 $h.removeClass(ts.css.processing + ' ' + c.cssProcessing); 1006 } 1007 }; 1008 1009 // detach tbody but save the position 1010 // don't use tbody because there are portions that look for a tbody index (updateCell) 1011 ts.processTbody = function(table, $tb, getIt){ 1012 var holdr; 1013 if (getIt) { 1014 table.isProcessing = true; 1015 $tb.before('<span class="tablesorter-savemyplace"/>'); 1016 holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); 1017 return holdr; 1018 } 1019 holdr = $(table).find('span.tablesorter-savemyplace'); 1020 $tb.insertAfter( holdr ); 1021 holdr.remove(); 1022 table.isProcessing = false; 1023 }; 1024 1025 ts.clearTableBody = function(table) { 1026 $(table)[0].config.$tbodies.empty(); 1027 }; 1028 1029 // restore headers 1030 ts.restoreHeaders = function(table){ 1031 var c = table.config; 1032 // don't use c.$headers here in case header cells were swapped 1033 c.$table.find(c.selectorHeaders).each(function(i){ 1034 // only restore header cells if it is wrapped 1035 // because this is also used by the updateAll method 1036 if ($(this).find('.tablesorter-header-inner').length){ 1037 $(this).html( c.headerContent[i] ); 1038 } 1039 }); 1040 }; 1041 1042 ts.destroy = function(table, removeClasses, callback){ 1043 table = $(table)[0]; 1044 if (!table.hasInitialized) { return; } 1045 // remove all widgets 1046 ts.refreshWidgets(table, true, true); 1047 var $t = $(table), c = table.config, 1048 $h = $t.find('thead:first'), 1049 $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow), 1050 $f = $t.find('tfoot:first > tr').children('th, td'); 1051 // remove widget added rows, just in case 1052 $h.find('tr').not($r).remove(); 1053 // disable tablesorter 1054 $t 1055 .removeData('tablesorter') 1056 .unbind('sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd '.split(' ').join('.tablesorter ')); 1057 c.$headers.add($f) 1058 .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc].join(' ') ) 1059 .removeAttr('data-column'); 1060 $r.find(c.selectorSort).unbind('mousedown.tablesorter mouseup.tablesorter keypress.tablesorter'); 1061 ts.restoreHeaders(table); 1062 if (removeClasses !== false) { 1063 $t.removeClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme); 1064 } 1065 // clear flag in case the plugin is initialized again 1066 table.hasInitialized = false; 1067 if (typeof callback === 'function') { 1068 callback(table); 1069 } 1070 }; 1071 1072 // *** sort functions *** 1073 // regex used in natural sort 1074 ts.regex = { 1075 chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters 1076 hex: /^0x[0-9a-f]+$/i // hex 1077 }; 1078 1079 // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed) 1080 ts.sortNatural = function(a, b) { 1081 if (a === b) { return 0; } 1082 var xN, xD, yN, yD, xF, yF, i, mx, 1083 r = ts.regex; 1084 // first try and sort Hex codes 1085 if (r.hex.test(b)) { 1086 xD = parseInt(a.match(r.hex), 16); 1087 yD = parseInt(b.match(r.hex), 16); 1088 if ( xD < yD ) { return -1; } 1089 if ( xD > yD ) { return 1; } 1090 } 1091 1092 // chunk/tokenize 1093 xN = a.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); 1094 yN = b.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); 1095 mx = Math.max(xN.length, yN.length); 1096 // natural sorting through split numeric strings and default strings 1097 for (i = 0; i < mx; i++) { 1098 // find floats not starting with '0', string or 0 if not defined 1099 xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; 1100 yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; 1101 // handle numeric vs string comparison - number < string - (Kyle Adams) 1102 if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } 1103 // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' 1104 if (typeof xF !== typeof yF) { 1105 xF += ''; 1106 yF += ''; 1107 } 1108 if (xF < yF) { return -1; } 1109 if (xF > yF) { return 1; } 1110 } 1111 return 0; 1112 }; 1113 1114 ts.sortNaturalAsc = function(a, b, col, table, c) { 1115 if (a === b) { return 0; } 1116 var e = c.string[ (c.empties[col] || c.emptyTo ) ]; 1117 if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } 1118 if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } 1119 return ts.sortNatural(a, b); 1120 }; 1121 1122 ts.sortNaturalDesc = function(a, b, col, table, c) { 1123 if (a === b) { return 0; } 1124 var e = c.string[ (c.empties[col] || c.emptyTo ) ]; 1125 if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } 1126 if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } 1127 return ts.sortNatural(b, a); 1128 }; 1129 1130 // basic alphabetical sort 1131 ts.sortText = function(a, b) { 1132 return a > b ? 1 : (a < b ? -1 : 0); 1133 }; 1134 1135 // return text string value by adding up ascii value 1136 // so the text is somewhat sorted when using a digital sort 1137 // this is NOT an alphanumeric sort 1138 ts.getTextValue = function(a, num, mx) { 1139 if (mx) { 1140 // make sure the text value is greater than the max numerical value (mx) 1141 var i, l = a ? a.length : 0, n = mx + num; 1142 for (i = 0; i < l; i++) { 1143 n += a.charCodeAt(i); 1144 } 1145 return num * n; 1146 } 1147 return 0; 1148 }; 1149 1150 ts.sortNumericAsc = function(a, b, num, mx, col, table) { 1151 if (a === b) { return 0; } 1152 var c = table.config, 1153 e = c.string[ (c.empties[col] || c.emptyTo ) ]; 1154 if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } 1155 if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } 1156 if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } 1157 if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } 1158 return a - b; 1159 }; 1160 1161 ts.sortNumericDesc = function(a, b, num, mx, col, table) { 1162 if (a === b) { return 0; } 1163 var c = table.config, 1164 e = c.string[ (c.empties[col] || c.emptyTo ) ]; 1165 if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } 1166 if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } 1167 if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } 1168 if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } 1169 return b - a; 1170 }; 1171 1172 ts.sortNumeric = function(a, b) { 1173 return a - b; 1174 }; 1175 1176 // used when replacing accented characters during sorting 1177 ts.characterEquivalents = { 1178 "a" : "\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5", // áàâãäąå 1179 "A" : "\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5", // ÁÀÂÃÄĄÅ 1180 "c" : "\u00e7\u0107\u010d", // çćč 1181 "C" : "\u00c7\u0106\u010c", // ÇĆČ 1182 "e" : "\u00e9\u00e8\u00ea\u00eb\u011b\u0119", // éèêëěę 1183 "E" : "\u00c9\u00c8\u00ca\u00cb\u011a\u0118", // ÉÈÊËĚĘ 1184 "i" : "\u00ed\u00ec\u0130\u00ee\u00ef\u0131", // íìİîïı 1185 "I" : "\u00cd\u00cc\u0130\u00ce\u00cf", // ÍÌİÎÏ 1186 "o" : "\u00f3\u00f2\u00f4\u00f5\u00f6", // óòôõö 1187 "O" : "\u00d3\u00d2\u00d4\u00d5\u00d6", // ÓÒÔÕÖ 1188 "ss": "\u00df", // ß (s sharp) 1189 "SS": "\u1e9e", // ẞ (Capital sharp s) 1190 "u" : "\u00fa\u00f9\u00fb\u00fc\u016f", // úùûüů 1191 "U" : "\u00da\u00d9\u00db\u00dc\u016e" // ÚÙÛÜŮ 1192 }; 1193 ts.replaceAccents = function(s) { 1194 var a, acc = '[', eq = ts.characterEquivalents; 1195 if (!ts.characterRegex) { 1196 ts.characterRegexArray = {}; 1197 for (a in eq) { 1198 if (typeof a === 'string') { 1199 acc += eq[a]; 1200 ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); 1201 } 1202 } 1203 ts.characterRegex = new RegExp(acc + ']'); 1204 } 1205 if (ts.characterRegex.test(s)) { 1206 for (a in eq) { 1207 if (typeof a === 'string') { 1208 s = s.replace( ts.characterRegexArray[a], a ); 1209 } 1210 } 1211 } 1212 return s; 1213 }; 1214 1215 // *** utilities *** 1216 ts.isValueInArray = function(v, a) { 1217 var i, l = a.length; 1218 for (i = 0; i < l; i++) { 1219 if (a[i][0] === v) { 1220 return true; 1221 } 1222 } 1223 return false; 1224 }; 1225 1226 ts.addParser = function(parser) { 1227 var i, l = ts.parsers.length, a = true; 1228 for (i = 0; i < l; i++) { 1229 if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { 1230 a = false; 1231 } 1232 } 1233 if (a) { 1234 ts.parsers.push(parser); 1235 } 1236 }; 1237 1238 ts.getParserById = function(name) { 1239 var i, l = ts.parsers.length; 1240 for (i = 0; i < l; i++) { 1241 if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { 1242 return ts.parsers[i]; 1243 } 1244 } 1245 return false; 1246 }; 1247 1248 ts.addWidget = function(widget) { 1249 ts.widgets.push(widget); 1250 }; 1251 1252 ts.getWidgetById = function(name) { 1253 var i, w, l = ts.widgets.length; 1254 for (i = 0; i < l; i++) { 1255 w = ts.widgets[i]; 1256 if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { 1257 return w; 1258 } 1259 } 1260 }; 1261 1262 ts.applyWidget = function(table, init) { 1263 table = $(table)[0]; // in case this is called externally 1264 var c = table.config, 1265 wo = c.widgetOptions, 1266 widgets = [], 1267 time, w, wd; 1268 if (c.debug) { time = new Date(); } 1269 if (c.widgets.length) { 1270 // ensure unique widget ids 1271 c.widgets = $.grep(c.widgets, function(v, k){ 1272 return $.inArray(v, c.widgets) === k; 1273 }); 1274 // build widget array & add priority as needed 1275 $.each(c.widgets || [], function(i,n){ 1276 wd = ts.getWidgetById(n); 1277 if (wd && wd.id) { 1278 // set priority to 10 if not defined 1279 if (!wd.priority) { wd.priority = 10; } 1280 widgets[i] = wd; 1281 } 1282 }); 1283 // sort widgets by priority 1284 widgets.sort(function(a, b){ 1285 return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; 1286 }); 1287 // add/update selected widgets 1288 $.each(widgets, function(i,w){ 1289 if (w) { 1290 if (init || !(c.widgetInit[w.id])) { 1291 if (w.hasOwnProperty('options')) { 1292 wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo ); 1293 } 1294 if (w.hasOwnProperty('init')) { 1295 w.init(table, w, c, wo); 1296 } 1297 c.widgetInit[w.id] = true; 1298 } 1299 if (!init && w.hasOwnProperty('format')) { 1300 w.format(table, c, wo, false); 1301 } 1302 } 1303 }); 1304 } 1305 if (c.debug) { 1306 w = c.widgets.length; 1307 benchmark("Completed " + (init === true ? "initializing " : "applying ") + w + " widget" + (w !== 1 ? "s" : ""), time); 1308 } 1309 }; 1310 1311 ts.refreshWidgets = function(table, doAll, dontapply) { 1312 table = $(table)[0]; // see issue #243 1313 var i, c = table.config, 1314 cw = c.widgets, 1315 w = ts.widgets, l = w.length; 1316 // remove previous widgets 1317 for (i = 0; i < l; i++){ 1318 if ( w[i] && w[i].id && (doAll || $.inArray( w[i].id, cw ) < 0) ) { 1319 if (c.debug) { log( 'Refeshing widgets: Removing ' + w[i].id ); } 1320 // only remove widgets that have been initialized - fixes #442 1321 if (w[i].hasOwnProperty('remove') && c.widgetInit[w[i].id]) { 1322 w[i].remove(table, c, c.widgetOptions); 1323 c.widgetInit[w[i].id] = false; 1324 } 1325 } 1326 } 1327 if (dontapply !== true) { 1328 ts.applyWidget(table, doAll); 1329 } 1330 }; 1331 1332 // get sorter, string, empty, etc options for each column from 1333 // jQuery data, metadata, header option or header class name ("sorter-false") 1334 // priority = jQuery data > meta > headers option > header class name 1335 ts.getData = function(h, ch, key) { 1336 var val = '', $h = $(h), m, cl; 1337 if (!$h.length) { return ''; } 1338 m = $.metadata ? $h.metadata() : false; 1339 cl = ' ' + ($h.attr('class') || ''); 1340 if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ 1341 // "data-lockedOrder" is assigned to "lockedorder"; but "data-locked-order" is assigned to "lockedOrder" 1342 // "data-sort-initial-order" is assigned to "sortInitialOrder" 1343 val += $h.data(key) || $h.data(key.toLowerCase()); 1344 } else if (m && typeof m[key] !== 'undefined') { 1345 val += m[key]; 1346 } else if (ch && typeof ch[key] !== 'undefined') { 1347 val += ch[key]; 1348 } else if (cl !== ' ' && cl.match(' ' + key + '-')) { 1349 // include sorter class name "sorter-text", etc; now works with "sorter-my-custom-parser" 1350 val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; 1351 } 1352 return $.trim(val); 1353 }; 1354 1355 ts.formatFloat = function(s, table) { 1356 if (typeof s !== 'string' || s === '') { return s; } 1357 // allow using formatFloat without a table; defaults to US number format 1358 var i, 1359 t = table && table.config ? table.config.usNumberFormat !== false : 1360 typeof table !== "undefined" ? table : true; 1361 if (t) { 1362 // US Format - 1,234,567.89 -> 1234567.89 1363 s = s.replace(/,/g,''); 1364 } else { 1365 // German Format = 1.234.567,89 -> 1234567.89 1366 // French Format = 1 234 567,89 -> 1234567.89 1367 s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); 1368 } 1369 if(/^\s*\([.\d]+\)/.test(s)) { 1370 // make (#) into a negative number -> (10) = -10 1371 s = s.replace(/^\s*\(([.\d]+)\)/, '-$1'); 1372 } 1373 i = parseFloat(s); 1374 // return the text instead of zero 1375 return isNaN(i) ? $.trim(s) : i; 1376 }; 1377 1378 ts.isDigit = function(s) { 1379 // replace all unwanted chars and match 1380 return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : true; 1381 }; 1382 1383 }() 1384 }); 1385 1386 // make shortcut 1387 var ts = $.tablesorter; 1388 1389 // extend plugin scope 1390 $.fn.extend({ 1391 tablesorter: ts.construct 1392 }); 1393 1394 // add default parsers 1395 ts.addParser({ 1396 id: "text", 1397 is: function() { 1398 return true; 1399 }, 1400 format: function(s, table) { 1401 var c = table.config; 1402 if (s) { 1403 s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); 1404 s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; 1405 } 1406 return s; 1407 }, 1408 type: "text" 1409 }); 1410 1411 ts.addParser({ 1412 id: "digit", 1413 is: function(s) { 1414 return ts.isDigit(s); 1415 }, 1416 format: function(s, table) { 1417 var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); 1418 return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; 1419 }, 1420 type: "numeric" 1421 }); 1422 1423 ts.addParser({ 1424 id: "currency", 1425 is: function(s) { 1426 return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[,. ]/g,'')); // £$€¤¥¢ 1427 }, 1428 format: function(s, table) { 1429 var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); 1430 return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; 1431 }, 1432 type: "numeric" 1433 }); 1434 1435 ts.addParser({ 1436 id: "ipAddress", 1437 is: function(s) { 1438 return (/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/).test(s); 1439 }, 1440 format: function(s, table) { 1441 var i, a = s ? s.split(".") : '', 1442 r = "", 1443 l = a.length; 1444 for (i = 0; i < l; i++) { 1445 r += ("00" + a[i]).slice(-3); 1446 } 1447 return s ? ts.formatFloat(r, table) : s; 1448 }, 1449 type: "numeric" 1450 }); 1451 1452 ts.addParser({ 1453 id: "url", 1454 is: function(s) { 1455 return (/^(https?|ftp|file):\/\//).test(s); 1456 }, 1457 format: function(s) { 1458 return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; 1459 }, 1460 type: "text" 1461 }); 1462 1463 ts.addParser({ 1464 id: "isoDate", 1465 is: function(s) { 1466 return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); 1467 }, 1468 format: function(s, table) { 1469 return s ? ts.formatFloat((s !== "") ? (new Date(s.replace(/-/g, "/")).getTime() || "") : "", table) : s; 1470 }, 1471 type: "numeric" 1472 }); 1473 1474 ts.addParser({ 1475 id: "percent", 1476 is: function(s) { 1477 return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; 1478 }, 1479 format: function(s, table) { 1480 return s ? ts.formatFloat(s.replace(/%/g, ""), table) : s; 1481 }, 1482 type: "numeric" 1483 }); 1484 1485 ts.addParser({ 1486 id: "usLongDate", 1487 is: function(s) { 1488 // two digit years are not allowed cross-browser 1489 // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 1490 return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); 1491 }, 1492 format: function(s, table) { 1493 return s ? ts.formatFloat( (new Date(s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ''), table) : s; 1494 }, 1495 type: "numeric" 1496 }); 1497 1498 ts.addParser({ 1499 id: "shortDate", // "mmddyyyy", "ddmmyyyy" or "yyyymmdd" 1500 is: function(s) { 1501 // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included 1502 return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g," ").replace(/[\-.,]/g, "/")); 1503 }, 1504 format: function(s, table, cell, cellIndex) { 1505 if (s) { 1506 var c = table.config, ci = c.headerList[cellIndex], 1507 format = ci.dateFormat || ts.getData( ci, c.headers[cellIndex], 'dateFormat') || c.dateFormat; 1508 s = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/"); // escaped - because JSHint in Firefox was showing it as an error 1509 if (format === "mmddyyyy") { 1510 s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$1/$2"); 1511 } else if (format === "ddmmyyyy") { 1512 s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1"); 1513 } else if (format === "yyyymmdd") { 1514 s = s.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$1/$2/$3"); 1515 } 1516 } 1517 return s ? ts.formatFloat( (new Date(s).getTime() || ''), table) : s; 1518 }, 1519 type: "numeric" 1520 }); 1521 1522 ts.addParser({ 1523 id: "time", 1524 is: function(s) { 1525 return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); 1526 }, 1527 format: function(s, table) { 1528 return s ? ts.formatFloat( (new Date("2000/01/01 " + s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ""), table) : s; 1529 }, 1530 type: "numeric" 1531 }); 1532 1533 ts.addParser({ 1534 id: "metadata", 1535 is: function() { 1536 return false; 1537 }, 1538 format: function(s, table, cell) { 1539 var c = table.config, 1540 p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; 1541 return $(cell).metadata()[p]; 1542 }, 1543 type: "numeric" 1544 }); 1545 1546 // add default widgets 1547 ts.addWidget({ 1548 id: "zebra", 1549 priority: 90, 1550 format: function(table, c, wo) { 1551 var $tb, $tv, $tr, row, even, time, k, l, 1552 child = new RegExp(c.cssChildRow, 'i'), 1553 b = c.$tbodies; 1554 if (c.debug) { 1555 time = new Date(); 1556 } 1557 for (k = 0; k < b.length; k++ ) { 1558 // loop through the visible rows 1559 $tb = b.eq(k); 1560 l = $tb.children('tr').length; 1561 if (l > 1) { 1562 row = 0; 1563 $tv = $tb.children('tr:visible').not(c.selectorRemove); 1564 // revered back to using jQuery each - strangely it's the fastest method 1565 /*jshint loopfunc:true */ 1566 $tv.each(function(){ 1567 $tr = $(this); 1568 // style children rows the same way the parent row was styled 1569 if (!child.test(this.className)) { row++; } 1570 even = (row % 2 === 0); 1571 $tr.removeClass(wo.zebra[even ? 1 : 0]).addClass(wo.zebra[even ? 0 : 1]); 1572 }); 1573 } 1574 } 1575 if (c.debug) { 1576 ts.benchmark("Applying Zebra widget", time); 1577 } 1578 }, 1579 remove: function(table, c, wo){ 1580 var k, $tb, 1581 b = c.$tbodies, 1582 rmv = (wo.zebra || [ "even", "odd" ]).join(' '); 1583 for (k = 0; k < b.length; k++ ){ 1584 $tb = $.tablesorter.processTbody(table, b.eq(k), true); // remove tbody 1585 $tb.children().removeClass(rmv); 1586 $.tablesorter.processTbody(table, $tb, false); // restore tbody 1587 } 1588 } 1589 }); 1590 1031 1591 })(jQuery); -
extensions/UserAdvManager/branches/2.6/admin/template/js/jquery.tablesorter.min.js
r8875 r26948 1 2 (function($){$.extend({tablesorter:new 3 function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1 4 var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery); 1 /*! 2 * TableSorter 2.14.4 min - Client-side table sorting with ease! 3 * Copyright (c) 2007 Christian Bach 4 */ 5 !function(g){g.extend({tablesorter:new function(){function c(){var a=1<arguments.length?Array.prototype.slice.call(arguments):arguments[0];"undefined"!==typeof console&&"undefined"!==typeof console.log?console.log(a):alert(a)}function r(a,b){c(a+" ("+((new Date).getTime()-b.getTime())+"ms)")}function k(a){for(var b in a)return!1;return!0}function p(a,b,d){if(!b)return"";var h=a.config,e=h.textExtraction,n="",n="simple"===e?h.supportsTextContent?b.textContent:g(b).text():"function"===typeof e?e(b, a,d):"object"===typeof e&&e.hasOwnProperty(d)?e[d](b,a,d):h.supportsTextContent?b.textContent:g(b).text();return g.trim(n)}function s(a){var b=a.config,d=b.$tbodies=b.$table.children("tbody:not(."+b.cssInfoBlock+")"),h,e,n,l,x,g,m,v="";if(0===d.length)return b.debug?c("*Empty table!* Not building a parser cache"):"";b.debug&&(m=new Date,c("Detecting parsers for each column"));d=d[0].rows;if(d[0])for(h=[],e=d[0].cells.length,n=0;n<e;n++){l=b.$headers.filter(":not([colspan])");l=l.add(b.$headers.filter('[colspan="1"]')).filter('[data-column="'+ n+'"]:last');x=b.headers[n];g=f.getParserById(f.getData(l,x,"sorter"));b.empties[n]=f.getData(l,x,"empty")||b.emptyTo||(b.emptyToBottom?"bottom":"top");b.strings[n]=f.getData(l,x,"string")||b.stringTo||"max";if(!g)a:{l=a;x=d;g=-1;for(var k=n,u=void 0,A=f.parsers.length,q=!1,s="",u=!0;""===s&&u;)g++,x[g]?(q=x[g].cells[k],s=p(l,q,k),l.config.debug&&c("Checking if value was empty on row "+g+", column: "+k+': "'+s+'"')):u=!1;for(;0<=--A;)if((u=f.parsers[A])&&"text"!==u.id&&u.is&&u.is(s,l,q)){g=u;break a}g= f.getParserById("text")}b.debug&&(v+="column:"+n+"; parser:"+g.id+"; string:"+b.strings[n]+"; empty: "+b.empties[n]+"\n");h.push(g)}b.debug&&(c(v),r("Completed detecting parsers",m));b.parsers=h}function w(a){var b=a.tBodies,d=a.config,h,e,n=d.parsers,l,x,y,m,v,k,u,A=[];d.cache={};if(!n)return d.debug?c("*Empty table!* Not building a cache"):"";d.debug&&(u=new Date);d.showProcessing&&f.isProcessing(a,!0);for(m=0;m<b.length;m++)if(d.cache[m]={row:[],normalized:[]},!g(b[m]).hasClass(d.cssInfoBlock)){h= b[m]&&b[m].rows.length||0;e=b[m].rows[0]&&b[m].rows[0].cells.length||0;for(x=0;x<h;++x)if(v=g(b[m].rows[x]),k=[],v.hasClass(d.cssChildRow))d.cache[m].row[d.cache[m].row.length-1]=d.cache[m].row[d.cache[m].row.length-1].add(v);else{d.cache[m].row.push(v);for(y=0;y<e;++y)l=p(a,v[0].cells[y],y),l=n[y].format(l,a,v[0].cells[y],y),k.push(l),"numeric"===(n[y].type||"").toLowerCase()&&(A[y]=Math.max(Math.abs(l)||0,A[y]||0));k.push(d.cache[m].normalized.length);d.cache[m].normalized.push(k)}d.cache[m].colMax= A}d.showProcessing&&f.isProcessing(a);d.debug&&r("Building cache for "+h+" rows",u)}function z(a,b){var d=a.config,h=d.widgetOptions,e=a.tBodies,n=[],l=d.cache,c,y,m,v,p,u,A,q,s,t,w;if(!k(l)){d.debug&&(w=new Date);for(q=0;q<e.length;q++)if(c=g(e[q]),c.length&&!c.hasClass(d.cssInfoBlock)){p=f.processTbody(a,c,!0);c=l[q].row;y=l[q].normalized;v=(m=y.length)?y[0].length-1:0;for(u=0;u<m;u++)if(t=y[u][v],n.push(c[t]),!d.appender||d.pager&&!(d.pager.removeRows&&h.pager_removeRows||d.pager.ajax))for(s=c[t].length, A=0;A<s;A++)p.append(c[t][A]);f.processTbody(a,p,!1)}d.appender&&d.appender(a,n);d.debug&&r("Rebuilt table",w);b||d.appender||f.applyWidget(a);g(a).trigger("sortEnd",a);g(a).trigger("updateComplete",a)}}function D(a){var b=[],d={},h=0,e=g(a).find("thead:eq(0), tfoot").children("tr"),n,l,c,f,m,k,r,p,t,q;for(n=0;n<e.length;n++)for(m=e[n].cells,l=0;l<m.length;l++){f=m[l];k=f.parentNode.rowIndex;r=k+"-"+f.cellIndex;p=f.rowSpan||1;t=f.colSpan||1;"undefined"===typeof b[k]&&(b[k]=[]);for(c=0;c<b[k].length+ 1;c++)if("undefined"===typeof b[k][c]){q=c;break}d[r]=q;h=Math.max(q,h);g(f).attr({"data-column":q});for(c=k;c<k+p;c++)for("undefined"===typeof b[c]&&(b[c]=[]),r=b[c],f=q;f<q+t;f++)r[f]="x"}a.config.columns=h+1;return d}function C(a){return/^d/i.test(a)||1===a}function E(a){var b=D(a),d,h,e,n,l,x,k,m=a.config;m.headerList=[];m.headerContent=[];m.debug&&(k=new Date);n=m.cssIcon?'<i class="'+(m.cssIcon===f.css.icon?f.css.icon:m.cssIcon+" "+f.css.icon)+'"></i>':"";m.$headers=g(a).find(m.selectorHeaders).each(function(a){h= g(this);d=m.headers[a];m.headerContent[a]=g(this).html();l=m.headerTemplate.replace(/\{content\}/g,g(this).html()).replace(/\{icon\}/g,n);m.onRenderTemplate&&(e=m.onRenderTemplate.apply(h,[a,l]))&&"string"===typeof e&&(l=e);g(this).html('<div class="tablesorter-header-inner">'+l+"</div>");m.onRenderHeader&&m.onRenderHeader.apply(h,[a]);this.column=b[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=C(f.getData(h,d,"sortInitialOrder")||m.sortInitialOrder)?[1,0,2]:[0,1,2];this.count=-1;this.lockedOrder= !1;x=f.getData(h,d,"lockedOrder")||!1;"undefined"!==typeof x&&!1!==x&&(this.order=this.lockedOrder=C(x)?[1,1,1]:[0,0,0]);h.addClass(f.css.header+" "+m.cssHeader);m.headerList[a]=this;h.parent().addClass(f.css.headerRow+" "+m.cssHeaderRow);m.tabIndex&&h.attr("tabindex",0)});F(a);m.debug&&(r("Built headers:",k),c(m.$headers))}function B(a,b,d){var h=a.config;h.$table.find(h.selectorRemove).remove();s(a);w(a);G(h.$table,b,d)}function F(a){var b,d=a.config;d.$headers.each(function(a,e){b="false"===f.getData(e, d.headers[a],"sorter");e.sortDisabled=b;g(e)[b?"addClass":"removeClass"]("sorter-false")})}function H(a){var b,d,h,e=a.config,n=e.sortList,l=[f.css.sortAsc+" "+e.cssAsc,f.css.sortDesc+" "+e.cssDesc],c=g(a).find("tfoot tr").children().removeClass(l.join(" "));e.$headers.removeClass(l.join(" "));h=n.length;for(b=0;b<h;b++)if(2!==n[b][1]&&(a=e.$headers.not(".sorter-false").filter('[data-column="'+n[b][0]+'"]'+(1===h?":last":"")),a.length))for(d=0;d<a.length;d++)a[d].sortDisabled||(a.eq(d).addClass(l[n[b][1]]), c.length&&c.filter('[data-column="'+n[b][0]+'"]').eq(d).addClass(l[n[b][1]]))}function L(a){if(a.config.widthFixed&&0===g(a).find("colgroup").length){var b=g("<colgroup>"),d=g(a).width();g(a.tBodies[0]).find("tr:first").children("td:visible").each(function(){b.append(g("<col>").css("width",parseInt(g(this).width()/d*1E3,10)/10+"%"))});g(a).prepend(b)}}function M(a,b){var d,h,e,n=a.config,c=b||n.sortList;n.sortList=[];g.each(c,function(a,b){d=[parseInt(b[0],10),parseInt(b[1],10)];if(e=n.$headers[d[0]])n.sortList.push(d), h=g.inArray(d[1],e.order),e.count=0<=h?h:d[1]%(n.sortReset?3:2)})}function N(a,b){return a&&a[b]?a[b].type||"":""}function O(a,b,d){var h,e,n,c=a.config,x=!d[c.sortMultiSortKey],k=g(a);k.trigger("sortStart",a);b.count=d[c.sortResetKey]?2:(b.count+1)%(c.sortReset?3:2);c.sortRestart&&(e=b,c.$headers.each(function(){this===e||!x&&g(this).is("."+f.css.sortDesc+",."+f.css.sortAsc)||(this.count=-1)}));e=b.column;if(x){c.sortList=[];if(null!==c.sortForce)for(h=c.sortForce,d=0;d<h.length;d++)h[d][0]!==e&& c.sortList.push(h[d]);h=b.order[b.count];if(2>h&&(c.sortList.push([e,h]),1<b.colSpan))for(d=1;d<b.colSpan;d++)c.sortList.push([e+d,h])}else if(c.sortAppend&&1<c.sortList.length&&f.isValueInArray(c.sortAppend[0][0],c.sortList)&&c.sortList.pop(),f.isValueInArray(e,c.sortList))for(d=0;d<c.sortList.length;d++)n=c.sortList[d],h=c.$headers[n[0]],n[0]===e&&(n[1]=h.order[b.count],2===n[1]&&(c.sortList.splice(d,1),h.count=-1));else if(h=b.order[b.count],2>h&&(c.sortList.push([e,h]),1<b.colSpan))for(d=1;d< b.colSpan;d++)c.sortList.push([e+d,h]);if(null!==c.sortAppend)for(h=c.sortAppend,d=0;d<h.length;d++)h[d][0]!==e&&c.sortList.push(h[d]);k.trigger("sortBegin",a);setTimeout(function(){H(a);I(a);z(a)},1)}function I(a){var b,d,c,e,n,l,g,p,m,v,t,u,s=0,q=a.config,w=q.textSorter||"",z=q.sortList,B=z.length,C=a.tBodies.length;if(!q.serverSideSorting&&!k(q.cache)){q.debug&&(m=new Date);for(d=0;d<C;d++)n=q.cache[d].colMax,p=(l=q.cache[d].normalized)&&l[0]?l[0].length-1:0,l.sort(function(d,l){for(b=0;b<B;b++){e= z[b][0];g=z[b][1];s=0===g;if(q.sortStable&&d[e]===l[e]&&1===B)break;(c=/n/i.test(N(q.parsers,e)))&&q.strings[e]?(c="boolean"===typeof q.string[q.strings[e]]?(s?1:-1)*(q.string[q.strings[e]]?-1:1):q.strings[e]?q.string[q.strings[e]]||0:0,v=q.numberSorter?q.numberSorter(t[e],u[e],s,n[e],a):f["sortNumeric"+(s?"Asc":"Desc")](d[e],l[e],c,n[e],e,a)):(t=s?d:l,u=s?l:d,v="function"===typeof w?w(t[e],u[e],s,e,a):"object"===typeof w&&w.hasOwnProperty(e)?w[e](t[e],u[e],s,e,a):f["sortNatural"+(s?"Asc":"Desc")](d[e], l[e],e,a,q));if(v)return v}return d[p]-l[p]});q.debug&&r("Sorting on "+z.toString()+" and dir "+g+" time",m)}}function J(a,b){var d=a[0].config;d.pager&&!d.pager.ajax&&a.trigger("updateComplete");"function"===typeof b&&b(a[0])}function G(a,b,d){!1===b||a[0].isProcessing?J(a,d):a.trigger("sorton",[a[0].config.sortList,function(){J(a,d)}])}function K(a){var b=a.config,d=b.$table,c,e;b.$headers.find(b.selectorSort).add(b.$headers.filter(b.selectorSort)).unbind("mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter").bind("mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter", function(d,c){if(!(1!==(d.which||d.button)&&!/sort|keypress/.test(d.type)||"keypress"===d.type&&13!==d.which||"mouseup"===d.type&&!0!==c&&250<(new Date).getTime()-e)){if("mousedown"===d.type)return e=(new Date).getTime(),"INPUT"===d.target.tagName?"":!b.cancelSelection;b.delayInit&&k(b.cache)&&w(a);var h=(/TH|TD/.test(this.tagName)?g(this):g(this).parents("th, td").filter(":first"))[0];h.sortDisabled||O(a,h,d)}});b.cancelSelection&&b.$headers.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none", MozUserSelect:"none"});d.unbind("sortReset update updateRows updateCell updateAll addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(".tablesorter ")).bind("sortReset.tablesorter",function(d){d.stopPropagation();b.sortList=[];H(a);I(a);z(a)}).bind("updateAll.tablesorter",function(b,d,c){b.stopPropagation();f.refreshWidgets(a,!0,!0);f.restoreHeaders(a);E(a);K(a);B(a,d,c)}).bind("update.tablesorter updateRows.tablesorter",function(b,d,c){b.stopPropagation(); F(a);B(a,d,c)}).bind("updateCell.tablesorter",function(c,e,h,f){c.stopPropagation();d.find(b.selectorRemove).remove();var m,k,r;m=d.find("tbody");c=m.index(g(e).parents("tbody").filter(":first"));var s=g(e).parents("tr").filter(":first");e=g(e)[0];m.length&&0<=c&&(k=m.eq(c).find("tr").index(s),r=e.cellIndex,m=b.cache[c].normalized[k].length-1,b.cache[c].row[a.config.cache[c].normalized[k][m]]=s,b.cache[c].normalized[k][r]=b.parsers[r].format(p(a,e,r),a,e,r),G(d,h,f))}).bind("addRows.tablesorter", function(e,f,g,r){e.stopPropagation();if(k(b.cache))F(a),B(a,g,r);else{var m=f.filter("tr").length,v=[],w=f[0].cells.length,u=d.find("tbody").index(f.parents("tbody").filter(":first"));b.parsers||s(a);for(e=0;e<m;e++){for(c=0;c<w;c++)v[c]=b.parsers[c].format(p(a,f[e].cells[c],c),a,f[e].cells[c],c);v.push(b.cache[u].row.length);b.cache[u].row.push([f[e]]);b.cache[u].normalized.push(v);v=[]}G(d,g,r)}}).bind("sorton.tablesorter",function(b,c,e,h){var f=a.config;b.stopPropagation();d.trigger("sortStart", this);M(a,c);H(a);f.delayInit&&k(f.cache)&&w(a);d.trigger("sortBegin",this);I(a);z(a,h);"function"===typeof e&&e(a)}).bind("appendCache.tablesorter",function(b,d,c){b.stopPropagation();z(a,c);"function"===typeof d&&d(a)}).bind("applyWidgetId.tablesorter",function(d,c){d.stopPropagation();f.getWidgetById(c).format(a,b,b.widgetOptions)}).bind("applyWidgets.tablesorter",function(b,d){b.stopPropagation();f.applyWidget(a,d)}).bind("refreshWidgets.tablesorter",function(b,d,c){b.stopPropagation();f.refreshWidgets(a, d,c)}).bind("destroy.tablesorter",function(b,d,c){b.stopPropagation();f.destroy(a,d,c)})}var f=this;f.version="2.14.4";f.parsers=[];f.widgets=[];f.defaults={theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1, sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",textExtraction:"simple",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0,initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssInfoBlock:"tablesorter-infoOnly",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me", debug:!1,headerList:[],empties:{},strings:{},parsers:[]};f.css={table:"tablesorter",childRow:"tablesorter-childRow",header:"tablesorter-header",headerRow:"tablesorter-headerRow",icon:"tablesorter-icon",info:"tablesorter-infoOnly",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc"};f.log=c;f.benchmark=r;f.construct=function(a){return this.each(function(){var b=g.extend(!0,{},f.defaults,a);!this.hasInitialized&&f.buildTable&&"TABLE"!==this.tagName&& f.buildTable(this,b);f.setup(this,b)})};f.setup=function(a,b){if(!a||!a.tHead||0===a.tBodies.length||!0===a.hasInitialized)return b.debug?c("stopping initialization! No table, thead, tbody or tablesorter has already been initialized"):"";var d="",h=g(a),e=g.metadata;a.hasInitialized=!1;a.isProcessing=!0;a.config=b;g.data(a,"tablesorter",b);b.debug&&g.data(a,"startoveralltimer",new Date);b.supportsTextContent="x"===g("<span>x</span>")[0].textContent;b.supportsDataObject=function(a){a[0]=parseInt(a[0], 10);return 1<a[0]||1===a[0]&&4<=parseInt(a[1],10)}(g.fn.jquery.split("."));b.string={max:1,min:-1,"max+":1,"max-":-1,zero:0,none:0,"null":0,top:!0,bottom:!1};/tablesorter\-/.test(h.attr("class"))||(d=""!==b.theme?" tablesorter-"+b.theme:"");b.$table=h.addClass(f.css.table+" "+b.tableClass+d);b.$tbodies=h.children("tbody:not(."+b.cssInfoBlock+")");b.widgetInit={};E(a);L(a);s(a);b.delayInit||w(a);K(a);b.supportsDataObject&&"undefined"!==typeof h.data().sortlist?b.sortList=h.data().sortlist:e&&h.metadata()&& h.metadata().sortlist&&(b.sortList=h.metadata().sortlist);f.applyWidget(a,!0);0<b.sortList.length?h.trigger("sorton",[b.sortList,{},!b.initWidgets]):b.initWidgets&&f.applyWidget(a);b.showProcessing&&h.unbind("sortBegin.tablesorter sortEnd.tablesorter").bind("sortBegin.tablesorter sortEnd.tablesorter",function(b){f.isProcessing(a,"sortBegin"===b.type)});a.hasInitialized=!0;a.isProcessing=!1;b.debug&&f.benchmark("Overall initialization time",g.data(a,"startoveralltimer"));h.trigger("tablesorter-initialized", a);"function"===typeof b.initialized&&b.initialized(a)};f.isProcessing=function(a,b,d){a=g(a);var c=a[0].config;a=d||a.find("."+f.css.header);b?(0<c.sortList.length&&(a=a.filter(function(){return this.sortDisabled?!1:f.isValueInArray(parseFloat(g(this).attr("data-column")),c.sortList)})),a.addClass(f.css.processing+" "+c.cssProcessing)):a.removeClass(f.css.processing+" "+c.cssProcessing)};f.processTbody=function(a,b,d){if(d)return a.isProcessing=!0,b.before('<span class="tablesorter-savemyplace"/>'), d=g.fn.detach?b.detach():b.remove();d=g(a).find("span.tablesorter-savemyplace");b.insertAfter(d);d.remove();a.isProcessing=!1};f.clearTableBody=function(a){g(a)[0].config.$tbodies.empty()};f.restoreHeaders=function(a){var b=a.config;b.$table.find(b.selectorHeaders).each(function(a){g(this).find(".tablesorter-header-inner").length&&g(this).html(b.headerContent[a])})};f.destroy=function(a,b,d){a=g(a)[0];if(a.hasInitialized){f.refreshWidgets(a,!0,!0);var c=g(a),e=a.config,n=c.find("thead:first"),l=n.find("tr."+ f.css.headerRow).removeClass(f.css.headerRow+" "+e.cssHeaderRow),k=c.find("tfoot:first > tr").children("th, td");n.find("tr").not(l).remove();c.removeData("tablesorter").unbind("sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd ".split(" ").join(".tablesorter "));e.$headers.add(k).removeClass([f.css.header,e.cssHeader,e.cssAsc,e.cssDesc,f.css.sortAsc,f.css.sortDesc].join(" ")).removeAttr("data-column"); l.find(e.selectorSort).unbind("mousedown.tablesorter mouseup.tablesorter keypress.tablesorter");f.restoreHeaders(a);!1!==b&&c.removeClass(f.css.table+" "+e.tableClass+" tablesorter-"+e.theme);a.hasInitialized=!1;"function"===typeof d&&d(a)}};f.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,hex:/^0x[0-9a-f]+$/i};f.sortNatural=function(a,b){if(a===b)return 0;var d,c,e,g,l,k;c=f.regex;if(c.hex.test(b)){d=parseInt(a.match(c.hex),16);e=parseInt(b.match(c.hex), 16);if(d<e)return-1;if(d>e)return 1}d=a.replace(c.chunk,"\\0$1\\0").replace(/\\0$/,"").replace(/^\\0/,"").split("\\0");c=b.replace(c.chunk,"\\0$1\\0").replace(/\\0$/,"").replace(/^\\0/,"").split("\\0");k=Math.max(d.length,c.length);for(l=0;l<k;l++){e=isNaN(d[l])?d[l]||0:parseFloat(d[l])||0;g=isNaN(c[l])?c[l]||0:parseFloat(c[l])||0;if(isNaN(e)!==isNaN(g))return isNaN(e)?1:-1;typeof e!==typeof g&&(e+="",g+="");if(e<g)return-1;if(e>g)return 1}return 0};f.sortNaturalAsc=function(a,b,d,c,e){if(a===b)return 0; d=e.string[e.empties[d]||e.emptyTo];return""===a&&0!==d?"boolean"===typeof d?d?-1:1:-d||-1:""===b&&0!==d?"boolean"===typeof d?d?1:-1:d||1:f.sortNatural(a,b)};f.sortNaturalDesc=function(a,b,d,c,e){if(a===b)return 0;d=e.string[e.empties[d]||e.emptyTo];return""===a&&0!==d?"boolean"===typeof d?d?-1:1:d||1:""===b&&0!==d?"boolean"===typeof d?d?1:-1:-d||-1:f.sortNatural(b,a)};f.sortText=function(a,b){return a>b?1:a<b?-1:0};f.getTextValue=function(a,b,d){if(d){var c=a?a.length:0,e=d+b;for(d=0;d<c;d++)e+= a.charCodeAt(d);return b*e}return 0};f.sortNumericAsc=function(a,b,d,c,e,g){if(a===b)return 0;g=g.config;e=g.string[g.empties[e]||g.emptyTo];if(""===a&&0!==e)return"boolean"===typeof e?e?-1:1:-e||-1;if(""===b&&0!==e)return"boolean"===typeof e?e?1:-1:e||1;isNaN(a)&&(a=f.getTextValue(a,d,c));isNaN(b)&&(b=f.getTextValue(b,d,c));return a-b};f.sortNumericDesc=function(a,b,d,c,e,g){if(a===b)return 0;g=g.config;e=g.string[g.empties[e]||g.emptyTo];if(""===a&&0!==e)return"boolean"===typeof e?e?-1:1:e||1;if(""=== b&&0!==e)return"boolean"===typeof e?e?1:-1:-e||-1;isNaN(a)&&(a=f.getTextValue(a,d,c));isNaN(b)&&(b=f.getTextValue(b,d,c));return b-a};f.sortNumeric=function(a,b){return a-b};f.characterEquivalents={a:"\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5",A:"\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5",c:"\u00e7\u0107\u010d",C:"\u00c7\u0106\u010c",e:"\u00e9\u00e8\u00ea\u00eb\u011b\u0119",E:"\u00c9\u00c8\u00ca\u00cb\u011a\u0118",i:"\u00ed\u00ec\u0130\u00ee\u00ef\u0131",I:"\u00cd\u00cc\u0130\u00ce\u00cf",o:"\u00f3\u00f2\u00f4\u00f5\u00f6", O:"\u00d3\u00d2\u00d4\u00d5\u00d6",ss:"\u00df",SS:"\u1e9e",u:"\u00fa\u00f9\u00fb\u00fc\u016f",U:"\u00da\u00d9\u00db\u00dc\u016e"};f.replaceAccents=function(a){var b,d="[",c=f.characterEquivalents;if(!f.characterRegex){f.characterRegexArray={};for(b in c)"string"===typeof b&&(d+=c[b],f.characterRegexArray[b]=RegExp("["+c[b]+"]","g"));f.characterRegex=RegExp(d+"]")}if(f.characterRegex.test(a))for(b in c)"string"===typeof b&&(a=a.replace(f.characterRegexArray[b],b));return a};f.isValueInArray=function(a, b){var d,c=b.length;for(d=0;d<c;d++)if(b[d][0]===a)return!0;return!1};f.addParser=function(a){var b,d=f.parsers.length,c=!0;for(b=0;b<d;b++)f.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(c=!1);c&&f.parsers.push(a)};f.getParserById=function(a){var b,d=f.parsers.length;for(b=0;b<d;b++)if(f.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return f.parsers[b];return!1};f.addWidget=function(a){f.widgets.push(a)};f.getWidgetById=function(a){var b,d,c=f.widgets.length;for(b=0;b<c;b++)if((d= f.widgets[b])&&d.hasOwnProperty("id")&&d.id.toLowerCase()===a.toLowerCase())return d};f.applyWidget=function(a,b){a=g(a)[0];var d=a.config,c=d.widgetOptions,e=[],k,l,p;d.debug&&(k=new Date);d.widgets.length&&(d.widgets=g.grep(d.widgets,function(a,b){return g.inArray(a,d.widgets)===b}),g.each(d.widgets||[],function(a,b){(p=f.getWidgetById(b))&&p.id&&(p.priority||(p.priority=10),e[a]=p)}),e.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority?0:1}),g.each(e,function(e,f){if(f){if(b|| !d.widgetInit[f.id])f.hasOwnProperty("options")&&(c=a.config.widgetOptions=g.extend(!0,{},f.options,c)),f.hasOwnProperty("init")&&f.init(a,f,d,c),d.widgetInit[f.id]=!0;!b&&f.hasOwnProperty("format")&&f.format(a,d,c,!1)}}));d.debug&&(l=d.widgets.length,r("Completed "+(!0===b?"initializing ":"applying ")+l+" widget"+(1!==l?"s":""),k))};f.refreshWidgets=function(a,b,d){a=g(a)[0];var h,e=a.config,k=e.widgets,l=f.widgets,r=l.length;for(h=0;h<r;h++)l[h]&&l[h].id&&(b||0>g.inArray(l[h].id,k))&&(e.debug&& c("Refeshing widgets: Removing "+l[h].id),l[h].hasOwnProperty("remove")&&e.widgetInit[l[h].id]&&(l[h].remove(a,e,e.widgetOptions),e.widgetInit[l[h].id]=!1));!0!==d&&f.applyWidget(a,b)};f.getData=function(a,b,d){var c="";a=g(a);var e,f;if(!a.length)return"";e=g.metadata?a.metadata():!1;f=" "+(a.attr("class")||"");"undefined"!==typeof a.data(d)||"undefined"!==typeof a.data(d.toLowerCase())?c+=a.data(d)||a.data(d.toLowerCase()):e&&"undefined"!==typeof e[d]?c+=e[d]:b&&"undefined"!==typeof b[d]?c+=b[d]: " "!==f&&f.match(" "+d+"-")&&(c=f.match(RegExp("\\s"+d+"-([\\w-]+)"))[1]||"");return g.trim(c)};f.formatFloat=function(a,b){if("string"!==typeof a||""===a)return a;var c;a=(b&&b.config?!1!==b.config.usNumberFormat:"undefined"!==typeof b?b:1)?a.replace(/,/g,""):a.replace(/[\s|\.]/g,"").replace(/,/g,".");/^\s*\([.\d]+\)/.test(a)&&(a=a.replace(/^\s*\(([.\d]+)\)/,"-$1"));c=parseFloat(a);return isNaN(c)?g.trim(a):c};f.isDigit=function(a){return isNaN(a)?/^[\-+(]?\d+[)]?$/.test(a.toString().replace(/[,.'"\s]/g, "")):!0}}});var p=g.tablesorter;g.fn.extend({tablesorter:p.construct});p.addParser({id:"text",is:function(){return!0},format:function(c,r){var k=r.config;c&&(c=g.trim(k.ignoreCase?c.toLocaleLowerCase():c),c=k.sortLocaleCompare?p.replaceAccents(c):c);return c},type:"text"});p.addParser({id:"digit",is:function(c){return p.isDigit(c)},format:function(c,r){var k=p.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),r);return c&&"number"===typeof k?k:c?g.trim(c&&r.config.ignoreCase?c.toLocaleLowerCase():c): c},type:"numeric"});p.addParser({id:"currency",is:function(c){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((c||"").replace(/[,. ]/g,""))},format:function(c,r){var k=p.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),r);return c&&"number"===typeof k?k:c?g.trim(c&&r.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"});p.addParser({id:"ipAddress",is:function(c){return/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/.test(c)},format:function(c, g){var k,t=c?c.split("."):"",s="",w=t.length;for(k=0;k<w;k++)s+=("00"+t[k]).slice(-3);return c?p.formatFloat(s,g):c},type:"numeric"});p.addParser({id:"url",is:function(c){return/^(https?|ftp|file):\/\//.test(c)},format:function(c){return c?g.trim(c.replace(/(https?|ftp|file):\/\//,"")):c},type:"text"});p.addParser({id:"isoDate",is:function(c){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(c)},format:function(c,g){return c?p.formatFloat(""!==c?(new Date(c.replace(/-/g,"/"))).getTime()||"":"",g):c}, type:"numeric"});p.addParser({id:"percent",is:function(c){return/(\d\s*?%|%\s*?\d)/.test(c)&&15>c.length},format:function(c,g){return c?p.formatFloat(c.replace(/%/g,""),g):c},type:"numeric"});p.addParser({id:"usLongDate",is:function(c){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(c)||/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(c)},format:function(c,g){return c?p.formatFloat((new Date(c.replace(/(\S)([AP]M)$/i,"$1 $2"))).getTime()||"",g):c},type:"numeric"}); p.addParser({id:"shortDate",is:function(c){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((c||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(c,g,k,t){if(c){k=g.config;var s=k.headerList[t];t=s.dateFormat||p.getData(s,k.headers[t],"dateFormat")||k.dateFormat;c=c.replace(/\s+/g," ").replace(/[\-.,]/g,"/");"mmddyyyy"===t?c=c.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===t?c=c.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1"):"yyyymmdd"===t&&(c=c.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3"))}return c?p.formatFloat((new Date(c)).getTime()||"",g):c},type:"numeric"});p.addParser({id:"time",is:function(c){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(c)},format:function(c,g){return c?p.formatFloat((new Date("2000/01/01 "+c.replace(/(\S)([AP]M)$/i,"$1 $2"))).getTime()||"",g):c},type:"numeric"});p.addParser({id:"metadata",is:function(){return!1},format:function(c,p,k){c=p.config; c=c.parserMetadataName?c.parserMetadataName:"sortValue";return g(k).metadata()[c]},type:"numeric"});p.addWidget({id:"zebra",priority:90,format:function(c,r,k){var t,s,w,z,D,C,E=RegExp(r.cssChildRow,"i"),B=r.$tbodies;r.debug&&(D=new Date);for(c=0;c<B.length;c++)t=B.eq(c),C=t.children("tr").length,1<C&&(w=0,t=t.children("tr:visible").not(r.selectorRemove),t.each(function(){s=g(this);E.test(this.className)||w++;z=0===w%2;s.removeClass(k.zebra[z?1:0]).addClass(k.zebra[z?0:1])}));r.debug&&p.benchmark("Applying Zebra widget", D)},remove:function(c,p,k){var t;p=p.$tbodies;var s=(k.zebra||["even","odd"]).join(" ");for(k=0;k<p.length;k++)t=g.tablesorter.processTbody(c,p.eq(k),!0),t.children().removeClass(s),g.tablesorter.processTbody(c,t,!1)}})}(jQuery); -
extensions/UserAdvManager/branches/2.6/admin/template/js/jquery.tablesorter.pager.js
r6399 r26948 1 (function($) { 2 $.extend({ 3 tablesorterPager: new function() { 4 5 function updatePageDisplay(c) { 6 var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages); 7 } 8 9 function setPageSize(table,size) { 10 var c = table.config; 11 c.size = size; 12 c.totalPages = Math.ceil(c.totalRows / c.size); 13 c.pagerPositionSet = false; 14 moveToPage(table); 15 fixPosition(table); 16 } 17 18 function fixPosition(table) { 19 var c = table.config; 20 if(!c.pagerPositionSet && c.positionFixed) { 21 var c = table.config, o = $(table); 22 if(o.offset) { 23 c.container.css({ 24 top: o.offset().top + o.height() + 'px', 25 position: 'absolute' 1 /*! 2 * tablesorter pager plugin 3 * updated 12/16/2013 (v2.14.5) 4 */ 5 /*jshint browser:true, jquery:true, unused:false */ 6 ;(function($) { 7 "use strict"; 8 /*jshint supernew:true */ 9 var ts = $.tablesorter; 10 11 $.extend({ tablesorterPager: new function() { 12 13 this.defaults = { 14 // target the pager markup 15 container: null, 16 17 // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}" 18 // where {page} is replaced by the page number, {size} is replaced by the number of records to show, 19 // {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds 20 // the filterList to the url into an "fcol" array. 21 // So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url 22 // and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url 23 ajaxUrl: null, 24 25 // modify the url after all processing has been applied 26 customAjaxUrl: function(table, url) { return url; }, 27 28 // modify the $.ajax object to allow complete control over your ajax requests 29 ajaxObject: { 30 dataType: 'json' 31 }, 32 33 // set this to false if you want to block ajax loading on init 34 processAjaxOnInit: true, 35 36 // process ajax so that the following information is returned: 37 // [ total_rows (number), rows (array of arrays), headers (array; optional) ] 38 // example: 39 // [ 40 // 100, // total rows 41 // [ 42 // [ "row1cell1", "row1cell2", ... "row1cellN" ], 43 // [ "row2cell1", "row2cell2", ... "row2cellN" ], 44 // ... 45 // [ "rowNcell1", "rowNcell2", ... "rowNcellN" ] 46 // ], 47 // [ "header1", "header2", ... "headerN" ] // optional 48 // ] 49 ajaxProcessing: function(ajax){ return [ 0, [], null ]; }, 50 51 // output default: '{page}/{totalPages}' 52 // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} 53 output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}' 54 55 // apply disabled classname to the pager arrows when the rows at either extreme is visible 56 updateArrows: true, 57 58 // starting page of the pager (zero based index) 59 page: 0, 60 61 // Number of visible rows 62 size: 10, 63 64 // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) 65 savePages: true, 66 67 // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty 68 // table row set to a height to compensate; default is false 69 fixedHeight: false, 70 71 // count child rows towards the set page size? (set true if it is a visible table row within the pager) 72 // if true, child row(s) may not appear to be attached to its parent row, may be split across pages or 73 // may distort the table if rowspan or cellspans are included. 74 countChildRows: false, 75 76 // remove rows from the table to speed up the sort of large tables. 77 // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. 78 removeRows: false, // removing rows in larger tables speeds up the sort 79 80 // css class names of pager arrows 81 cssFirst: '.first', // go to first page arrow 82 cssPrev: '.prev', // previous page arrow 83 cssNext: '.next', // next page arrow 84 cssLast: '.last', // go to last page arrow 85 cssGoto: '.gotoPage', // go to page selector - select dropdown that sets the current page 86 cssPageDisplay: '.pagedisplay', // location of where the "output" is displayed 87 cssPageSize: '.pagesize', // page size selector - select dropdown that sets the "size" option 88 cssErrorRow: 'tablesorter-errorRow', // error information row 89 90 // class added to arrows when at the extremes (i.e. prev/first arrows are "disabled" when on the first page) 91 cssDisabled: 'disabled', // Note there is no period "." in front of this class name 92 93 // stuff not set by the user 94 totalRows: 0, 95 totalPages: 0, 96 filteredRows: 0, 97 filteredPages: 0, 98 ajaxCounter: 0, 99 currentFilters: [], 100 startRow: 0, 101 endRow: 0, 102 $size: null, 103 last: {} 104 105 }; 106 107 var $this = this, 108 109 // hide arrows at extremes 110 pagerArrows = function(p, disable) { 111 var a = 'addClass', 112 r = 'removeClass', 113 d = p.cssDisabled, 114 dis = !!disable, 115 tp = Math.min( p.totalPages, p.filteredPages ); 116 if ( p.updateArrows ) { 117 p.$container.find(p.cssFirst + ',' + p.cssPrev)[ ( dis || p.page === 0 ) ? a : r ](d); 118 p.$container.find(p.cssNext + ',' + p.cssLast)[ ( dis || p.page === tp - 1 || p.totalPages === 0 ) ? a : r ](d); 119 } 120 }, 121 122 updatePageDisplay = function(table, p, flag) { 123 var i, pg, s, out, 124 c = table.config, 125 f = c.$table.hasClass('hasFilters') && !p.ajaxUrl, 126 t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove + 127 (p.countChildRows ? '' : ',.' + c.cssChildRow), 128 sz = p.size || 10; // don't allow dividing by zero 129 p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method 130 p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t ).length : p.totalRows; 131 p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages; 132 if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) { 133 t = (p.size * p.page > p.filteredRows); 134 p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1); 135 p.page = (t) ? 0 : p.page; 136 p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) ); 137 out = p.$container.find(p.cssPageDisplay); 138 // form the output string (can now get a new output string from the server) 139 s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || p.output : p.output ) 140 // {page} = one-based index; {page+#} = zero based index +/- value 141 .replace(/\{page([\-+]\d+)?\}/gi, function(m,n){ 142 return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0; 143 }) 144 // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object) 145 .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){ 146 var str = m.replace(/[{}\s]/g,''), 147 extra = str.split(':'), 148 data = p.ajaxData, 149 // return zero for default page/row numbers 150 deflt = /(rows?|pages?)$/i.test(str) ? 0 : ''; 151 return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt; 152 }); 153 if (out.length) { 154 out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s); 155 if ( p.$goto.length ) { 156 t = ''; 157 pg = Math.min( p.totalPages, p.filteredPages ); 158 for ( i = 1; i <= pg; i++ ) { 159 t += '<option>' + i + '</option>'; 160 } 161 p.$goto.html(t).val( p.page + 1 ); 162 } 163 } 164 } 165 pagerArrows(p); 166 if (p.initialized && flag !== false) { 167 c.$table.trigger('pagerComplete', p); 168 // save pager info to storage 169 if (p.savePages && ts.storage) { 170 ts.storage(table, 'tablesorter-pager', { 171 page : p.page, 172 size : p.size 173 }); 174 } 175 } 176 }, 177 178 fixHeight = function(table, p) { 179 var d, h, 180 c = table.config, 181 $b = c.$tbodies.eq(0); 182 if (p.fixedHeight) { 183 $b.find('tr.pagerSavedHeightSpacer').remove(); 184 h = $.data(table, 'pagerSavedHeight'); 185 if (h) { 186 d = h - $b.height(); 187 if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) { 188 $b.append('<tr class="pagerSavedHeightSpacer ' + c.selectorRemove.replace(/(tr)?\./g,'') + '" style="height:' + d + 'px;"></tr>'); 189 } 190 } 191 } 192 }, 193 194 changeHeight = function(table, p) { 195 var $b = table.config.$tbodies.eq(0); 196 $b.find('tr.pagerSavedHeightSpacer').remove(); 197 $.data(table, 'pagerSavedHeight', $b.height()); 198 fixHeight(table, p); 199 $.data(table, 'pagerLastSize', p.size); 200 }, 201 202 hideRows = function(table, p){ 203 if (!p.ajaxUrl) { 204 var i, 205 c = table.config, 206 rows = c.$tbodies.eq(0).children(), 207 l = rows.length, 208 s = ( p.page * p.size ), 209 e = s + p.size, 210 f = c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered', 211 j = 0; // size counter 212 for ( i = 0; i < l; i++ ){ 213 if ( !rows[i].className.match(f) ) { 214 rows[i].style.display = ( j >= s && j < e ) ? '' : 'none'; 215 // don't count child rows 216 j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1; 217 } 218 } 219 } 220 }, 221 222 hideRowsSetup = function(table, p){ 223 p.size = parseInt( p.$size.val(), 10 ) || p.size; 224 $.data(table, 'pagerLastSize', p.size); 225 pagerArrows(p); 226 if ( !p.removeRows ) { 227 hideRows(table, p); 228 $(table).bind('sortEnd.pager filterEnd.pager', function(){ 229 hideRows(table, p); 230 }); 231 } 232 }, 233 234 renderAjax = function(data, table, p, xhr, exception){ 235 // process data 236 if ( typeof(p.ajaxProcessing) === "function" ) { 237 // ajaxProcessing result: [ total, rows, headers ] 238 var i, j, hsh, $f, $sh, t, th, d, l, $err, rr_count, 239 c = table.config, 240 $t = c.$table, 241 tds = '', 242 result = p.ajaxProcessing(data, table) || [ 0, [] ], 243 hl = $t.find('thead th').length; 244 245 $t.find('thead tr.' + p.cssErrorRow).remove(); // Clean up any previous error. 246 247 if ( exception ) { 248 if (c.debug) { 249 ts.log('Ajax Error', xhr, exception); 250 } 251 $err = $('<tr class="' + p.cssErrorRow + '"><td style="text-align:center;" colspan="' + hl + '">' + ( 252 xhr.status === 0 ? 'Not connected, verify Network' : 253 xhr.status === 404 ? 'Requested page not found [404]' : 254 xhr.status === 500 ? 'Internal Server Error [500]' : 255 exception === 'parsererror' ? 'Requested JSON parse failed' : 256 exception === 'timeout' ? 'Time out error' : 257 exception === 'abort' ? 'Ajax Request aborted' : 258 'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']' ) + '</td></tr>') 259 .click(function(){ 260 $(this).remove(); 261 }) 262 // add error row to thead instead of tbody, or clicking on the header will result in a parser error 263 .appendTo( $t.find('thead:first') ); 264 c.$tbodies.eq(0).empty(); 265 } else { 266 // process ajax object 267 if (!$.isArray(result)) { 268 p.ajaxData = result; 269 p.totalRows = result.total; 270 th = result.headers; 271 d = result.rows; 272 } else { 273 // allow [ total, rows, headers ] or [ rows, total, headers ] 274 t = isNaN(result[0]) && !isNaN(result[1]); 275 //ensure a zero returned row count doesn't fail the logical || 276 rr_count = result[t ? 1 : 0]; 277 p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count; 278 d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data 279 th = result[2]; // headers 280 } 281 l = d.length; 282 if (d instanceof jQuery) { 283 // append jQuery object 284 c.$tbodies.eq(0).empty().append(d); 285 } else if (l) { 286 // build table from array 287 for ( i = 0; i < l; i++ ) { 288 tds += '<tr>'; 289 for ( j = 0; j < d[i].length; j++ ) { 290 // build tbody cells; watch for data containing HTML markup - see #434 291 tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>'; 292 } 293 tds += '</tr>'; 294 } 295 // add rows to first tbody 296 p.processAjaxOnInit ? c.$tbodies.eq(0).html( tds ) : p.processAjaxOnInit = true; 297 } 298 // only add new header text if the length matches 299 if ( th && th.length === hl ) { 300 hsh = $t.hasClass('hasStickyHeaders'); 301 $sh = hsh ? c.widgetOptions.$sticky.children('thead:first').children().children() : ''; 302 $f = $t.find('tfoot tr:first').children(); 303 // don't change td headers (may contain pager) 304 c.$headers.filter('th').each(function(j){ 305 var $t = $(this), icn; 306 // add new test within the first span it finds, or just in the header 307 if ( $t.find('.' + ts.css.icon).length ) { 308 icn = $t.find('.' + ts.css.icon).clone(true); 309 $t.find('.tablesorter-header-inner').html( th[j] ).append(icn); 310 if ( hsh && $sh.length ) { 311 icn = $sh.eq(j).find('.' + ts.css.icon).clone(true); 312 $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icn); 313 } 314 } else { 315 $t.find('.tablesorter-header-inner').html( th[j] ); 316 if (hsh && $sh.length) { 317 $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ); 318 } 319 } 320 $f.eq(j).html( th[j] ); 26 321 }); 27 322 } 28 c.pagerPositionSet = true; 29 } 30 } 31 32 function moveToFirstPage(table) { 33 var c = table.config; 34 c.page = 0; 35 moveToPage(table); 36 } 37 38 function moveToLastPage(table) { 39 var c = table.config; 40 c.page = (c.totalPages-1); 41 moveToPage(table); 42 } 43 44 function moveToNextPage(table) { 45 var c = table.config; 46 c.page++; 47 if(c.page >= (c.totalPages-1)) { 48 c.page = (c.totalPages-1); 49 } 50 moveToPage(table); 51 } 52 53 function moveToPrevPage(table) { 54 var c = table.config; 55 c.page--; 56 if(c.page <= 0) { 57 c.page = 0; 58 } 59 moveToPage(table); 60 } 61 62 63 function moveToPage(table) { 64 var c = table.config; 65 if(c.page < 0 || c.page > (c.totalPages-1)) { 66 c.page = 0; 67 } 68 69 renderTable(table,c.rowsCopy); 70 } 71 72 function renderTable(table,rows) { 73 74 var c = table.config; 75 var l = rows.length; 76 var s = (c.page * c.size); 77 var e = (s + c.size); 78 if(e > rows.length ) { 323 } 324 if (c.showProcessing) { 325 ts.isProcessing(table); // remove loading icon 326 } 327 // make sure last pager settings are saved, prevents multiple server side calls with 328 // the same parameters 329 p.last.totalPages = p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) ); 330 p.last.currentFilters = p.currentFilters; 331 p.last.sortList = (c.sortList || []).join(','); 332 updatePageDisplay(table, p); 333 fixHeight(table, p); 334 // apply widgets after table has rendered 335 $t.trigger('applyWidgets'); 336 $t.trigger('update', [false, function(){ 337 if (p.initialized) { 338 $t.trigger('updateComplete'); 339 $t.trigger('pagerChange', p); 340 } 341 }]); 342 } 343 if (!p.initialized) { 344 p.initialized = true; 345 $(table).trigger('pagerInitialized', p); 346 } 347 }, 348 349 getAjax = function(table, p){ 350 var url = getAjaxUrl(table, p), 351 $doc = $(document), 352 counter, 353 c = table.config; 354 if ( url !== '' ) { 355 if (c.showProcessing) { 356 ts.isProcessing(table, true); // show loading icon 357 } 358 $doc.bind('ajaxError.pager', function(e, xhr, settings, exception) { 359 renderAjax(null, table, p, xhr, exception); 360 $doc.unbind('ajaxError.pager'); 361 }); 362 363 counter = ++p.ajaxCounter; 364 365 p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl 366 p.ajaxObject.success = function(data) { 367 // Refuse to process old ajax commands that were overwritten by new ones - see #443 368 if (counter < p.ajaxCounter){ 369 return; 370 } 371 renderAjax(data, table, p); 372 $doc.unbind('ajaxError.pager'); 373 if (typeof p.oldAjaxSuccess === 'function') { 374 p.oldAjaxSuccess(data); 375 } 376 }; 377 if (c.debug) { 378 ts.log('ajax initialized', p.ajaxObject); 379 } 380 $.ajax(p.ajaxObject); 381 } 382 }, 383 384 getAjaxUrl = function(table, p) { 385 var c = table.config, 386 url = (p.ajaxUrl) ? p.ajaxUrl 387 // allow using "{page+1}" in the url string to switch to a non-zero based index 388 .replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); }) 389 .replace(/\{size\}/g, p.size) : '', 390 sl = c.sortList, 391 fl = p.currentFilters || $(table).data('lastSearch') || [], 392 sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/), 393 filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/), 394 arry = []; 395 if (sortCol) { 396 sortCol = sortCol[1]; 397 $.each(sl, function(i,v){ 398 arry.push(sortCol + '[' + v[0] + ']=' + v[1]); 399 }); 400 // if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col" 401 url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol ); 402 arry = []; 403 } 404 if (filterCol) { 405 filterCol = filterCol[1]; 406 $.each(fl, function(i,v){ 407 if (v) { 408 arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v)); 409 } 410 }); 411 // if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol" 412 url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol ); 413 p.currentFilters = fl; 414 } 415 if ( typeof(p.customAjaxUrl) === "function" ) { 416 url = p.customAjaxUrl(table, url); 417 } 418 if (c.debug) { 419 ts.log('Pager ajax url: ' + url); 420 } 421 return url; 422 }, 423 424 renderTable = function(table, rows, p) { 425 var i, $tb, 426 l = rows && rows.length || 0, // rows may be undefined 427 s = ( p.page * p.size ), 428 e = ( s + p.size ); 429 if ( l < 1 ) { return; } // empty table, abort! 430 if ( p.page >= p.totalPages ) { 431 // lets not render the table more than once 432 moveToLastPage(table, p); 433 } 434 p.isDisabled = false; // needed because sorting will change the page and re-enable the pager 435 if (p.initialized) { $(table).trigger('pagerChange', p); } 436 437 if ( !p.removeRows ) { 438 hideRows(table, p); 439 } else { 440 if ( e > rows.length ) { 79 441 e = rows.length; 80 442 } 81 82 83 var tableBody = $(table.tBodies[0]); 84 85 // clear the table body 86 87 $.tablesorter.clearTableBody(table); 88 89 for(var i = s; i < e; i++) { 90 91 //tableBody.append(rows[i]); 92 93 var o = rows[i]; 94 var l = o.length; 95 for(var j=0; j < l; j++) { 96 97 tableBody[0].appendChild(o[j]); 98 99 } 100 } 101 102 fixPosition(table,tableBody); 103 104 $(table).trigger("applyWidgets"); 105 106 if( c.page >= c.totalPages ) { 107 moveToLastPage(table); 108 } 109 110 updatePageDisplay(c); 111 } 112 113 this.appender = function(table,rows) { 114 115 var c = table.config; 116 443 ts.clearTableBody(table); 444 $tb = ts.processTbody(table, table.config.$tbodies.eq(0), true); 445 for ( i = s; i < e; i++ ) { 446 $tb.append(rows[i]); 447 } 448 ts.processTbody(table, $tb, false); 449 } 450 451 updatePageDisplay(table, p); 452 if ( !p.isDisabled ) { fixHeight(table, p); } 453 $(table).trigger('applyWidgets'); 454 }, 455 456 showAllRows = function(table, p){ 457 if ( p.ajax ) { 458 pagerArrows(p, true); 459 } else { 460 p.isDisabled = true; 461 $.data(table, 'pagerLastPage', p.page); 462 $.data(table, 'pagerLastSize', p.size); 463 p.page = 0; 464 p.size = p.totalRows; 465 p.totalPages = 1; 466 $(table).addClass('pagerDisabled').find('tr.pagerSavedHeightSpacer').remove(); 467 renderTable(table, table.config.rowsCopy, p); 468 if (table.config.debug) { 469 ts.log('pager disabled'); 470 } 471 } 472 // disable size selector 473 p.$size.add(p.$goto).each(function(){ 474 $(this).addClass(p.cssDisabled)[0].disabled = true; 475 }); 476 }, 477 478 moveToPage = function(table, p, flag) { 479 if ( p.isDisabled ) { return; } 480 var c = table.config, 481 l = p.last, 482 pg = Math.min( p.totalPages, p.filteredPages ); 483 if ( p.page < 0 ) { p.page = 0; } 484 if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; } 485 // don't allow rendering multiple times on the same page/size/totalpages/filters/sorts 486 if ( l.page === p.page && l.size === p.size && l.totalPages === p.totalPages && 487 (l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') && 488 l.sortList === (c.sortList || []).join(',') ) { return; } 489 if (c.debug) { 490 ts.log('Pager changing to page ' + p.page); 491 } 492 p.last = { 493 page : p.page, 494 size : p.size, 495 // fixes #408; modify sortList otherwise it auto-updates 496 sortList : (c.sortList || []).join(','), 497 totalPages : p.totalPages, 498 currentFilters : p.currentFilters || [] 499 }; 500 if (p.ajax) { 501 getAjax(table, p); 502 } else if (!p.ajax) { 503 renderTable(table, table.config.rowsCopy, p); 504 } 505 $.data(table, 'pagerLastPage', p.page); 506 if (p.initialized && flag !== false) { 507 c.$table.trigger('pageMoved', p); 508 c.$table.trigger('applyWidgets'); 509 } 510 }, 511 512 setPageSize = function(table, size, p) { 513 p.size = size || p.size || 10; 514 p.$size.val(p.size); 515 $.data(table, 'pagerLastPage', p.page); 516 $.data(table, 'pagerLastSize', p.size); 517 p.totalPages = Math.ceil( p.totalRows / p.size ); 518 moveToPage(table, p); 519 }, 520 521 moveToFirstPage = function(table, p) { 522 p.page = 0; 523 moveToPage(table, p); 524 }, 525 526 moveToLastPage = function(table, p) { 527 p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); 528 moveToPage(table, p); 529 }, 530 531 moveToNextPage = function(table, p) { 532 p.page++; 533 if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) { 534 p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); 535 } 536 moveToPage(table, p); 537 }, 538 539 moveToPrevPage = function(table, p) { 540 p.page--; 541 if ( p.page <= 0 ) { 542 p.page = 0; 543 } 544 moveToPage(table, p); 545 }, 546 547 destroyPager = function(table, p){ 548 showAllRows(table, p); 549 p.$container.hide(); // hide pager 550 table.config.appender = null; // remove pager appender function 551 p.initialized = false; 552 $(table).unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager'); 553 if (ts.storage) { 554 ts.storage(table, 'tablesorter-pager', ''); 555 } 556 }, 557 558 enablePager = function(table, p, triggered){ 559 var pg = p.$size.removeClass(p.cssDisabled).removeAttr('disabled'); 560 p.$goto.removeClass(p.cssDisabled).removeAttr('disabled'); 561 p.isDisabled = false; 562 p.page = $.data(table, 'pagerLastPage') || p.page || 0; 563 p.size = $.data(table, 'pagerLastSize') || parseInt(pg.find('option[selected]').val(), 10) || p.size || 10; 564 pg.val(p.size); // set page size 565 p.totalPages = Math.ceil( Math.min( p.totalPages, p.filteredPages ) / p.size ); 566 if ( triggered ) { 567 $(table).trigger('update'); 568 setPageSize(table, p.size, p); 569 hideRowsSetup(table, p); 570 fixHeight(table, p); 571 if (table.config.debug) { 572 ts.log('pager enabled'); 573 } 574 } 575 }; 576 577 $this.appender = function(table, rows) { 578 var c = table.config, 579 p = c.pager; 580 if ( !p.ajax ) { 117 581 c.rowsCopy = rows; 118 c.totalRows = rows.length; 119 c.totalPages = Math.ceil(c.totalRows / c.size); 120 121 renderTable(table,rows); 122 }; 123 124 this.defaults = { 125 size: 10, 126 offset: 0, 127 page: 0, 128 totalRows: 0, 129 totalPages: 0, 130 container: null, 131 cssNext: '.next', 132 cssPrev: '.prev', 133 cssFirst: '.first', 134 cssLast: '.last', 135 cssPageDisplay: '.pagedisplay', 136 cssPageSize: '.pagesize', 137 seperator: "/", 138 positionFixed: true, 139 appender: this.appender 140 }; 141 142 this.construct = function(settings) { 143 144 return this.each(function() { 145 146 config = $.extend(this.config, $.tablesorterPager.defaults, settings); 147 148 var table = this, pager = config.container; 149 150 $(this).trigger("appendCache"); 151 152 config.size = parseInt($(".pagesize",pager).val()); 153 154 $(config.cssFirst,pager).click(function() { 155 moveToFirstPage(table); 582 p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children().length : rows.length; 583 p.size = $.data(table, 'pagerLastSize') || p.size || 10; 584 p.totalPages = Math.ceil( p.totalRows / p.size ); 585 renderTable(table, rows, p); 586 } 587 }; 588 589 $this.construct = function(settings) { 590 return this.each(function() { 591 // check if tablesorter has initialized 592 if (!(this.config && this.hasInitialized)) { return; } 593 var t, ctrls, fxn, 594 table = this, 595 c = table.config, 596 p = c.pager = $.extend( {}, $.tablesorterPager.defaults, settings ), 597 $t = c.$table, 598 // added in case the pager is reinitialized after being destroyed. 599 pager = p.$container = $(p.container).addClass('tablesorter-pager').show(); 600 if (c.debug) { 601 ts.log('Pager initializing'); 602 } 603 p.oldAjaxSuccess = p.oldAjaxSuccess || p.ajaxObject.success; 604 c.appender = $this.appender; 605 if (ts.filter && $.inArray('filter', c.widgets) >= 0) { 606 // get any default filter settings (data-value attribute) fixes #388 607 p.currentFilters = c.$table.data('lastSearch') || ts.filter.setDefaults(table, c, c.widgetOptions) || []; 608 // set, but don't apply current filters 609 ts.setFilters(table, p.currentFilters, false); 610 } 611 if (p.savePages && ts.storage) { 612 t = ts.storage(table, 'tablesorter-pager') || {}; // fixes #387 613 p.page = isNaN(t.page) ? p.page : t.page; 614 p.size = ( isNaN(t.size) ? p.size : t.size ) || 10; 615 $.data(table, 'pagerLastSize', p.size); 616 } 617 618 $t 619 .unbind('filterStart filterEnd sortEnd disable enable destroy update updateRows updateAll addRows pageSize '.split(' ').join('.pager ')) 620 .bind('filterStart.pager', function(e, filters) { 621 p.currentFilters = filters; 622 p.page = 0; // fixes #456 623 }) 624 // update pager after filter widget completes 625 .bind('filterEnd.pager sortEnd.pager', function() { 626 if (p.initialized) { 627 moveToPage(table, p, false); 628 updatePageDisplay(table, p, false); 629 fixHeight(table, p); 630 } 631 }) 632 .bind('disable.pager', function(e){ 633 e.stopPropagation(); 634 showAllRows(table, p); 635 }) 636 .bind('enable.pager', function(e){ 637 e.stopPropagation(); 638 enablePager(table, p, true); 639 }) 640 .bind('destroy.pager', function(e){ 641 e.stopPropagation(); 642 destroyPager(table, p); 643 }) 644 .bind('update updateRows updateAll addRows '.split(' ').join('.pager '), function(e){ 645 e.stopPropagation(); 646 hideRows(table, p); 647 }) 648 .bind('pageSize.pager', function(e,v){ 649 e.stopPropagation(); 650 setPageSize(table, parseInt(v, 10) || 10, p); 651 hideRows(table, p); 652 updatePageDisplay(table, p, false); 653 if (p.$size.length) { p.$size.val(p.size); } // twice? 654 }) 655 .bind('pageSet.pager', function(e,v){ 656 e.stopPropagation(); 657 p.page = (parseInt(v, 10) || 1) - 1; 658 if (p.$goto.length) { p.$goto.val(p.size); } // twice? 659 moveToPage(table, p); 660 updatePageDisplay(table, p, false); 661 }); 662 663 // clicked controls 664 ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ]; 665 fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ]; 666 pager.find(ctrls.join(',')) 667 .unbind('click.pager') 668 .bind('click.pager', function(e){ 669 e.stopPropagation(); 670 var i, $t = $(this), l = ctrls.length; 671 if ( !$t.hasClass(p.cssDisabled) ) { 672 for (i = 0; i < l; i++) { 673 if ($t.is(ctrls[i])) { 674 fxn[i](table, p); 675 break; 676 } 677 } 678 } 679 }); 680 681 // goto selector 682 p.$goto = pager.find(p.cssGoto); 683 if ( p.$goto.length ) { 684 p.$goto 685 .unbind('change') 686 .bind('change', function(){ 687 p.page = $(this).val() - 1; 688 moveToPage(table, p); 689 updatePageDisplay(table, p, false); 690 }); 691 } 692 693 // page size selector 694 p.$size = pager.find(p.cssPageSize); 695 if ( p.$size.length ) { 696 p.$size.unbind('change.pager').bind('change.pager', function() { 697 p.$size.val( $(this).val() ); // in case there are more than one pagers 698 if ( !$(this).hasClass(p.cssDisabled) ) { 699 setPageSize(table, parseInt( $(this).val(), 10 ), p); 700 changeHeight(table, p); 701 } 156 702 return false; 157 703 }); 158 $(config.cssNext,pager).click(function() { 159 moveToNextPage(table); 160 return false; 161 }); 162 $(config.cssPrev,pager).click(function() { 163 moveToPrevPage(table); 164 return false; 165 }); 166 $(config.cssLast,pager).click(function() { 167 moveToLastPage(table); 168 return false; 169 }); 170 $(config.cssPageSize,pager).change(function() { 171 setPageSize(table,parseInt($(this).val())); 172 return false; 173 }); 174 }); 175 }; 176 177 } 178 }); 179 // extend plugin scope 180 $.fn.extend({ 181 tablesorterPager: $.tablesorterPager.construct 182 }); 183 184 })(jQuery); 704 } 705 706 // clear initialized flag 707 p.initialized = false; 708 // before initialization event 709 $t.trigger('pagerBeforeInitialized', p); 710 711 enablePager(table, p, false); 712 713 if ( typeof(p.ajaxUrl) === 'string' ) { 714 // ajax pager; interact with database 715 p.ajax = true; 716 //When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side. 717 c.widgetOptions.filter_serversideFiltering = true; 718 c.serverSideSorting = true; 719 moveToPage(table, p); 720 } else { 721 p.ajax = false; 722 // Regular pager; all rows stored in memory 723 $(this).trigger("appendCache", true); 724 hideRowsSetup(table, p); 725 } 726 727 changeHeight(table, p); 728 729 // pager initialized 730 if (!p.ajax) { 731 p.initialized = true; 732 $(table).trigger('pagerInitialized', p); 733 } 734 }); 735 }; 736 737 }() 738 }); 739 // extend plugin scope 740 $.fn.extend({ 741 tablesorterPager: $.tablesorterPager.construct 742 }); 743 744 })(jQuery); -
extensions/UserAdvManager/branches/2.6/admin/template/uam.css
r18461 r26948 38 38 font-weight: bold; 39 39 color: yellow; 40 } 41 42 table.table2 { 43 border: 1px solid #111; 44 margin: 1em auto; 45 padding: 0; 46 width: 97%; 40 47 } 41 48 … … 85 92 86 93 /* jQuery tablesorter instructions */ 87 tr.throw 94 table.tablesorter tbody tr.normal-row td { 95 background: #111111; 96 color: #666666; 97 } 98 table.tablesorter tbody tr.alt-row td { 99 background: #222222; 100 color: #666666; 101 } 102 103 tr.tablesorter-headerRow, throw 88 104 { 89 105 cursor:pointer; … … 91 107 } 92 108 93 th. header109 th.tablesorter-header 94 110 { 95 111 background-image:url("./icon/bg.png"); … … 99 115 } 100 116 101 th. headerSortDown117 th.tablesorter-headerDesc 102 118 { 103 119 background-image:url("./icon/desc.png"); 104 120 } 105 121 106 th. headerSortUp122 th.tablesorter-headerAsc 107 123 { 108 124 background-image:url("./icon/asc.png"); 109 125 } 110 126 127 th.sorter-false { 128 background-image: none; 129 } 130 131 /* jQuery tablesorter pager instructions */ 111 132 .pager{ 112 133 text-align:center; 134 } 135 136 /* pager wrapper, div */ 137 .tablesorter-pager { 138 padding: 5px; 139 } 140 /* pager wrapper, in thead/tfoot */ 141 td.tablesorter-pager { 142 background-color: #e6eeee; 143 margin: 0; /* needed for bootstrap .pager gets a 18px bottom margin */ 144 } 145 /* pager navigation arrows */ 146 .tablesorter-pager img { 147 vertical-align: middle; 148 margin-right: 2px; 149 cursor: pointer; 113 150 } 114 151 … … 116 153 margin-bottom: -3px; 117 154 } 155 156 /* pager output text */ 157 .tablesorter-pager .pagedisplay { 158 padding: 0 5px 0 5px; 159 width: 50px; 160 text-align: center; 161 } 162 163 164 /* pager element reset (needed for bootstrap) */ 165 .tablesorter-pager select { 166 margin: 0; 167 padding: 0; 168 } 169 170 /*** css used when "updateArrows" option is true ***/ 171 /* the pager itself gets a disabled class when the number of rows is less than the size */ 172 .tablesorter-pager.disabled { 173 display: none; 174 } 175 /* hide or fade out pager arrows when the first or last row is visible */ 176 .tablesorter-pager .disabled { 177 /* visibility: hidden */ 178 opacity: 0.5; 179 filter: alpha(opacity=50); 180 cursor: default; 181 } -
extensions/UserAdvManager/branches/2.6/admin/template/userlist.tpl
r21747 r26948 2 2 {combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 3 3 {combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager. js'}4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 5 5 6 6 {combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} 7 7 8 8 9 <script type="text/javascript"> … … 21 22 .tablesorter( 22 23 {ldelim} 23 sortList:[[3, 1]],24 sortList:[[3,0]], 24 25 // pass the headers argument and assing a object 25 26 headers: 26 {ldelim} 27 // assign the fourth column (we start counting zero) 27 {ldelim} 28 // assign the second column (we start counting zero) 29 1: 30 {ldelim} 31 // disable it by setting the property sorter to false 32 sorter: false 33 {rdelim}, 34 // assign the fifth column (we start counting zero) 28 35 4: 29 36 {ldelim} 30 37 // disable it by setting the property sorter to false 31 sorter: false 38 sorter: false 32 39 {rdelim} 33 {rdelim} 40 {rdelim} 34 41 {rdelim}) 35 .tablesorterPager({ldelim}container: $("#pager"), p ositionFixed: false, size: 20, totalPages: 0{rdelim});42 .tablesorterPager({ldelim}container: $("#pager"), page: 0, size: 20, output: '{ldelim}page{rdelim} / {ldelim}totalPages{rdelim}'{rdelim}); 36 43 {rdelim} 37 44 ); … … 42 49 </div> 43 50 44 <form method="post" action=""class="general">51 <form method="post" class="general"> 45 52 <fieldset> 46 53 <legend class="cluetip" title="{'UAM_Tracking registered users'|translate}|{'UAM_userlistTitle_d'|translate}">{'UAM_Tracking registered users'|@translate}</legend> 47 54 {if count($users) > 0} 48 <table id="sorting" class="table2" width="97%" summary="">55 <table id="sorting" class="table2"> 49 56 <thead> 50 57 <tr class="throw"> … … 59 66 {foreach from=$users item=user name=users_loop} 60 67 <tr class="{if $smarty.foreach.users_loop.index is odd}row1{else}row2{/if}"> 61 <td><label for="selection-{$user.ID}">{$user.USERNAME}</label></td>62 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" /></a></td>68 <td><label>{$user.USERNAME}</label></td> 69 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" alt=""/></a></td> 63 70 <td>{$user.EMAIL}</td> 64 71 <td style="text-align:center;">{$user.LASTVISIT}</td> … … 80 87 </table> 81 88 <div id="pager" class="pager"> 82 <form> 83 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first"/> 84 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev"/> 89 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first" alt=""/> 90 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev" alt=""/> 85 91 <input type="text" class="pagedisplay"/> 86 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" />87 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" />88 <select class="pagesize" >92 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" alt=""/> 93 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" alt=""/> 94 <select class="pagesize" title="{'UAM_Select page size'|@translate}"> 89 95 <option value="10">10</option> 90 96 <option selected="selected" value="20">20</option> … … 92 98 <option value="40">40</option> 93 99 </select> 94 </form>100 <select class="gotoPage" title="{'UAM_Select page number'|@translate}"></select> 95 101 </div> 96 102 <br/> -
extensions/UserAdvManager/branches/2.6/admin/template/usermanager.tpl
r21747 r26948 2 2 {combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 3 3 {combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager. js'}4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 5 5 6 6 {combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} … … 16 16 {rdelim}); 17 17 18 $(document).ready(function() 18 $(document).ready(function() 19 19 {ldelim} 20 20 $("#sorting") 21 .tablesorter({ldelim}sortList:[[6, 1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim}{rdelim}{rdelim})22 .tablesorterPager({ldelim}container: $("#pager"), p ositionFixed: false, size: 20, totalPages: 0{rdelim});21 .tablesorter({ldelim}sortList:[[6,0]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim},2: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 22 .tablesorterPager({ldelim}container: $("#pager"), page: 0, size: 20, output: '{ldelim}page{rdelim} / {ldelim}totalPages{rdelim}',{rdelim}); 23 23 {rdelim} 24 24 ); … … 29 29 </div> 30 30 31 <form method="post" action="" class="general"> 31 <form method="post" class="general"> 32 {if count($users) > 0} 32 33 <fieldset> 33 34 <legend class="cluetip" title="{'UAM_Tracking confirmations'|translate}|{'UAM_usermanTitle_d'|translate}">{'UAM_Tracking confirmations'|@translate}</legend> 34 {if count($users) > 0} 35 <table id="sorting" class="table2" width="97%" summary=""> 35 <table id="sorting" class="table2"> 36 36 <thead> 37 37 <tr class="throw"> 38 <th> </t d>38 <th> </th> 39 39 <th>{'Username'|@translate} </th> 40 40 <th>{'Profile'|@translate} </th> … … 53 53 <td><input type="checkbox" name="selection[]" value="{$user.ID}" {$user.CHECKED} id="selection-{$user.ID}"/></td> 54 54 <td><label for="selection-{$user.ID}">{$user.USERNAME}</label></td> 55 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" /></a></td>55 <td style="text-align:center;"><a href="./admin.php?page=profile&user_id={$user.ID}" title="{'Profile'|@translate}" onclick="window.open(this.href); return false;"><img src="{$UAM_PATH}admin/template/icon/edit_s.png" alt=""/></a></td> 56 56 <td>{$user.STATUS}</td> 57 57 <td>{$user.EMAIL}</td> … … 70 70 {if !empty($users)} 71 71 <div id="pager" class="pager"> 72 <form> 73 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first"/> 74 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev"/> 72 <img src="{$UAM_PATH}admin/template/icon/first.png" class="first" alt=""/> 73 <img src="{$UAM_PATH}admin/template/icon/prev.png" class="prev" alt=""/> 75 74 <input type="text" class="pagedisplay"/> 76 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" />77 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" />78 <select class="pagesize" >75 <img src="{$UAM_PATH}admin/template/icon/next.png" class="next" alt=""/> 76 <img src="{$UAM_PATH}admin/template/icon/last.png" class="last" alt=""/> 77 <select class="pagesize" title="{'UAM_Select page size'|@translate}"> 79 78 <option value="10">10</option> 80 79 <option selected="selected" value="20">20</option> … … 82 81 <option value="40">40</option> 83 82 </select> 84 </form>83 <select class="gotoPage" title="{'UAM_Select page number'|@translate}"></select> 85 84 </div> 86 85 {/if} … … 107 106 </fieldset> 108 107 {else} 108 <fieldset> 109 <legend class="cluetip" title="{'UAM_Tracking confirmations'|translate}|{'UAM_usermanTitle_d'|translate}">{'UAM_Tracking confirmations'|@translate}</legend> 109 110 <div> 110 111 {'UAM_No_Usermanager'|@translate} 111 112 </div> 113 </fieldset> 112 114 {/if} 113 115 </form> -
extensions/UserAdvManager/branches/2.6/include/functions.inc.php
r26077 r26948 142 142 143 143 // -------------------------------------------------------------------------------------------------------------------- 144 // Workflow when admins have to validate registrations (CONFIRM_MAIL = local) 145 // No validation needed when admins add users if ADMINCONFMAIL is set to OFF - users are considered as valid by default 146 // Else a notification email with validation link is send to admins 147 // Finally when a user registers himself, a notification email with validation link is send to admins 144 // Workflow when admins have to validate registrations (CONFIRM_MAIL = local): 145 // 1- A confirmation email with validation link is send to users added by admins 146 // 2- Else no validation needed when admins add users if ADMINCONFMAIL is set to OFF - users are considered as valid by 147 // default and no information email is send to user from UAM (Piwigo will do that by checking the option box) 148 // 3- Finally when a user registers himself, a notification email with validation link is send to admins 148 149 // -------------------------------------------------------------------------------------------------------------------- 149 150 if (isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'local') 150 151 { 151 if (is_admin() and isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'true')152 if (is_admin() and (isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'true')) 152 153 { 153 154 SendMail2User(1, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], true); 154 155 } 155 elseif (is_admin() and isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'false')156 elseif (is_admin() and (isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'false')) 156 157 { 157 158 SetValidated($register_user['id']); 158 SendMail2User(1, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], false); 159 // Pending information email - Managed by Piwigo 160 //SendMail2User(2, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], false); 159 161 } 160 162 elseif (!is_admin()) … … 164 166 } 165 167 // -------------------------------------------------------------------------------------------------------------------- 166 // Workflow when users have to validate their registration (CONFIRM_MAIL = true) 167 // No validation needed when admins add users if ADMINCONFMAIL is set to OFF - users are considered as valid by default 168 // Else an email with validation link is send to user 169 // Finally when a user registers himself, an email with validation link is send to him 168 // Workflow when users have to validate their registration (CONFIRM_MAIL = true): 169 // 1- A confirmation email with validation link is send to users added by admins 170 // 2- ELse no validation needed when admins add users if ADMINCONFMAIL is set to OFF - users are considered as valid by 171 // default and no information email is send to user from UAM (Piwigo will do that by checking the option box) 172 // 3- Finally when a user registers himself, an email with validation link is send to him 170 173 // -------------------------------------------------------------------------------------------------------------------- 171 174 elseif (isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'true') 172 175 { 173 if (is_admin() and isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'true')176 if (is_admin() and (isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'true')) 174 177 { 175 178 SendMail2User(1, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], true); 176 179 } 177 elseif (is_admin() and isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'false')180 elseif (is_admin() and (isset($conf_UAM['ADMINCONFMAIL']) and $conf_UAM['ADMINCONFMAIL'] == 'false')) 178 181 { 179 182 SetValidated($register_user['id']); 180 SendMail2User(1, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], false); 183 // Pending information email - Managed by Piwigo 184 //SendMail2User(2, $register_user['id'], $register_user['username'], $passwd, $register_user['email'], false); 181 185 } 182 186 elseif (!is_admin()) … … 287 291 } 288 292 289 $typemail = 3; // Only information email send to user on user profile update if checked290 291 if (!empty($_POST['use_new_pwd']))292 {293 $typemail = 2; // Confirmation email on user profile update - With information email294 }295 296 293 // Sending registration confirmation by email 297 294 // ------------------------------------------ … … 310 307 list($current_email) = pwg_db_fetch_row(pwg_query($query)); 311 308 312 // This is to se nd a new validation key313 // ------------------------------------ 314 if ($_POST['mail_address'] != $current_email and (isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'true'))309 // This is to set the user to "waiting" group or status until validation 310 // --------------------------------------------------------------------- 311 if ($_POST['mail_address'] != $current_email and (isset($conf_UAM['CONFIRM_MAIL']) and ($conf_UAM['CONFIRM_MAIL'] == 'true' or $conf_UAM['CONFIRM_MAIL'] == 'local'))) 315 312 { 316 313 SetPermission($user['id']);// Set to "waiting" group or status until user validation … … 318 315 $confirm_mail_need = true; 319 316 } 320 321 // This is to set the user to "waiting" group or status until admin validation 322 // --------------------------------------------------------------------------- 323 elseif ($_POST['mail_address'] != $current_email and (isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'local')) 317 else 324 318 { 325 SetPermission($user['id']);// Set to "waiting" group or status until admin validation326 SetUnvalidated($user['id']); // Set UAM_validated field to false in #_users table327 319 $confirm_mail_need = false; 328 } 329 } 330 331 if (((!empty($_POST['use_new_pwd']) and (isset($conf_UAM['MAIL_INFO']) and $conf_UAM['MAIL_INFO'] == 'true')) or $confirm_mail_need)) 320 } 321 } 322 323 // Send information email 324 if ((isset($conf_UAM['MAIL_INFO']) and $conf_UAM['MAIL_INFO'] == 'true') or $confirm_mail_need) 332 325 { 333 326 $query = ' … … 338 331 339 332 list($username) = pwg_db_fetch_row(pwg_query($query)); 340 SendMail2User($typemail, $user['id'], $username, $_POST['use_new_pwd'], $_POST['mail_address'], $confirm_mail_need); 333 334 SendMail2User(2, $user['id'], $username, $_POST['use_new_pwd'], $_POST['mail_address'], $confirm_mail_need); 341 335 } 342 336 } … … 1109 1103 break; 1110 1104 1111 case 2: // Confirmation email on user profile update - With information email if modification done in user profile1112 if (isset($conf_UAM[' CONFIRMMAIL_SUBJECT']) and !empty($conf_UAM['CONFIRMMAIL_SUBJECT']))1105 case 2: // Confirmation email on user profile update - Information email if modification done in user profile 1106 if (isset($conf_UAM['INFOMAIL_SUBJECT']) and !empty($conf_UAM['INFOMAIL_SUBJECT'])) 1113 1107 { 1114 1108 // Management of Extension flags ([username], [mygallery]) … … 1121 1115 if (function_exists('get_user_language_desc')) 1122 1116 { 1123 $subject = get_user_language_desc(preg_replace($patterns, $replacements, $conf_UAM[' CONFIRMMAIL_SUBJECT']))."\n\n";1117 $subject = get_user_language_desc(preg_replace($patterns, $replacements, $conf_UAM['INFOMAIL_SUBJECT']))."\n\n"; 1124 1118 } 1125 else $subject = l10n(preg_replace($patterns, $replacements, $conf_UAM[' CONFIRMMAIL_SUBJECT']))."\n\n";1126 } 1127 1128 $password = !empty($password) ? $password : l10n('UAM_ empty_pwd');1119 else $subject = l10n(preg_replace($patterns, $replacements, $conf_UAM['INFOMAIL_SUBJECT']))."\n\n"; 1120 } 1121 1122 $password = !empty($password) ? $password : l10n('UAM_no_update_pwd'); 1129 1123 1130 1124 if (isset($conf_UAM['MAILINFO_TEXT']) and !empty($conf_UAM['MAILINFO_TEXT'])) … … 1170 1164 1171 1165 break; 1172 1173 case 3: // Only information email send to user if checked1174 if (isset($conf_UAM['INFOMAIL_SUBJECT']) and !empty($conf_UAM['INFOMAIL_SUBJECT']))1175 {1176 // Management of Extension flags ([username], [mygallery])1177 // -------------------------------------------------------1178 $patterns[] = '#\[username\]#i';1179 $replacements[] = $username;1180 $patterns[] = '#\[mygallery\]#i';1181 $replacements[] = $conf['gallery_title'];1182 1183 if (function_exists('get_user_language_desc'))1184 {1185 $subject = get_user_language_desc(preg_replace($patterns, $replacements, $conf_UAM['INFOMAIL_SUBJECT']))."\n\n";1186 }1187 else $subject = l10n(preg_replace($patterns, $replacements, $conf_UAM['INFOMAIL_SUBJECT']))."\n\n";1188 }1189 1190 $password = !empty($password) ? $password : l10n('UAM_no_update_pwd');1191 1192 if (isset($conf_UAM['MAILINFO_TEXT']) and !empty($conf_UAM['MAILINFO_TEXT']))1193 {1194 // Management of Extension flags ([username], [mygallery], [myurl])1195 // ----------------------------------------------------------------1196 $patterns[] = '#\[username\]#i';1197 $replacements[] = $username;1198 $patterns[] = '#\[mygallery\]#i';1199 $replacements[] = $conf['gallery_title'];1200 $patterns[] = '#\[myurl\]#i';1201 $replacements[] = get_gallery_home_url();1202 1203 if (function_exists('get_user_language_desc'))1204 {1205 $infos1_perso = get_user_language_desc(preg_replace($patterns, $replacements, $conf_UAM['MAILINFO_TEXT']))."\n\n";1206 }1207 else $infos1_perso = l10n(preg_replace($patterns, $replacements, $conf_UAM['MAILINFO_TEXT']))."\n\n";1208 }1209 1210 if (isset($conf_UAM['MAIL_INFO']) and $conf_UAM['MAIL_INFO'] == 'true')1211 {1212 if (isset($conf_UAM['HIDEPASSW']) and $conf_UAM['HIDEPASSW'] == 'true') // Allow display of clear password in email1213 {1214 $infos1 = array(1215 get_l10n_args('UAM_infos_mail %s', stripslashes($username)),1216 get_l10n_args('UAM_User: %s', stripslashes($username)),1217 get_l10n_args('UAM_Password: %s', $password),1218 get_l10n_args('Email: %s', $email),1219 get_l10n_args('', ''),1220 );1221 }1222 else // Do not allow display of clear password in email1223 {1224 $infos1 = array(1225 get_l10n_args('UAM_infos_mail %s', stripslashes($username)),1226 get_l10n_args('UAM_User: %s', stripslashes($username)),1227 get_l10n_args('Email: %s', $email),1228 get_l10n_args('', ''),1229 );1230 }1231 }1232 1233 break;1234 1166 } 1235 1167 … … 1266 1198 } 1267 1199 1200 // $converted_res = ($confirm) ? 'true' : 'false'; 1201 // UAMLog($typemail,$converted_res,$conf_UAM['CONFIRM_MAIL'],$subject); 1202 1268 1203 // Sending the email with subject and contents 1269 1204 // ------------------------------------------- 1270 if ((isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'local') and $confirm) 1271 { 1205 1206 if ((isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'local') and $confirm) // Confirmation email send to admins 1207 { 1272 1208 switch_lang_to(get_default_language()); 1273 1209 1274 1275 $subject= get_l10n_args('UAM_Subject admin validation for %s',$username);1276 1277 $content= array(1278 1279 get_l10n_args('', ''),1280 get_l10n_args('UAM_Link: %s', AddConfirmMail($id, $email)),1210 load_language('plugin.lang', UAM_PATH); 1211 $subject_admin = get_l10n_args('UAM_Subject admin validation for %s',$username); 1212 1213 $content_admin = array( 1214 get_l10n_args('UAM_Manual_validation_needed_for %s', stripslashes($username)), 1215 get_l10n_args('', ''), 1216 get_l10n_args('UAM_Link: %s', AddConfirmMail($id, $email)), 1281 1217 ); 1282 1218 1283 //UAM_mail_notification_admins($subject, $content); 1284 pwg_mail_notification_admins($subject, $content, true); 1285 } 1286 elseif ((isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'true') and $confirm) 1219 pwg_mail_notification_admins($subject_admin, $content_admin, true); 1220 } 1221 1222 1223 if ((isset($conf_UAM['CONFIRM_MAIL']) and $conf_UAM['CONFIRM_MAIL'] == 'true') and $confirm) // Confirmation email send to users 1287 1224 { 1288 1225 // Adding gallery URL at the end of the email 1289 1226 if (isset($conf_UAM['ADD_GALLERY_URL_TO_EMAILS']) and $conf_UAM['ADD_GALLERY_URL_TO_EMAILS'] == 'true') 1290 1227 { 1291 $content = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : "").get_absolute_root_url();1228 $content_confirmation = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : "").get_absolute_root_url(); 1292 1229 1293 1230 pwg_mail( … … 1297 1234 ), 1298 1235 array( 1299 'content' => $content ,1236 'content' => $content_confirmation, 1300 1237 'content_format' => 'text/plain', 1301 1238 'subject' => $subject, … … 1306 1243 elseif (isset($conf_UAM['ADD_GALLERY_URL_TO_EMAILS']) and $conf_UAM['ADD_GALLERY_URL_TO_EMAILS'] == 'false') 1307 1244 { 1308 $content = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : "");1245 $content_confirmation = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : ""); 1309 1246 1310 1247 pwg_mail( … … 1314 1251 ), 1315 1252 array( 1316 'content' => $content ,1253 'content' => $content_confirmation, 1317 1254 'content_format' => 'text/plain', 1318 1255 'subject' => $subject, … … 1323 1260 else 1324 1261 { 1325 $content = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : "");1262 $content_confirmation = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : ""); 1326 1263 1327 1264 pwg_mail( … … 1331 1268 ), 1332 1269 array( 1333 'content' => $content, 1270 'content' => $content_confirmation, 1271 'content_format' => 'text/plain', 1272 'subject' => $subject, 1273 ) 1274 ); 1275 } 1276 } 1277 1278 1279 if ((isset($conf_UAM['MAIL_INFO']) and $conf_UAM['MAIL_INFO'] == 'true') and $typemail <> 1) // Information email send to users 1280 { 1281 // Adding gallery URL at the end of the email 1282 if (isset($conf_UAM['ADD_GALLERY_URL_TO_EMAILS']) and $conf_UAM['ADD_GALLERY_URL_TO_EMAILS'] == 'true') 1283 { 1284 $content_info = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : "").get_absolute_root_url(); 1285 1286 pwg_mail( 1287 array( 1288 'name' => stripslashes($username), 1289 'email' => $email, 1290 ), 1291 array( 1292 'content' => $content_info, 1293 'content_format' => 'text/plain', 1294 'subject' => $subject, 1295 ) 1296 ); 1297 } 1298 // Do not add gallery URL at the end of the email 1299 elseif (isset($conf_UAM['ADD_GALLERY_URL_TO_EMAILS']) and $conf_UAM['ADD_GALLERY_URL_TO_EMAILS'] == 'false') 1300 { 1301 $content_info = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : ""); 1302 1303 pwg_mail( 1304 array( 1305 'name' => stripslashes($username), 1306 'email' => $email, 1307 ), 1308 array( 1309 'content' => $content_info, 1310 'content_format' => 'text/plain', 1311 'subject' => $subject, 1312 ) 1313 ); 1314 } 1315 // By default do not add gallery URL at the end of the email 1316 else 1317 { 1318 $content_info = (isset($infos1) ? $infos1_perso.l10n_args($infos1)."\n\n" : "").(isset($infos2) ? $infos2_perso.l10n_args($infos2)."\n\n" : ""); 1319 1320 pwg_mail( 1321 array( 1322 'name' => stripslashes($username), 1323 'email' => $email, 1324 ), 1325 array( 1326 'content' => $content_info, 1334 1327 'content_format' => 'text/plain', 1335 1328 'subject' => $subject, -
extensions/UserAdvManager/branches/2.6/language/en_UK/plugin.lang.php
r25101 r26948 268 268 Goals: Inform the visitor that the registration is awaiting approval by displaying a personal block on the home page of the gallery, and this, as registration is not approved. 269 269 <br/><br/> 270 <b>Recall: In standard operation, the "Guest" only sees the public categories, without information message.</b> 271 </li><br/><br/> 272 <li> 273 Prerequisite:<br/> 274 - A gallery with all or some private categories, visible only by registered users<br/> 275 - At least 2 following Piwigo\'s users groups: "Waiting," without permission on private categories, and "Confirmed" with all the permissions on the private categories<br/> 276 - UAM plugin<br/> 277 - PWG Stuffs plugin, for adding a special UAM module<br/> 278 - Optionally, the plugin Extended Description to support multi-languages<br/> 279 </li><br/><br/> 280 <li> 281 Stages:<br/><br/> 270 <b>Recall: In standard operation, the "Guest" only sees the public albums, without information message.</b> 271 </li> 272 <li style="list-style-type: none;"><br/></li> 273 <li> 274 Prerequisite: 275 <li style="list-style-type: none;"></li> 276 <li style="list-style-type: none;">- A gallery with all or some private albums, visible only by registered users</li> 277 <li style="list-style-type: none;">- At least 2 following Piwigo\'s users groups: "Waiting," without permission on private albums, and "Confirmed" with all the permissions on the private albums</li> 278 <li style="list-style-type: none;">- UAM plugin</li> 279 <li style="list-style-type: none;">- PWG Stuffs plugin, for adding a special UAM module</li> 280 <li style="list-style-type: none;">- Optionally, the plugin Extended Description to support multi-languages</li> 281 </li> 282 <li style="list-style-type: none;"><br/></li> 283 <li> 284 Stages: 285 <li style="list-style-type: none;"></li> 282 286 A. In plugin UAM: 283 287 <ol> … … 289 293 <li>Save the plugin configuration</li> 290 294 </ol> 291 < br/>295 <li style="list-style-type: none;"><br/></li> 292 296 B. In plugin PWG Stuffs : 293 297 <ol> … … 306 310 <li> 307 311 Goals: Inform the visitor that the registration is awaiting confirmation by posting an additional page replacing the standard index page gallery at each of these connections, and this, as registration is not approved. 308 < br/><br/>312 <li style="list-style-type: none;"></li> 309 313 Advantages over the method with PWG_Stuffs: Allow formatting information and displaying the information immediately upon registration of visitors. 310 </li><br/><br/> 311 <li> 312 Prerequisite:<br/> 313 - A gallery with all or some private categories, visible only by registered users<br/> 314 - At least 2 following Piwigo\'s users groups: "Waiting," without permission on private categories, and "Confirmed" with all the permissions on the private categories<br/> 315 - UAM plugin<br/> 316 - Additional Pages plugin for adding and managing an additional page to replace the default index page of the gallery<br/> 317 - Optionally, the plugin Extended Description to support multi-languages<br/> 318 </li><br/><br/> 319 <li> 320 Stages:<br/><br/> 314 </li> 315 <li style="list-style-type: none;"><br/></li> 316 <li> 317 Prerequisite: 318 <li style="list-style-type: none;"></li> 319 <li style="list-style-type: none;">- A gallery with all or some private albums, visible only by registered users</li> 320 <li style="list-style-type: none;">- At least 2 following Piwigo\'s users groups: "Waiting," without permission on private albums, and "Confirmed" with all the permissions on the private albums</li> 321 <li style="list-style-type: none;">- UAM plugin</li> 322 <li style="list-style-type: none;">- Additional Pages plugin for adding and managing an additional page to replace the default index page of the gallery</li> 323 <li style="list-style-type: none;">- Optionally, the plugin Extended Description to support multi-languages</li> 324 </li> 325 <li style="list-style-type: none;"><br/></li> 326 <li> 327 Stages: 328 <li style="list-style-type: none;"></li> 321 329 A. In plugin UAM: 322 330 <ol> … … 327 335 <li>Save the plugin configuration</li> 328 336 </ol> 329 <br/> 330 B. In plugin Additional Pages:<br/> 337 <li style="list-style-type: none;"><br/></li> 338 B. In plugin Additional Pages: 339 <li style="list-style-type: none;"></li> 331 340 <b>NOTE : The management of access rights for groups on Additional Pages must be turned on (see plugin configuration settings).</b> 332 < br/>341 <li style="list-style-type: none;"></li> 333 342 <ol> 334 343 <li>Add a new page with at least the following parameters:</li> … … 403 412 $lang['UAM_AddURL2Mail'] = 'Add the URL of the gallery at the end of emails (like a signature)'; 404 413 $lang['UAM_Follow this link to access the gallery'] = 'Please, follow this link to access the gallery'; 414 415 $lang['UAM_Select page size'] = 'Select page size'; 416 $lang['UAM_Select page number'] = 'Select page number'; 405 417 ?> -
extensions/UserAdvManager/branches/2.6/language/fr_FR/plugin.lang.php
r25101 r26948 105 105 $lang['UAM_GT_Init'] = 'Initialisation du Ghost Tracker'; 106 106 $lang['UAM_GhostTracker_Title'] = 'Gestion des visiteurs fantômes'; 107 $lang['UAM_GhostTracker_Init'] = 'A première activation de cette fonction, ou à sa réactivation après une longue période pendant laquelle de nouveaux visiteurs se sont inscrits, il convient d\'initialiser ou de réinitialiser le Ghost Tracker. Cette action n\'est à faire qu\'une seule fois après activation ou réactivation de l\'option; à cet effet, cliquez <u>une seule fois</u> sur le bouton d\'initialisation ci-dessous.</b>';107 $lang['UAM_GhostTracker_Init'] = 'A la première activation de cette fonction, ou à sa réactivation après une longue période pendant laquelle de nouveaux visiteurs se sont inscrits, il convient d\'initialiser ou de réinitialiser le Ghost Tracker. Cette action n\'est à faire qu\'une seule fois après activation ou réactivation de l\'option; à cet effet, cliquez <u>une seule fois</u> sur le bouton d\'initialisation ci-dessous.'; 108 108 /* Mailing */ 109 109 $lang['UAM_Add of %s'] = 'Profil créé pour %s'; … … 262 262 <br/><br/> 263 263 Avantages par rapport à la méthode avec PWG_Stuffs : Permettre une information mise en forme et moins austère et afficher immédiatement l\'information dès l\'inscription des visiteurs. 264 </li><br/><br/> 265 <li> 266 Pré-requis:<br/> 267 - Une galerie avec tout ou partie des catégories privées, visibles par les seuls utilisateurs inscrits<br/> 268 - Au moins les 2 groupes d\'utilisateurs Piwigo suivants : "Attente", sans aucune permission sur les catégories privées, et "Confirmés", avec toutes les permissions sur les catégories privées<br/> 269 - Le plugin UAM<br/> 270 - Le plugin Additional Pages, pour l\'ajout et la gestion d\'une page additionnelle remplaçant la page d\'index par défaut de la galerie<br/> 271 - En option, le plugin Extended Description, pour le support multi-langues<br/> 272 </li><br/><br/> 273 <li> 274 Réalisation:<br/><br/> 275 A. Dans le plugin UAM:<br/> 264 </li> 265 <li style="list-style-type: none;"><br/></li> 266 <li> 267 Pré-requis: 268 <li style="list-style-type: none;"></li> 269 <li style="list-style-type: none;">- Une galerie avec tout ou partie des albums privées, visibles par les seuls utilisateurs inscrits</li> 270 <li style="list-style-type: none;">- Au moins les 2 groupes d\'utilisateurs Piwigo suivants : "Attente", sans aucune permission sur les albums privées, et "Confirmés", avec toutes les permissions sur les albums privées</li> 271 <li style="list-style-type: none;">- Le plugin UAM</li> 272 <li style="list-style-type: none;">- Le plugin Additional Pages, pour l\'ajout et la gestion d\'une page additionnelle remplaçant la page d\'index par défaut de la galerie</li> 273 <li style="list-style-type: none;">- En option, le plugin Extended Description, pour le support multi-langues</li> 274 </li> 275 <li style="list-style-type: none;"><br/></li> 276 <li> 277 Réalisation: 278 <li style="list-style-type: none;"></li> 279 A. Dans le plugin UAM: 280 <li style="list-style-type: none;"></li> 276 281 <ol> 277 282 <li>Activer la confirmation d\'inscription</li> … … 281 286 <li>Enregistrer la configuration du plugin</li> 282 287 </ol> 283 <br/> 284 B. Dans le plugin Additional Pages:<br/> 288 <li style="list-style-type: none;"><br/></li> 289 B. Dans le plugin Additional Pages: 290 <li style="list-style-type: none;"></li> 285 291 <b>NOTE : La gestion des droits d\'accès aux pages additionelles pour les groupes doit être activée (voir configuration du plugin Additional Pages).</b> 286 292 <br/> … … 312 318 <li> 313 319 Objectifs : Informer le visiteur que son inscription est en attente de confirmation en affichant un bloc personnel sur la page d\'accueil de la galerie; et ce, tant que l\'inscription n\'est pas confirmée.<br/><br/> 314 <b>Rappel: En fonctionnement standard, le "Guest" ne voit que les catégories publiques, sans message d\'information.</b> 315 </li><br/><br/> 316 <li> 317 Pré-requis:<br/> 318 - Une galerie avec tout ou partie des catégories privées, visibles par les seuls utilisateurs inscrits<br/> 319 - Au moins les 2 groupes d\'utilisateurs Piwigo suivants : "Attente", sans aucune permission sur les catégories privées, et "Confirmés", avec toutes les permissions sur les catégories privées<br/> 320 - Le plugin UAM<br/> 321 - Le plugin PWG Stuffs, pour l\'ajout d\'un module spécial UAM<br/> 322 - En option, le plugin Extended Description, pour le support multi-langues<br/> 323 </li><br/><br/> 324 <li> 325 Réalisation:<br/><br/> 326 A. Dans le plugin UAM:<br/> 320 <b>Rappel: En fonctionnement standard, le "Guest" ne voit que les albums publics, sans message d\'information.</b> 321 </li> 322 <li style="list-style-type: none;"><br/></li> 323 <li> 324 Pré-requis: 325 <li style="list-style-type: none;"></li> 326 <li style="list-style-type: none;">- Une galerie avec tout ou partie des albums privées, visibles par les seuls utilisateurs inscrits</li> 327 <li style="list-style-type: none;">- Au moins les 2 groupes d\'utilisateurs Piwigo suivants : "Attente", sans aucune permission sur les albums privées, et "Confirmés", avec toutes les permissions sur les albums privées</li> 328 <li style="list-style-type: none;">- Le plugin UAM</li> 329 <li style="list-style-type: none;">- Le plugin PWG Stuffs, pour l\'ajout d\'un module spécial UAM</li> 330 <li style="list-style-type: none;">- En option, le plugin Extended Description, pour le support multi-langues</li> 331 </li> 332 <li style="list-style-type: none;"><br/></li> 333 <li> 334 Réalisation: 335 <li style="list-style-type: none;"></li> 336 A. Dans le plugin UAM: 337 <li style="list-style-type: none;"></li> 327 338 <ol> 328 339 <li>Activer la confirmation d\'inscription</li> … … 333 344 <li>Enregistrer la configuration du plugin</li> 334 345 </ol> 335 <br/> 336 B. Dans le plugin PWG Stuffs:<br/> 346 <li style="list-style-type: none;"><br/></li> 347 B. Dans le plugin PWG Stuffs: 348 <li style="list-style-type: none;"></li> 337 349 <ol> 338 350 <li>Aller dans l\'onglet "Ajouter un nouveau bloc"</li> … … 403 415 $lang['UAM_AddURL2Mail'] = 'Ajouter l\'URL de la galerie à la fin des emails (comme une signature)'; 404 416 $lang['UAM_Follow this link to access the gallery'] = 'Veuillez utiliser ce lien pour vous connecter'; 417 418 $lang['UAM_Select page size'] = 'Choisir la taille des pages'; 419 $lang['UAM_Select page number'] = 'Sélectionner une page'; 405 420 ?> -
extensions/UserAdvManager/branches/2.6/language/pt_BR/help.lang.php
r25664 r26948 77 77 <br/><br/> 78 78 Se esta opção e a opção "Lembrar os usuários não confirmados" são ativadas, novas opções aparecem em baixo nesta seção para permitir a automação de gestão de usuários não confirmados.'; 79 $lang['UAM_miscTitle_d'] = '- Usuários registrados monitoramento <br/> 80 - Apelido obrigatório para comentário de visitantes <br/> 81 ...'; 82 $lang['UAM_infomailTitle_d'] = 'Esta opção permite automatizar o envio de um e-mail de informações de um usuário quando ele muda de senha ou endereço de e-mail em sua página de perfil. <br/><bb/> 83 O conteúdo da mensagem enviada é composta por uma parte customizável a introduzir uma pequena nota de boas-vindas e uma parte fixa, indicando o nome de login, senha e endereço de e-mail do usuário.'; 84 $lang['UAM_confirmstatTitle'] = 'Estatutos'; 85 $lang['UAM_confirmTitle_d'] = '- Informações geração email <br/> 86 - Registrar confirmação geração email <br/> 87 - Grupos, estado ou nível de privacidade auto registro <br/> 88 - Prazo para a confirmação do registro <br/> 89 - Geração email Lembrete 90 ...'; 91 $lang['UAM_USRAutoMailTitle_d'] = 'Quando ativada, esta função irá enviar automaticamente conteúdo personalizado em "Lembrete de e-mail com uma nova chave gerada" aos visitantes que correspondem aos critérios.'; 92 $lang['UAM_Tracking registered users_d'] = 'Isso ativa uma tabela na guia "de rastreamento de usuários registrados", onde são listados os utilizadores registados na galeria com a data de sua última visita e tempo gasto (em dias) desde a sua última visita. O monitoramento é puramente informativo para o administrador da galeria.'; 93 $lang['UAM_StuffsTitle_d'] = 'Isso permite que um bloco UAM adicional no PWG Stuffs plugin (se instalado), informar os visitantes que não confirmaram sua inscrição sobre suas condição. 94 <br/><br/> 95 Consulte <b>Dicas e Exemplos de Uso</b> na parte inferior desta página para mais detalhes.'; 96 $lang['UAM_HidePasswTitle_d'] = 'Escolha esta opção se você deseja exibir a senha escolhida pelo visitante no e-mail informações. Se você ativar a opção, a senha irá aparecer em texto claro. Se você desativar a senha não vai aparecer.'; 79 97 ?> -
extensions/UserAdvManager/branches/2.6/language/pt_PT/description.txt
r24203 r26948 1 Reforço das possibilidades de gerenciamento de utilizadores1 Reforço das capacidades de gestão de utilizadores -
extensions/UserAdvManager/branches/2.6/language/pt_PT/help.lang.php
r25809 r26948 317 317 $lang['UAM_infomailTitle_d'] = 'Esta opção permite automatizar o envio de um e-mail informação para um utilizador quando ele altera a senha ou endereço de e-mail no seu perfil. <br/> 318 318 O conteúdo da mensagem a enviar é composto por uma parte personalizável para introduzir uma pequena nota de boas-vindas e uma parte fixa, indicando o nome de login, senha e endereço de e-mail do utilizador.'; 319 $lang['UAM_confirmstatTitle_d'] = '<b style="color: red;">AVISO : A utilização de estatutos na confirmação requer que tenha mantido o estatuto "Guest (Visitante)" como o estatuto por defeito (no modelo de utilizador) para os novos registos. Note que também pode definir outro tipo de utilizador como defeito. Por favor reveja a documentação do Piwigo para mais detalhes.</b><br/><br/> 320 Os estatutos são validados para utilização conjunta com a "Confirmação de registo"'; 321 $lang['UAM_confirmlevelTitle_d'] = '<b style="color: red;">AVISO : A utilização do nível de privacidade requere que já o tenha utilizado com as suas imagens. Por favor reveja a documentação do Piwigo para mais detalhes.</b><br/><br/> 322 O nível de privacidade é validado para utilização conjunta com a "Confirmação de registo"'; 323 $lang['UAM_confirmgrpTitle_d'] = '<b style="color: red;">AVISO : A utilização de grupos na confirmação requer que tenha criado pelo menos um grupo de utilizadores e que este esteja definido como grupo "por defeito" na gestão de grupos de utilizadores do Piwigo.</b><br/><br/> 324 os grupos são validados para utilização conjunta com a "Confirmação de registo" 325 '; 326 $lang['UAM_carexcTitle_d'] = 'Pode ser interessante a proibição da utilização de certos caracteres nos nomes de utilizador (exemplo: recusar nomes de login que contenham @). Esta opção permite excluir caracteres ou sequências de caracteres.<br/> 327 NB: A opção pode também excluir palavras inteiras 328 <br/><br/> 329 <b style="color: red;">Aviso: esta opção não tem efeito sobre os nomes de utilizador criados à ativação da mesma.</b>'; 319 330 ?>
Note: See TracChangeset
for help on using the changeset viewer.