| | @@ -64,10 +64,11 @@ |
| 64 | 64 | ** The following static variable holds the name of the alternative skin, |
| 65 | 65 | ** or NULL if the skin should be as configured. |
| 66 | 66 | */ |
| 67 | 67 | static struct BuiltinSkin *pAltSkin = 0; |
| 68 | 68 | static char *zAltSkinDir = 0; |
| 69 | +static int iDraftSkin = 0; |
| 69 | 70 | |
| 70 | 71 | /* |
| 71 | 72 | ** Skin details are a set of key/value pairs that define display |
| 72 | 73 | ** attributes of the skin that cannot be easily specified using CSS |
| 73 | 74 | ** or that need to be known on the server-side. |
| | @@ -100,10 +101,14 @@ |
| 100 | 101 | int i; |
| 101 | 102 | Blob err = BLOB_INITIALIZER; |
| 102 | 103 | if( strchr(zName, '/')!=0 ){ |
| 103 | 104 | zAltSkinDir = fossil_strdup(zName); |
| 104 | 105 | return 0; |
| 106 | + } |
| 107 | + if( sqlite3_strglob("draft[1-9]", zName)==0 ){ |
| 108 | + skin_use_draft(zName[5] - '0'); |
| 109 | + return 0; |
| 105 | 110 | } |
| 106 | 111 | for(i=0; i<count(aBuiltinSkin); i++){ |
| 107 | 112 | if( fossil_strcmp(aBuiltinSkin[i].zLabel, zName)==0 ){ |
| 108 | 113 | pAltSkin = &aBuiltinSkin[i]; |
| 109 | 114 | return 0; |
| | @@ -126,18 +131,33 @@ |
| 126 | 131 | if( zSkin ){ |
| 127 | 132 | char *zErr = skin_use_alternative(zSkin); |
| 128 | 133 | if( zErr ) fossil_fatal("%s", zErr); |
| 129 | 134 | } |
| 130 | 135 | } |
| 136 | + |
| 137 | +/* |
| 138 | +** Use one of the draft skins. |
| 139 | +*/ |
| 140 | +void skin_use_draft(int i){ |
| 141 | + iDraftSkin = i; |
| 142 | +} |
| 131 | 143 | |
| 132 | 144 | /* |
| 133 | 145 | ** The following routines return the various components of the skin |
| 134 | 146 | ** that should be used for the current run. |
| 147 | +** |
| 148 | +** zWhat is one of: "css", "header", "footer", "details". |
| 135 | 149 | */ |
| 136 | 150 | const char *skin_get(const char *zWhat){ |
| 137 | 151 | const char *zOut; |
| 138 | 152 | char *z; |
| 153 | + if( iDraftSkin ){ |
| 154 | + z = mprintf("draft%d-%s", iDraftSkin, zWhat); |
| 155 | + zOut = db_get(z, 0); |
| 156 | + fossil_free(z); |
| 157 | + if( zOut ) return zOut; |
| 158 | + } |
| 139 | 159 | if( zAltSkinDir ){ |
| 140 | 160 | char *z = mprintf("%s/%s.txt", zAltSkinDir, zWhat); |
| 141 | 161 | if( file_isfile(z) ){ |
| 142 | 162 | Blob x; |
| 143 | 163 | blob_read_from_file(&x, z); |
| | @@ -668,39 +688,83 @@ |
| 668 | 688 | } |
| 669 | 689 | @ </div></form> |
| 670 | 690 | style_footer(); |
| 671 | 691 | db_end_transaction(0); |
| 672 | 692 | } |
| 693 | + |
| 694 | +/* |
| 695 | +** Try to initialize draft skin iSkin to the built-in or preexisting |
| 696 | +** skin named by zTemplate. |
| 697 | +*/ |
| 698 | +static void skin_initialize_draft(int iSkin, const char *zTemplate){ |
| 699 | + int i; |
| 700 | + const char *azWhat[] = { "css", "header", "footer", "detail" }; |
| 701 | + if( zTemplate==0 ) return; |
| 702 | + if( strcmp(zTemplate, "current")==0 ){ |
| 703 | + for(i=0; i<count(azWhat); i++){ |
| 704 | + db_unset_mprintf("draft%d-%s", 0, iSkin, azWhat[i]); |
| 705 | + } |
| 706 | + }else{ |
| 707 | + for(i=0; i<count(aBuiltinSkin); i++){ |
| 708 | + if( strcmp(zTemplate, aBuiltinSkin[i].zLabel)==0 ){ |
| 709 | + for(i=0; i<count(azWhat); i++){ |
| 710 | + char *zKey = mprintf("skins/%s/%s.txt", zTemplate, azWhat[i]); |
| 711 | + db_set_mprintf("draft%d-%s", builtin_text(zKey), 0, iSkin, azWhat[i]); |
| 712 | + } |
| 713 | + break; |
| 714 | + } |
| 715 | + } |
| 716 | + } |
| 717 | +} |
| 673 | 718 | |
| 674 | 719 | /* |
| 675 | 720 | ** WEBPAGE: setup_skin |
| 676 | 721 | ** |
| 677 | 722 | ** Generate a page showing the steps needed to customize a skin. |
| 678 | 723 | */ |
| 679 | 724 | void setup_skin(void){ |
| 680 | 725 | int i; /* Loop counter */ |
| 681 | 726 | int iSkin; /* Which draft skin is being edited */ |
| 727 | + int isAdmin; /* True for an administrator */ |
| 728 | + int isEditor; /* Others authorized to make edits */ |
| 682 | 729 | static const char *azTestPages[] = { |
| 683 | 730 | "home", |
| 684 | 731 | "timeline", |
| 685 | 732 | "dir?ci=tip", |
| 686 | 733 | "dir?ci=tip&type=tree", |
| 687 | 734 | "brlist", |
| 688 | 735 | "info/trunk", |
| 689 | 736 | }; |
| 690 | 737 | |
| 691 | | - |
| 738 | + /* Figure out which skin we are editing */ |
| 692 | 739 | iSkin = atoi(PD("sk","1")); |
| 693 | 740 | if( iSkin<1 || iSkin>9 ) iSkin = 1; |
| 741 | + |
| 742 | + /* Figure out if the current user is allowed to make administrative |
| 743 | + ** changes and/or edits |
| 744 | + */ |
| 694 | 745 | login_check_credentials(); |
| 695 | | - style_header("Customize Skin"); |
| 746 | + if( g.perm.Admin ){ |
| 747 | + isAdmin = isEditor = 1; |
| 748 | + }else{ |
| 749 | + char *zAllowedEditors; |
| 750 | + Glob *pAllowedEditors; |
| 751 | + isAdmin = isEditor = 0; |
| 752 | + zAllowedEditors = db_get_mprintf("draft%d-users", 0, iSkin); |
| 753 | + if( zAllowedEditors ){ |
| 754 | + pAllowedEditors = glob_create(zAllowedEditors); |
| 755 | + isEditor = glob_match(pAllowedEditors, zAllowedEditors); |
| 756 | + glob_free(pAllowedEditors); |
| 757 | + } |
| 758 | + } |
| 759 | + |
| 760 | + /* Initialize the skin, if requested and authorized. */ |
| 761 | + if( P("init3")!=0 && isEditor ){ |
| 762 | + skin_initialize_draft(iSkin, P("initskin")); |
| 763 | + } |
| 696 | 764 | |
| 697 | | -#if 0 |
| 698 | | - @ <p> |
| 699 | | - cgi_print_all(0); |
| 700 | | - @ </p> |
| 701 | | -#endif |
| 765 | + style_header("Customize Skin"); |
| 702 | 766 | |
| 703 | 767 | @ <p>Customize the look of this Fossil repository by making changes |
| 704 | 768 | @ to the CSS, Header, Footer, and Detail Settings in one of nine "draft" |
| 705 | 769 | @ configurations. Then, after verifying that all is working correctly, |
| 706 | 770 | @ publish the draft to become the new main Skin.<p> |
| | @@ -729,10 +793,31 @@ |
| 729 | 793 | @ <a name='step2'></a> |
| 730 | 794 | @ <h1>Step 2: Authenticate |
| 731 | 795 | @ |
| 732 | 796 | @ <a name='step3'></a> |
| 733 | 797 | @ <h1>Step 3: Initialize The Draft</h1> |
| 798 | + @ |
| 799 | + if( !isEditor ){ |
| 800 | + @ <p>You are not allowed to initialize draft%(iSkin). Contact |
| 801 | + @ the administrator for this repository for more information. |
| 802 | + }else{ |
| 803 | + @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins |
| 804 | + @ or a preexisting skin, to use as a baseline.</p> |
| 805 | + @ |
| 806 | + @ <p><form method='POST' action='%R/setup_skin#stop4' id='f03'> |
| 807 | + @ <input type='hidden' name='sk' value='%d(iSkin)'> |
| 808 | + @ Initialize <b>draft%d(iSkin)</b> to |
| 809 | + @ <select size='1' name='initskin'> |
| 810 | + @ <option value='current'>Currently In Use</option> |
| 811 | + for(i=0; i<count(aBuiltinSkin); i++){ |
| 812 | + @ <option value='%s(aBuiltinSkin[i].zLabel)'>\ |
| 813 | + @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> |
| 814 | + } |
| 815 | + @ </select> |
| 816 | + @ <input type='submit' name='init3' value='Go'> |
| 817 | + @ </p> |
| 818 | + } |
| 734 | 819 | @ |
| 735 | 820 | @ <a name='step4'></a> |
| 736 | 821 | @ <h1>Step 4: Make Edits</h1> |
| 737 | 822 | @ |
| 738 | 823 | @ <a name='step5'></a> |
| | @@ -739,15 +824,19 @@ |
| 739 | 824 | @ <h1>Step 5: Verify The Draft Skin</h1> |
| 740 | 825 | @ |
| 741 | 826 | @ <p>To test this draft skin, insert text "/draft%d(iSkin)/" just before the |
| 742 | 827 | @ operation name in the URL. Here are a few links to try: |
| 743 | 828 | @ <ul> |
| 744 | | - for(i=0; i<sizeof(azTestPages)/sizeof(azTestPages[0]); i++){ |
| 829 | + for(i=0; i<count(azTestPages); i++){ |
| 745 | 830 | @ <li><a href='%s(g.zBaseURL)/draft%d(iSkin)/%s(azTestPages[i])'>\ |
| 746 | 831 | @ %s(g.zBaseURL)/draft%d(iSkin)/%s(azTestPages[i])</a> |
| 747 | 832 | } |
| 748 | 833 | @ </ul> |
| 834 | + @ |
| 835 | + @ <p><b>Important:</b> After CSS changes, you will probably need to |
| 836 | + @ press the "Reload" button on your browser for those changes |
| 837 | + @ to take effect.</p> |
| 749 | 838 | @ |
| 750 | 839 | @ <a name='step6'></a> |
| 751 | 840 | @ <h1>Step 6: Publish The Draft</h1> |
| 752 | 841 | if( !g.perm.Setup ){ |
| 753 | 842 | @ <p>Only administrators are allowed to publish draft skins. Contact |
| 754 | 843 | |