Fossil SCM
Improvements to skin administration. The /setup_skin_admin page allows the admin to set the default-skin setting to select which skin to use, and to clear out the custom skin.
Commit
f3702b86c3d75fb501a88adf406dc2a1c42a5bbd2e49c7a8b0fedc74edb40d18
Parent
18d76fffb1c99ff…
1 file changed
+127
-79
+127
-79
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -559,10 +559,20 @@ | ||
| 559 | 559 | ); |
| 560 | 560 | db_protect_pop(); |
| 561 | 561 | return 0; |
| 562 | 562 | } |
| 563 | 563 | |
| 564 | +/* | |
| 565 | +** Return true if a custom skin exists | |
| 566 | +*/ | |
| 567 | +static int skin_exists_custom(void){ | |
| 568 | + return db_exists("SELECT 1 FROM config WHERE name IN" | |
| 569 | + " ('css','details','footer','header','js')"); | |
| 570 | +} | |
| 571 | + | |
| 572 | +static void skin_publish(int); /* Forward reference */ | |
| 573 | + | |
| 564 | 574 | /* |
| 565 | 575 | ** WEBPAGE: setup_skin_admin |
| 566 | 576 | ** |
| 567 | 577 | ** Administrative actions on skins. For administrators only. |
| 568 | 578 | */ |
| @@ -571,14 +581,15 @@ | ||
| 571 | 581 | char *zName; |
| 572 | 582 | char *zErr = 0; |
| 573 | 583 | const char *zCurrent = 0; /* Current skin */ |
| 574 | 584 | int i; /* Loop counter */ |
| 575 | 585 | Stmt q; |
| 576 | - int seenCurrent = 0; | |
| 577 | 586 | int once; |
| 578 | - const char *zInstalled = 0; | |
| 579 | 587 | const char *zOverride = 0; |
| 588 | + const char *zDfltSkin = 0; | |
| 589 | + int seenDefault = 0; | |
| 590 | + int hasCustom; | |
| 580 | 591 | |
| 581 | 592 | login_check_credentials(); |
| 582 | 593 | if( !g.perm.Admin ){ |
| 583 | 594 | login_needed(0); |
| 584 | 595 | return; |
| @@ -591,11 +602,11 @@ | ||
| 591 | 602 | |
| 592 | 603 | style_set_current_feature("skins"); |
| 593 | 604 | |
| 594 | 605 | if( cgi_csrf_safe(2) ){ |
| 595 | 606 | /* Process requests to delete a user-defined skin */ |
| 596 | - if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){ | |
| 607 | + if( P("del1") && P("sn")!=0 ){ | |
| 597 | 608 | style_header("Confirm Custom Skin Delete"); |
| 598 | 609 | @ <form action="%R/setup_skin_admin" method="post"><div> |
| 599 | 610 | @ <p>Deletion of a custom skin is a permanent action that cannot |
| 600 | 611 | @ be undone. Please confirm that this is what you want to do:</p> |
| 601 | 612 | @ <input type="hidden" name="sn" value="%h(P("sn"))"> |
| @@ -605,13 +616,18 @@ | ||
| 605 | 616 | @ </div></form> |
| 606 | 617 | style_finish_page(); |
| 607 | 618 | db_end_transaction(1); |
| 608 | 619 | return; |
| 609 | 620 | } |
| 610 | - if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ | |
| 621 | + if( P("del2")!=0 ){ | |
| 611 | 622 | db_unprotect(PROTECT_CONFIG); |
| 612 | - db_multi_exec("DELETE FROM config WHERE name=%Q", zName); | |
| 623 | + if( fossil_strcmp(P("sn"),"custom")==0 ){ | |
| 624 | + db_multi_exec("DELETE FROM config WHERE name IN" | |
| 625 | + "('css','details','footer','header','js')"); | |
| 626 | + }else if( (zName = skinVarName(P("sn"), 1))!=0 ){ | |
| 627 | + db_multi_exec("DELETE FROM config WHERE name=%Q", zName); | |
| 628 | + } | |
| 613 | 629 | db_protect_pop(); |
| 614 | 630 | } |
| 615 | 631 | if( P("draftdel")!=0 ){ |
| 616 | 632 | const char *zDraft = P("name"); |
| 617 | 633 | if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ |
| @@ -627,39 +643,57 @@ | ||
| 627 | 643 | } |
| 628 | 644 | if( skinRename() || skinSave(zCurrent) ){ |
| 629 | 645 | db_end_transaction(0); |
| 630 | 646 | return; |
| 631 | 647 | } |
| 648 | + | |
| 649 | + if( P("setdflt") && (z = P("bisl"))!=0 ){ | |
| 650 | + if( z[0] ){ | |
| 651 | + db_set("default-skin", z, 0); | |
| 652 | + }else{ | |
| 653 | + db_unset("default-skin", 0); | |
| 654 | + } | |
| 655 | + db_end_transaction(0); | |
| 656 | + cgi_redirectf("%R/setup_skin_admin"); | |
| 657 | + return; | |
| 658 | + } | |
| 632 | 659 | |
| 633 | 660 | /* The user pressed one of the "Install" buttons. */ |
| 634 | 661 | if( P("load") && (z = P("sn"))!=0 && z[0] ){ |
| 635 | 662 | int seen = 0; |
| 636 | 663 | |
| 637 | 664 | /* Check to see if the current skin is already saved. If it is, there |
| 638 | 665 | ** is no need to create a backup */ |
| 639 | - zCurrent = getSkin(0); | |
| 640 | - for(i=0; i<count(aBuiltinSkin); i++){ | |
| 641 | - if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ | |
| 642 | - seen = 1; | |
| 643 | - break; | |
| 644 | - } | |
| 645 | - } | |
| 646 | - if( !seen ){ | |
| 647 | - seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" | |
| 648 | - " AND value=%Q", zCurrent); | |
| 649 | - if( !seen ){ | |
| 650 | - db_unprotect(PROTECT_CONFIG); | |
| 651 | - db_multi_exec( | |
| 652 | - "INSERT INTO config(name,value,mtime) VALUES(" | |
| 653 | - " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," | |
| 654 | - " %Q,now())", zCurrent | |
| 655 | - ); | |
| 656 | - db_protect_pop(); | |
| 666 | + hasCustom = skin_exists_custom(); | |
| 667 | + if( hasCustom ){ | |
| 668 | + zCurrent = getSkin(0); | |
| 669 | + for(i=0; i<count(aBuiltinSkin); i++){ | |
| 670 | + if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ | |
| 671 | + seen = 1; | |
| 672 | + break; | |
| 673 | + } | |
| 674 | + } | |
| 675 | + if( !seen ){ | |
| 676 | + seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" | |
| 677 | + " AND value=%Q", zCurrent); | |
| 678 | + if( !seen ){ | |
| 679 | + db_unprotect(PROTECT_CONFIG); | |
| 680 | + db_multi_exec( | |
| 681 | + "INSERT INTO config(name,value,mtime) VALUES(" | |
| 682 | + " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," | |
| 683 | + " %Q,now())", zCurrent | |
| 684 | + ); | |
| 685 | + db_protect_pop(); | |
| 686 | + } | |
| 657 | 687 | } |
| 658 | 688 | } |
| 659 | 689 | seen = 0; |
| 660 | - for(i=0; i<count(aBuiltinSkin); i++){ | |
| 690 | + if( z[0]>='1' && z[0]<='9' && z[1]==0 ){ | |
| 691 | + skin_publish(z[0]-'0'); | |
| 692 | + seen = 1; | |
| 693 | + } | |
| 694 | + for(i=0; seen==0 && i<count(aBuiltinSkin); i++){ | |
| 661 | 695 | if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ |
| 662 | 696 | seen = 1; |
| 663 | 697 | zCurrent = aBuiltinSkin[i].zSQL; |
| 664 | 698 | db_unprotect(PROTECT_CONFIG); |
| 665 | 699 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| @@ -674,36 +708,40 @@ | ||
| 674 | 708 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| 675 | 709 | db_protect_pop(); |
| 676 | 710 | } |
| 677 | 711 | } |
| 678 | 712 | } |
| 713 | + | |
| 714 | + zDfltSkin = db_get("default-skin",0); | |
| 715 | + hasCustom = skin_exists_custom(); | |
| 716 | + if( !hasCustom && zDfltSkin==0 ){ | |
| 717 | + zDfltSkin = "default"; | |
| 718 | + } | |
| 679 | 719 | |
| 680 | 720 | style_header("Skins"); |
| 681 | 721 | if( zErr ){ |
| 682 | 722 | @ <p style="color:red">%h(zErr)</p> |
| 683 | 723 | } |
| 684 | 724 | @ <table border="0"> |
| 685 | - @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></th> | |
| 725 | + @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></tr> | |
| 686 | 726 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 687 | 727 | z = aBuiltinSkin[i].zDesc; |
| 688 | 728 | @ <tr><td>%d(i+1).<td>%h(z)<td> <td> |
| 689 | - if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ | |
| 690 | - @ (Installed) | |
| 691 | - zInstalled = z; | |
| 692 | - seenCurrent = 1; | |
| 729 | + @ <form action="%R/setup_skin_admin" method="POST"> | |
| 730 | + login_insert_csrf_secret(); | |
| 731 | + if( zDfltSkin==0 || fossil_strcmp(aBuiltinSkin[i].zLabel, zDfltSkin)!=0 ){ | |
| 732 | + /* vvvv--- mnemonic: Built-In Skin Label */ | |
| 733 | + @ <input type="hidden" name="bisl" value="%h(aBuiltinSkin[i].zLabel)"> | |
| 734 | + @ <input type="submit" name="setdflt" value="Set"> | |
| 693 | 735 | }else{ |
| 694 | - @ <form action="%R/setup_skin_admin" method="post"> | |
| 695 | - @ <input type="hidden" name="sn" value="%h(z)"> | |
| 696 | - @ <input type="submit" name="load" value="Install"> | |
| 697 | - login_insert_csrf_secret(); | |
| 698 | - if( pAltSkin==&aBuiltinSkin[i] ){ | |
| 699 | - zOverride = z; | |
| 700 | - @ (Currently Used) | |
| 701 | - } | |
| 702 | - @ </form> | |
| 703 | - } | |
| 704 | - @ </tr> | |
| 736 | + @ (Selected) | |
| 737 | + seenDefault = 1; | |
| 738 | + } | |
| 739 | + if( pAltSkin==&aBuiltinSkin[i] && iSkinSource!=SKIN_FROM_SETTING ){ | |
| 740 | + @ (Override) | |
| 741 | + } | |
| 742 | + @ </form></td></tr> | |
| 705 | 743 | } |
| 706 | 744 | if( zOverride ){ |
| 707 | 745 | @ <tr><td> <td colspan="3"> |
| 708 | 746 | @ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of |
| 709 | 747 | switch( iSkinSource ){ |
| @@ -727,57 +765,59 @@ | ||
| 727 | 765 | @ reasons unknown. (Fix me!) |
| 728 | 766 | break; |
| 729 | 767 | } |
| 730 | 768 | @ </tr> |
| 731 | 769 | } |
| 770 | + i++; | |
| 771 | + @ <tr><td colspan=4><h2>Custom skin:</h2></td></tr> | |
| 772 | + @ <tr><td>%d(i). | |
| 773 | + if( hasCustom ){ | |
| 774 | + @ <td>Custom<td> <td> | |
| 775 | + }else{ | |
| 776 | + @ <td><i>(None)</i><td> <td> | |
| 777 | + } | |
| 778 | + @ <form method="post"> | |
| 779 | + login_insert_csrf_secret(); | |
| 780 | + if( hasCustom ){ | |
| 781 | + @ <input type="submit" name="save" value="Backup"> | |
| 782 | + @ <input type="submit" name="editdraft" value="Edit"> | |
| 783 | + if( !seenDefault ){ | |
| 784 | + @ (Selected) | |
| 785 | + }else{ | |
| 786 | + @ <input type="hidden" name="bisl" value=""> | |
| 787 | + @ <input type="submit" name="setdflt" value="Set"> | |
| 788 | + @ <input type="submit" name="del1" value="Delete"> | |
| 789 | + @ <input type="hidden" name="sn" value="custom"> | |
| 790 | + } | |
| 791 | + }else{ | |
| 792 | + @ <input type="submit" name="editdraft" value="Create"> | |
| 793 | + } | |
| 794 | + @ </form> | |
| 795 | + @ </td></tr> | |
| 732 | 796 | db_prepare(&q, |
| 733 | - "SELECT substr(name, 6), value FROM config" | |
| 797 | + "SELECT substr(name, 6) FROM config" | |
| 734 | 798 | " WHERE name GLOB 'skin:*'" |
| 735 | 799 | " ORDER BY name" |
| 736 | 800 | ); |
| 737 | 801 | once = 1; |
| 738 | 802 | while( db_step(&q)==SQLITE_ROW ){ |
| 739 | 803 | const char *zN = db_column_text(&q, 0); |
| 740 | - const char *zV = db_column_text(&q, 1); | |
| 741 | 804 | i++; |
| 742 | 805 | if( once ){ |
| 743 | 806 | once = 0; |
| 744 | - @ <tr><td colspan=4><h2>Backup skins saved as "skin:*' entries \ | |
| 745 | - @ in the CONFIG table:</h2></td></tr> | |
| 807 | + @ <tr><td colspan=4><h2>Backups of past custom skins:</h2></td></tr> | |
| 746 | 808 | } |
| 747 | 809 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 748 | 810 | @ <form action="%R/setup_skin_admin" method="post"> |
| 749 | 811 | login_insert_csrf_secret(); |
| 750 | - if( fossil_strcmp(zV, zCurrent)==0 ){ | |
| 751 | - @ (Installed) | |
| 752 | - zInstalled = mprintf("%s", zN); | |
| 753 | - seenCurrent = 1; | |
| 754 | - }else{ | |
| 755 | - @ <input type="submit" name="load" value="Install"> | |
| 756 | - @ <input type="submit" name="del1" value="Delete"> | |
| 757 | - } | |
| 812 | + @ <input type="submit" name="load" value="Install"> | |
| 813 | + @ <input type="submit" name="del1" value="Delete"> | |
| 758 | 814 | @ <input type="submit" name="rename" value="Rename"> |
| 759 | 815 | @ <input type="hidden" name="sn" value="%h(zN)"> |
| 760 | 816 | @ </form></tr> |
| 761 | 817 | } |
| 762 | 818 | db_finalize(&q); |
| 763 | - i++; | |
| 764 | - @ <tr><td colspan=4><h2>Current skin in css/details/footer/header/js \ | |
| 765 | - @ entries in the CONFIG table:</h2></td></tr> | |
| 766 | - @ <tr><td>%d(i).<td><i>Current</i><td> <td> | |
| 767 | - @ <form action="%R/setup_skin_admin" method="post"> | |
| 768 | - if( !seenCurrent ){ | |
| 769 | - @ <input type="submit" name="save" value="Backup"> | |
| 770 | - } | |
| 771 | - @ <input type="submit" name="editdraft" value="Edit"> | |
| 772 | - login_insert_csrf_secret(); | |
| 773 | - @ </form> | |
| 774 | - if( zInstalled ){ | |
| 775 | - @ <tr><td> <td colspan="3"><p> | |
| 776 | - @ Note: The current skin is an exact copy of "%h(zInstalled)". | |
| 777 | - @ </tr> | |
| 778 | - } | |
| 779 | 819 | db_prepare(&q, |
| 780 | 820 | "SELECT DISTINCT substr(name, 1, 6) FROM config" |
| 781 | 821 | " WHERE name GLOB 'draft[1-9]-*'" |
| 782 | 822 | " ORDER BY name" |
| 783 | 823 | ); |
| @@ -785,18 +825,19 @@ | ||
| 785 | 825 | while( db_step(&q)==SQLITE_ROW ){ |
| 786 | 826 | const char *zN = db_column_text(&q, 0); |
| 787 | 827 | i++; |
| 788 | 828 | if( once ){ |
| 789 | 829 | once = 0; |
| 790 | - @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \ | |
| 791 | - @ in the CONFIG table:</h2></td></tr> | |
| 830 | + @ <tr><td colspan=4><h2>Draft skins:</h2></td></tr> | |
| 792 | 831 | } |
| 793 | 832 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 794 | 833 | @ <form action="%R/setup_skin_admin" method="post"> |
| 795 | 834 | login_insert_csrf_secret(); |
| 835 | + @ <input type="submit" name="load" value="Install"> | |
| 796 | 836 | @ <input type="submit" name="draftdel" value="Delete"> |
| 797 | 837 | @ <input type="hidden" name="name" value="%h(zN)"> |
| 838 | + @ <input type="hidden" name="sn" value="%h(zN+5)"> | |
| 798 | 839 | @ </form></tr> |
| 799 | 840 | } |
| 800 | 841 | db_finalize(&q); |
| 801 | 842 | |
| 802 | 843 | @ </table> |
| @@ -812,35 +853,38 @@ | ||
| 812 | 853 | const char *zVarName, /* Variable name for the <select> */ |
| 813 | 854 | const char *zDefault, /* The default value, if not NULL */ |
| 814 | 855 | const char *zExcept /* Omit this skin if not NULL */ |
| 815 | 856 | ){ |
| 816 | 857 | int i; |
| 858 | + Stmt s; | |
| 817 | 859 | @ <select size='1' name='%s(zVarName)'> |
| 818 | - if( fossil_strcmp(zExcept, "current")!=0 ){ | |
| 819 | - @ <option value='current'>Currently In Use</option> | |
| 860 | + if( fossil_strcmp(zExcept, "current")!=0 && skin_exists_custom() ){ | |
| 861 | + @ <option value='current'>Current Custom Skin</option> | |
| 820 | 862 | } |
| 821 | 863 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 822 | 864 | const char *zName = aBuiltinSkin[i].zLabel; |
| 823 | 865 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 824 | 866 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 825 | 867 | @ <option value='%s(zName)' selected>\ |
| 826 | - @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> | |
| 868 | + @ %h(aBuiltinSkin[i].zDesc)</option> | |
| 827 | 869 | }else{ |
| 828 | 870 | @ <option value='%s(zName)'>\ |
| 829 | - @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> | |
| 871 | + @ %h(aBuiltinSkin[i].zDesc)</option> | |
| 830 | 872 | } |
| 831 | 873 | } |
| 832 | - for(i=1; i<=9; i++){ | |
| 833 | - char zName[20]; | |
| 834 | - sqlite3_snprintf(sizeof(zName), zName, "draft%d", i); | |
| 874 | + db_prepare(&s, "SELECT DISTINCT substr(name,1,6) FROM config" | |
| 875 | + " WHERE name GLOB 'draft[1-9]-*' ORDER BY 1"); | |
| 876 | + while( db_step(&s)==SQLITE_ROW ){ | |
| 877 | + const char *zName = db_column_text(&s, 0); | |
| 835 | 878 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 836 | 879 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 837 | 880 | @ <option value='%s(zName)' selected>%s(zName)</option> |
| 838 | 881 | }else{ |
| 839 | 882 | @ <option value='%s(zName)'>%s(zName)</option> |
| 840 | 883 | } |
| 841 | 884 | } |
| 885 | + db_finalize(&s); | |
| 842 | 886 | @ </select> |
| 843 | 887 | } |
| 844 | 888 | |
| 845 | 889 | /* |
| 846 | 890 | ** Return the text of one of the skin files. |
| @@ -1054,16 +1098,18 @@ | ||
| 1054 | 1098 | /* Publish draft iSkin */ |
| 1055 | 1099 | for(i=0; i<count(azSkinFile); i++){ |
| 1056 | 1100 | char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); |
| 1057 | 1101 | db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0); |
| 1058 | 1102 | } |
| 1103 | + db_unset("default-skin", 0); | |
| 1059 | 1104 | } |
| 1060 | 1105 | |
| 1061 | 1106 | /* |
| 1062 | 1107 | ** WEBPAGE: setup_skin |
| 1063 | 1108 | ** |
| 1064 | -** Generate a page showing the steps needed to customize a skin. | |
| 1109 | +** Generate a page showing the steps needed to create or edit | |
| 1110 | +** a custom skin. | |
| 1065 | 1111 | */ |
| 1066 | 1112 | void setup_skin(void){ |
| 1067 | 1113 | int i; /* Loop counter */ |
| 1068 | 1114 | int iSkin; /* Which draft skin is being edited */ |
| 1069 | 1115 | int isSetup; /* True for an administrator */ |
| @@ -1186,18 +1232,20 @@ | ||
| 1186 | 1232 | @ |
| 1187 | 1233 | if( !isEditor ){ |
| 1188 | 1234 | @ <p>You are not allowed to initialize draft%d(iSkin). Contact |
| 1189 | 1235 | @ the administrator for this repository for more information. |
| 1190 | 1236 | }else{ |
| 1237 | + char *zDraft = mprintf("draft%d", iSkin); | |
| 1191 | 1238 | @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins |
| 1192 | 1239 | @ or a preexisting skin, to use as a baseline.</p> |
| 1193 | 1240 | @ |
| 1194 | 1241 | @ <form method='POST' action='%R/setup_skin#step4' id='f03'> |
| 1195 | 1242 | @ <p class='skinInput'> |
| 1196 | 1243 | @ <input type='hidden' name='sk' value='%d(iSkin)'> |
| 1197 | 1244 | @ Initialize skin <b>draft%d(iSkin)</b> using |
| 1198 | - skin_emit_skin_selector("initskin", "current", 0); | |
| 1245 | + skin_emit_skin_selector("initskin", 0, zDraft); | |
| 1246 | + fossil_free(zDraft); | |
| 1199 | 1247 | @ <input type='submit' name='init3' value='Go'> |
| 1200 | 1248 | @ </p> |
| 1201 | 1249 | @ </form> |
| 1202 | 1250 | } |
| 1203 | 1251 | @ |
| 1204 | 1252 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -559,10 +559,20 @@ | |
| 559 | ); |
| 560 | db_protect_pop(); |
| 561 | return 0; |
| 562 | } |
| 563 | |
| 564 | /* |
| 565 | ** WEBPAGE: setup_skin_admin |
| 566 | ** |
| 567 | ** Administrative actions on skins. For administrators only. |
| 568 | */ |
| @@ -571,14 +581,15 @@ | |
| 571 | char *zName; |
| 572 | char *zErr = 0; |
| 573 | const char *zCurrent = 0; /* Current skin */ |
| 574 | int i; /* Loop counter */ |
| 575 | Stmt q; |
| 576 | int seenCurrent = 0; |
| 577 | int once; |
| 578 | const char *zInstalled = 0; |
| 579 | const char *zOverride = 0; |
| 580 | |
| 581 | login_check_credentials(); |
| 582 | if( !g.perm.Admin ){ |
| 583 | login_needed(0); |
| 584 | return; |
| @@ -591,11 +602,11 @@ | |
| 591 | |
| 592 | style_set_current_feature("skins"); |
| 593 | |
| 594 | if( cgi_csrf_safe(2) ){ |
| 595 | /* Process requests to delete a user-defined skin */ |
| 596 | if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){ |
| 597 | style_header("Confirm Custom Skin Delete"); |
| 598 | @ <form action="%R/setup_skin_admin" method="post"><div> |
| 599 | @ <p>Deletion of a custom skin is a permanent action that cannot |
| 600 | @ be undone. Please confirm that this is what you want to do:</p> |
| 601 | @ <input type="hidden" name="sn" value="%h(P("sn"))"> |
| @@ -605,13 +616,18 @@ | |
| 605 | @ </div></form> |
| 606 | style_finish_page(); |
| 607 | db_end_transaction(1); |
| 608 | return; |
| 609 | } |
| 610 | if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ |
| 611 | db_unprotect(PROTECT_CONFIG); |
| 612 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 613 | db_protect_pop(); |
| 614 | } |
| 615 | if( P("draftdel")!=0 ){ |
| 616 | const char *zDraft = P("name"); |
| 617 | if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ |
| @@ -627,39 +643,57 @@ | |
| 627 | } |
| 628 | if( skinRename() || skinSave(zCurrent) ){ |
| 629 | db_end_transaction(0); |
| 630 | return; |
| 631 | } |
| 632 | |
| 633 | /* The user pressed one of the "Install" buttons. */ |
| 634 | if( P("load") && (z = P("sn"))!=0 && z[0] ){ |
| 635 | int seen = 0; |
| 636 | |
| 637 | /* Check to see if the current skin is already saved. If it is, there |
| 638 | ** is no need to create a backup */ |
| 639 | zCurrent = getSkin(0); |
| 640 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 641 | if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ |
| 642 | seen = 1; |
| 643 | break; |
| 644 | } |
| 645 | } |
| 646 | if( !seen ){ |
| 647 | seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" |
| 648 | " AND value=%Q", zCurrent); |
| 649 | if( !seen ){ |
| 650 | db_unprotect(PROTECT_CONFIG); |
| 651 | db_multi_exec( |
| 652 | "INSERT INTO config(name,value,mtime) VALUES(" |
| 653 | " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," |
| 654 | " %Q,now())", zCurrent |
| 655 | ); |
| 656 | db_protect_pop(); |
| 657 | } |
| 658 | } |
| 659 | seen = 0; |
| 660 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 661 | if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ |
| 662 | seen = 1; |
| 663 | zCurrent = aBuiltinSkin[i].zSQL; |
| 664 | db_unprotect(PROTECT_CONFIG); |
| 665 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| @@ -674,36 +708,40 @@ | |
| 674 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| 675 | db_protect_pop(); |
| 676 | } |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | style_header("Skins"); |
| 681 | if( zErr ){ |
| 682 | @ <p style="color:red">%h(zErr)</p> |
| 683 | } |
| 684 | @ <table border="0"> |
| 685 | @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></th> |
| 686 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 687 | z = aBuiltinSkin[i].zDesc; |
| 688 | @ <tr><td>%d(i+1).<td>%h(z)<td> <td> |
| 689 | if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ |
| 690 | @ (Installed) |
| 691 | zInstalled = z; |
| 692 | seenCurrent = 1; |
| 693 | }else{ |
| 694 | @ <form action="%R/setup_skin_admin" method="post"> |
| 695 | @ <input type="hidden" name="sn" value="%h(z)"> |
| 696 | @ <input type="submit" name="load" value="Install"> |
| 697 | login_insert_csrf_secret(); |
| 698 | if( pAltSkin==&aBuiltinSkin[i] ){ |
| 699 | zOverride = z; |
| 700 | @ (Currently Used) |
| 701 | } |
| 702 | @ </form> |
| 703 | } |
| 704 | @ </tr> |
| 705 | } |
| 706 | if( zOverride ){ |
| 707 | @ <tr><td> <td colspan="3"> |
| 708 | @ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of |
| 709 | switch( iSkinSource ){ |
| @@ -727,57 +765,59 @@ | |
| 727 | @ reasons unknown. (Fix me!) |
| 728 | break; |
| 729 | } |
| 730 | @ </tr> |
| 731 | } |
| 732 | db_prepare(&q, |
| 733 | "SELECT substr(name, 6), value FROM config" |
| 734 | " WHERE name GLOB 'skin:*'" |
| 735 | " ORDER BY name" |
| 736 | ); |
| 737 | once = 1; |
| 738 | while( db_step(&q)==SQLITE_ROW ){ |
| 739 | const char *zN = db_column_text(&q, 0); |
| 740 | const char *zV = db_column_text(&q, 1); |
| 741 | i++; |
| 742 | if( once ){ |
| 743 | once = 0; |
| 744 | @ <tr><td colspan=4><h2>Backup skins saved as "skin:*' entries \ |
| 745 | @ in the CONFIG table:</h2></td></tr> |
| 746 | } |
| 747 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 748 | @ <form action="%R/setup_skin_admin" method="post"> |
| 749 | login_insert_csrf_secret(); |
| 750 | if( fossil_strcmp(zV, zCurrent)==0 ){ |
| 751 | @ (Installed) |
| 752 | zInstalled = mprintf("%s", zN); |
| 753 | seenCurrent = 1; |
| 754 | }else{ |
| 755 | @ <input type="submit" name="load" value="Install"> |
| 756 | @ <input type="submit" name="del1" value="Delete"> |
| 757 | } |
| 758 | @ <input type="submit" name="rename" value="Rename"> |
| 759 | @ <input type="hidden" name="sn" value="%h(zN)"> |
| 760 | @ </form></tr> |
| 761 | } |
| 762 | db_finalize(&q); |
| 763 | i++; |
| 764 | @ <tr><td colspan=4><h2>Current skin in css/details/footer/header/js \ |
| 765 | @ entries in the CONFIG table:</h2></td></tr> |
| 766 | @ <tr><td>%d(i).<td><i>Current</i><td> <td> |
| 767 | @ <form action="%R/setup_skin_admin" method="post"> |
| 768 | if( !seenCurrent ){ |
| 769 | @ <input type="submit" name="save" value="Backup"> |
| 770 | } |
| 771 | @ <input type="submit" name="editdraft" value="Edit"> |
| 772 | login_insert_csrf_secret(); |
| 773 | @ </form> |
| 774 | if( zInstalled ){ |
| 775 | @ <tr><td> <td colspan="3"><p> |
| 776 | @ Note: The current skin is an exact copy of "%h(zInstalled)". |
| 777 | @ </tr> |
| 778 | } |
| 779 | db_prepare(&q, |
| 780 | "SELECT DISTINCT substr(name, 1, 6) FROM config" |
| 781 | " WHERE name GLOB 'draft[1-9]-*'" |
| 782 | " ORDER BY name" |
| 783 | ); |
| @@ -785,18 +825,19 @@ | |
| 785 | while( db_step(&q)==SQLITE_ROW ){ |
| 786 | const char *zN = db_column_text(&q, 0); |
| 787 | i++; |
| 788 | if( once ){ |
| 789 | once = 0; |
| 790 | @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \ |
| 791 | @ in the CONFIG table:</h2></td></tr> |
| 792 | } |
| 793 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 794 | @ <form action="%R/setup_skin_admin" method="post"> |
| 795 | login_insert_csrf_secret(); |
| 796 | @ <input type="submit" name="draftdel" value="Delete"> |
| 797 | @ <input type="hidden" name="name" value="%h(zN)"> |
| 798 | @ </form></tr> |
| 799 | } |
| 800 | db_finalize(&q); |
| 801 | |
| 802 | @ </table> |
| @@ -812,35 +853,38 @@ | |
| 812 | const char *zVarName, /* Variable name for the <select> */ |
| 813 | const char *zDefault, /* The default value, if not NULL */ |
| 814 | const char *zExcept /* Omit this skin if not NULL */ |
| 815 | ){ |
| 816 | int i; |
| 817 | @ <select size='1' name='%s(zVarName)'> |
| 818 | if( fossil_strcmp(zExcept, "current")!=0 ){ |
| 819 | @ <option value='current'>Currently In Use</option> |
| 820 | } |
| 821 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 822 | const char *zName = aBuiltinSkin[i].zLabel; |
| 823 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 824 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 825 | @ <option value='%s(zName)' selected>\ |
| 826 | @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> |
| 827 | }else{ |
| 828 | @ <option value='%s(zName)'>\ |
| 829 | @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> |
| 830 | } |
| 831 | } |
| 832 | for(i=1; i<=9; i++){ |
| 833 | char zName[20]; |
| 834 | sqlite3_snprintf(sizeof(zName), zName, "draft%d", i); |
| 835 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 836 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 837 | @ <option value='%s(zName)' selected>%s(zName)</option> |
| 838 | }else{ |
| 839 | @ <option value='%s(zName)'>%s(zName)</option> |
| 840 | } |
| 841 | } |
| 842 | @ </select> |
| 843 | } |
| 844 | |
| 845 | /* |
| 846 | ** Return the text of one of the skin files. |
| @@ -1054,16 +1098,18 @@ | |
| 1054 | /* Publish draft iSkin */ |
| 1055 | for(i=0; i<count(azSkinFile); i++){ |
| 1056 | char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); |
| 1057 | db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0); |
| 1058 | } |
| 1059 | } |
| 1060 | |
| 1061 | /* |
| 1062 | ** WEBPAGE: setup_skin |
| 1063 | ** |
| 1064 | ** Generate a page showing the steps needed to customize a skin. |
| 1065 | */ |
| 1066 | void setup_skin(void){ |
| 1067 | int i; /* Loop counter */ |
| 1068 | int iSkin; /* Which draft skin is being edited */ |
| 1069 | int isSetup; /* True for an administrator */ |
| @@ -1186,18 +1232,20 @@ | |
| 1186 | @ |
| 1187 | if( !isEditor ){ |
| 1188 | @ <p>You are not allowed to initialize draft%d(iSkin). Contact |
| 1189 | @ the administrator for this repository for more information. |
| 1190 | }else{ |
| 1191 | @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins |
| 1192 | @ or a preexisting skin, to use as a baseline.</p> |
| 1193 | @ |
| 1194 | @ <form method='POST' action='%R/setup_skin#step4' id='f03'> |
| 1195 | @ <p class='skinInput'> |
| 1196 | @ <input type='hidden' name='sk' value='%d(iSkin)'> |
| 1197 | @ Initialize skin <b>draft%d(iSkin)</b> using |
| 1198 | skin_emit_skin_selector("initskin", "current", 0); |
| 1199 | @ <input type='submit' name='init3' value='Go'> |
| 1200 | @ </p> |
| 1201 | @ </form> |
| 1202 | } |
| 1203 | @ |
| 1204 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -559,10 +559,20 @@ | |
| 559 | ); |
| 560 | db_protect_pop(); |
| 561 | return 0; |
| 562 | } |
| 563 | |
| 564 | /* |
| 565 | ** Return true if a custom skin exists |
| 566 | */ |
| 567 | static int skin_exists_custom(void){ |
| 568 | return db_exists("SELECT 1 FROM config WHERE name IN" |
| 569 | " ('css','details','footer','header','js')"); |
| 570 | } |
| 571 | |
| 572 | static void skin_publish(int); /* Forward reference */ |
| 573 | |
| 574 | /* |
| 575 | ** WEBPAGE: setup_skin_admin |
| 576 | ** |
| 577 | ** Administrative actions on skins. For administrators only. |
| 578 | */ |
| @@ -571,14 +581,15 @@ | |
| 581 | char *zName; |
| 582 | char *zErr = 0; |
| 583 | const char *zCurrent = 0; /* Current skin */ |
| 584 | int i; /* Loop counter */ |
| 585 | Stmt q; |
| 586 | int once; |
| 587 | const char *zOverride = 0; |
| 588 | const char *zDfltSkin = 0; |
| 589 | int seenDefault = 0; |
| 590 | int hasCustom; |
| 591 | |
| 592 | login_check_credentials(); |
| 593 | if( !g.perm.Admin ){ |
| 594 | login_needed(0); |
| 595 | return; |
| @@ -591,11 +602,11 @@ | |
| 602 | |
| 603 | style_set_current_feature("skins"); |
| 604 | |
| 605 | if( cgi_csrf_safe(2) ){ |
| 606 | /* Process requests to delete a user-defined skin */ |
| 607 | if( P("del1") && P("sn")!=0 ){ |
| 608 | style_header("Confirm Custom Skin Delete"); |
| 609 | @ <form action="%R/setup_skin_admin" method="post"><div> |
| 610 | @ <p>Deletion of a custom skin is a permanent action that cannot |
| 611 | @ be undone. Please confirm that this is what you want to do:</p> |
| 612 | @ <input type="hidden" name="sn" value="%h(P("sn"))"> |
| @@ -605,13 +616,18 @@ | |
| 616 | @ </div></form> |
| 617 | style_finish_page(); |
| 618 | db_end_transaction(1); |
| 619 | return; |
| 620 | } |
| 621 | if( P("del2")!=0 ){ |
| 622 | db_unprotect(PROTECT_CONFIG); |
| 623 | if( fossil_strcmp(P("sn"),"custom")==0 ){ |
| 624 | db_multi_exec("DELETE FROM config WHERE name IN" |
| 625 | "('css','details','footer','header','js')"); |
| 626 | }else if( (zName = skinVarName(P("sn"), 1))!=0 ){ |
| 627 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 628 | } |
| 629 | db_protect_pop(); |
| 630 | } |
| 631 | if( P("draftdel")!=0 ){ |
| 632 | const char *zDraft = P("name"); |
| 633 | if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ |
| @@ -627,39 +643,57 @@ | |
| 643 | } |
| 644 | if( skinRename() || skinSave(zCurrent) ){ |
| 645 | db_end_transaction(0); |
| 646 | return; |
| 647 | } |
| 648 | |
| 649 | if( P("setdflt") && (z = P("bisl"))!=0 ){ |
| 650 | if( z[0] ){ |
| 651 | db_set("default-skin", z, 0); |
| 652 | }else{ |
| 653 | db_unset("default-skin", 0); |
| 654 | } |
| 655 | db_end_transaction(0); |
| 656 | cgi_redirectf("%R/setup_skin_admin"); |
| 657 | return; |
| 658 | } |
| 659 | |
| 660 | /* The user pressed one of the "Install" buttons. */ |
| 661 | if( P("load") && (z = P("sn"))!=0 && z[0] ){ |
| 662 | int seen = 0; |
| 663 | |
| 664 | /* Check to see if the current skin is already saved. If it is, there |
| 665 | ** is no need to create a backup */ |
| 666 | hasCustom = skin_exists_custom(); |
| 667 | if( hasCustom ){ |
| 668 | zCurrent = getSkin(0); |
| 669 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 670 | if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ |
| 671 | seen = 1; |
| 672 | break; |
| 673 | } |
| 674 | } |
| 675 | if( !seen ){ |
| 676 | seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" |
| 677 | " AND value=%Q", zCurrent); |
| 678 | if( !seen ){ |
| 679 | db_unprotect(PROTECT_CONFIG); |
| 680 | db_multi_exec( |
| 681 | "INSERT INTO config(name,value,mtime) VALUES(" |
| 682 | " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," |
| 683 | " %Q,now())", zCurrent |
| 684 | ); |
| 685 | db_protect_pop(); |
| 686 | } |
| 687 | } |
| 688 | } |
| 689 | seen = 0; |
| 690 | if( z[0]>='1' && z[0]<='9' && z[1]==0 ){ |
| 691 | skin_publish(z[0]-'0'); |
| 692 | seen = 1; |
| 693 | } |
| 694 | for(i=0; seen==0 && i<count(aBuiltinSkin); i++){ |
| 695 | if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ |
| 696 | seen = 1; |
| 697 | zCurrent = aBuiltinSkin[i].zSQL; |
| 698 | db_unprotect(PROTECT_CONFIG); |
| 699 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| @@ -674,36 +708,40 @@ | |
| 708 | db_multi_exec("%s", zCurrent/*safe-for-%s*/); |
| 709 | db_protect_pop(); |
| 710 | } |
| 711 | } |
| 712 | } |
| 713 | |
| 714 | zDfltSkin = db_get("default-skin",0); |
| 715 | hasCustom = skin_exists_custom(); |
| 716 | if( !hasCustom && zDfltSkin==0 ){ |
| 717 | zDfltSkin = "default"; |
| 718 | } |
| 719 | |
| 720 | style_header("Skins"); |
| 721 | if( zErr ){ |
| 722 | @ <p style="color:red">%h(zErr)</p> |
| 723 | } |
| 724 | @ <table border="0"> |
| 725 | @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></tr> |
| 726 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 727 | z = aBuiltinSkin[i].zDesc; |
| 728 | @ <tr><td>%d(i+1).<td>%h(z)<td> <td> |
| 729 | @ <form action="%R/setup_skin_admin" method="POST"> |
| 730 | login_insert_csrf_secret(); |
| 731 | if( zDfltSkin==0 || fossil_strcmp(aBuiltinSkin[i].zLabel, zDfltSkin)!=0 ){ |
| 732 | /* vvvv--- mnemonic: Built-In Skin Label */ |
| 733 | @ <input type="hidden" name="bisl" value="%h(aBuiltinSkin[i].zLabel)"> |
| 734 | @ <input type="submit" name="setdflt" value="Set"> |
| 735 | }else{ |
| 736 | @ (Selected) |
| 737 | seenDefault = 1; |
| 738 | } |
| 739 | if( pAltSkin==&aBuiltinSkin[i] && iSkinSource!=SKIN_FROM_SETTING ){ |
| 740 | @ (Override) |
| 741 | } |
| 742 | @ </form></td></tr> |
| 743 | } |
| 744 | if( zOverride ){ |
| 745 | @ <tr><td> <td colspan="3"> |
| 746 | @ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of |
| 747 | switch( iSkinSource ){ |
| @@ -727,57 +765,59 @@ | |
| 765 | @ reasons unknown. (Fix me!) |
| 766 | break; |
| 767 | } |
| 768 | @ </tr> |
| 769 | } |
| 770 | i++; |
| 771 | @ <tr><td colspan=4><h2>Custom skin:</h2></td></tr> |
| 772 | @ <tr><td>%d(i). |
| 773 | if( hasCustom ){ |
| 774 | @ <td>Custom<td> <td> |
| 775 | }else{ |
| 776 | @ <td><i>(None)</i><td> <td> |
| 777 | } |
| 778 | @ <form method="post"> |
| 779 | login_insert_csrf_secret(); |
| 780 | if( hasCustom ){ |
| 781 | @ <input type="submit" name="save" value="Backup"> |
| 782 | @ <input type="submit" name="editdraft" value="Edit"> |
| 783 | if( !seenDefault ){ |
| 784 | @ (Selected) |
| 785 | }else{ |
| 786 | @ <input type="hidden" name="bisl" value=""> |
| 787 | @ <input type="submit" name="setdflt" value="Set"> |
| 788 | @ <input type="submit" name="del1" value="Delete"> |
| 789 | @ <input type="hidden" name="sn" value="custom"> |
| 790 | } |
| 791 | }else{ |
| 792 | @ <input type="submit" name="editdraft" value="Create"> |
| 793 | } |
| 794 | @ </form> |
| 795 | @ </td></tr> |
| 796 | db_prepare(&q, |
| 797 | "SELECT substr(name, 6) FROM config" |
| 798 | " WHERE name GLOB 'skin:*'" |
| 799 | " ORDER BY name" |
| 800 | ); |
| 801 | once = 1; |
| 802 | while( db_step(&q)==SQLITE_ROW ){ |
| 803 | const char *zN = db_column_text(&q, 0); |
| 804 | i++; |
| 805 | if( once ){ |
| 806 | once = 0; |
| 807 | @ <tr><td colspan=4><h2>Backups of past custom skins:</h2></td></tr> |
| 808 | } |
| 809 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 810 | @ <form action="%R/setup_skin_admin" method="post"> |
| 811 | login_insert_csrf_secret(); |
| 812 | @ <input type="submit" name="load" value="Install"> |
| 813 | @ <input type="submit" name="del1" value="Delete"> |
| 814 | @ <input type="submit" name="rename" value="Rename"> |
| 815 | @ <input type="hidden" name="sn" value="%h(zN)"> |
| 816 | @ </form></tr> |
| 817 | } |
| 818 | db_finalize(&q); |
| 819 | db_prepare(&q, |
| 820 | "SELECT DISTINCT substr(name, 1, 6) FROM config" |
| 821 | " WHERE name GLOB 'draft[1-9]-*'" |
| 822 | " ORDER BY name" |
| 823 | ); |
| @@ -785,18 +825,19 @@ | |
| 825 | while( db_step(&q)==SQLITE_ROW ){ |
| 826 | const char *zN = db_column_text(&q, 0); |
| 827 | i++; |
| 828 | if( once ){ |
| 829 | once = 0; |
| 830 | @ <tr><td colspan=4><h2>Draft skins:</h2></td></tr> |
| 831 | } |
| 832 | @ <tr><td>%d(i).<td>%h(zN)<td> <td> |
| 833 | @ <form action="%R/setup_skin_admin" method="post"> |
| 834 | login_insert_csrf_secret(); |
| 835 | @ <input type="submit" name="load" value="Install"> |
| 836 | @ <input type="submit" name="draftdel" value="Delete"> |
| 837 | @ <input type="hidden" name="name" value="%h(zN)"> |
| 838 | @ <input type="hidden" name="sn" value="%h(zN+5)"> |
| 839 | @ </form></tr> |
| 840 | } |
| 841 | db_finalize(&q); |
| 842 | |
| 843 | @ </table> |
| @@ -812,35 +853,38 @@ | |
| 853 | const char *zVarName, /* Variable name for the <select> */ |
| 854 | const char *zDefault, /* The default value, if not NULL */ |
| 855 | const char *zExcept /* Omit this skin if not NULL */ |
| 856 | ){ |
| 857 | int i; |
| 858 | Stmt s; |
| 859 | @ <select size='1' name='%s(zVarName)'> |
| 860 | if( fossil_strcmp(zExcept, "current")!=0 && skin_exists_custom() ){ |
| 861 | @ <option value='current'>Current Custom Skin</option> |
| 862 | } |
| 863 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 864 | const char *zName = aBuiltinSkin[i].zLabel; |
| 865 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 866 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 867 | @ <option value='%s(zName)' selected>\ |
| 868 | @ %h(aBuiltinSkin[i].zDesc)</option> |
| 869 | }else{ |
| 870 | @ <option value='%s(zName)'>\ |
| 871 | @ %h(aBuiltinSkin[i].zDesc)</option> |
| 872 | } |
| 873 | } |
| 874 | db_prepare(&s, "SELECT DISTINCT substr(name,1,6) FROM config" |
| 875 | " WHERE name GLOB 'draft[1-9]-*' ORDER BY 1"); |
| 876 | while( db_step(&s)==SQLITE_ROW ){ |
| 877 | const char *zName = db_column_text(&s, 0); |
| 878 | if( fossil_strcmp(zName, zExcept)==0 ) continue; |
| 879 | if( fossil_strcmp(zDefault, zName)==0 ){ |
| 880 | @ <option value='%s(zName)' selected>%s(zName)</option> |
| 881 | }else{ |
| 882 | @ <option value='%s(zName)'>%s(zName)</option> |
| 883 | } |
| 884 | } |
| 885 | db_finalize(&s); |
| 886 | @ </select> |
| 887 | } |
| 888 | |
| 889 | /* |
| 890 | ** Return the text of one of the skin files. |
| @@ -1054,16 +1098,18 @@ | |
| 1098 | /* Publish draft iSkin */ |
| 1099 | for(i=0; i<count(azSkinFile); i++){ |
| 1100 | char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); |
| 1101 | db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0); |
| 1102 | } |
| 1103 | db_unset("default-skin", 0); |
| 1104 | } |
| 1105 | |
| 1106 | /* |
| 1107 | ** WEBPAGE: setup_skin |
| 1108 | ** |
| 1109 | ** Generate a page showing the steps needed to create or edit |
| 1110 | ** a custom skin. |
| 1111 | */ |
| 1112 | void setup_skin(void){ |
| 1113 | int i; /* Loop counter */ |
| 1114 | int iSkin; /* Which draft skin is being edited */ |
| 1115 | int isSetup; /* True for an administrator */ |
| @@ -1186,18 +1232,20 @@ | |
| 1232 | @ |
| 1233 | if( !isEditor ){ |
| 1234 | @ <p>You are not allowed to initialize draft%d(iSkin). Contact |
| 1235 | @ the administrator for this repository for more information. |
| 1236 | }else{ |
| 1237 | char *zDraft = mprintf("draft%d", iSkin); |
| 1238 | @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins |
| 1239 | @ or a preexisting skin, to use as a baseline.</p> |
| 1240 | @ |
| 1241 | @ <form method='POST' action='%R/setup_skin#step4' id='f03'> |
| 1242 | @ <p class='skinInput'> |
| 1243 | @ <input type='hidden' name='sk' value='%d(iSkin)'> |
| 1244 | @ Initialize skin <b>draft%d(iSkin)</b> using |
| 1245 | skin_emit_skin_selector("initskin", 0, zDraft); |
| 1246 | fossil_free(zDraft); |
| 1247 | @ <input type='submit' name='init3' value='Go'> |
| 1248 | @ </p> |
| 1249 | @ </form> |
| 1250 | } |
| 1251 | @ |
| 1252 |