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.

drh 2024-02-23 20:52 trunk
Commit f3702b86c3d75fb501a88adf406dc2a1c42a5bbd2e49c7a8b0fedc74edb40d18
1 file changed +127 -79
+127 -79
--- src/skins.c
+++ src/skins.c
@@ -559,10 +559,20 @@
559559
);
560560
db_protect_pop();
561561
return 0;
562562
}
563563
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
+
564574
/*
565575
** WEBPAGE: setup_skin_admin
566576
**
567577
** Administrative actions on skins. For administrators only.
568578
*/
@@ -571,14 +581,15 @@
571581
char *zName;
572582
char *zErr = 0;
573583
const char *zCurrent = 0; /* Current skin */
574584
int i; /* Loop counter */
575585
Stmt q;
576
- int seenCurrent = 0;
577586
int once;
578
- const char *zInstalled = 0;
579587
const char *zOverride = 0;
588
+ const char *zDfltSkin = 0;
589
+ int seenDefault = 0;
590
+ int hasCustom;
580591
581592
login_check_credentials();
582593
if( !g.perm.Admin ){
583594
login_needed(0);
584595
return;
@@ -591,11 +602,11 @@
591602
592603
style_set_current_feature("skins");
593604
594605
if( cgi_csrf_safe(2) ){
595606
/* 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 ){
597608
style_header("Confirm Custom Skin Delete");
598609
@ <form action="%R/setup_skin_admin" method="post"><div>
599610
@ <p>Deletion of a custom skin is a permanent action that cannot
600611
@ be undone. Please confirm that this is what you want to do:</p>
601612
@ <input type="hidden" name="sn" value="%h(P("sn"))">
@@ -605,13 +616,18 @@
605616
@ </div></form>
606617
style_finish_page();
607618
db_end_transaction(1);
608619
return;
609620
}
610
- if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
621
+ if( P("del2")!=0 ){
611622
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
+ }
613629
db_protect_pop();
614630
}
615631
if( P("draftdel")!=0 ){
616632
const char *zDraft = P("name");
617633
if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){
@@ -627,39 +643,57 @@
627643
}
628644
if( skinRename() || skinSave(zCurrent) ){
629645
db_end_transaction(0);
630646
return;
631647
}
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
+ }
632659
633660
/* The user pressed one of the "Install" buttons. */
634661
if( P("load") && (z = P("sn"))!=0 && z[0] ){
635662
int seen = 0;
636663
637664
/* Check to see if the current skin is already saved. If it is, there
638665
** 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
+ }
657687
}
658688
}
659689
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++){
661695
if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
662696
seen = 1;
663697
zCurrent = aBuiltinSkin[i].zSQL;
664698
db_unprotect(PROTECT_CONFIG);
665699
db_multi_exec("%s", zCurrent/*safe-for-%s*/);
@@ -674,36 +708,40 @@
674708
db_multi_exec("%s", zCurrent/*safe-for-%s*/);
675709
db_protect_pop();
676710
}
677711
}
678712
}
713
+
714
+ zDfltSkin = db_get("default-skin",0);
715
+ hasCustom = skin_exists_custom();
716
+ if( !hasCustom && zDfltSkin==0 ){
717
+ zDfltSkin = "default";
718
+ }
679719
680720
style_header("Skins");
681721
if( zErr ){
682722
@ <p style="color:red">%h(zErr)</p>
683723
}
684724
@ <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>
686726
for(i=0; i<count(aBuiltinSkin); i++){
687727
z = aBuiltinSkin[i].zDesc;
688728
@ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<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">
693735
}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>
705743
}
706744
if( zOverride ){
707745
@ <tr><td>&nbsp;<td colspan="3">
708746
@ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of
709747
switch( iSkinSource ){
@@ -727,57 +765,59 @@
727765
@ reasons unknown. (Fix me!)
728766
break;
729767
}
730768
@ </tr>
731769
}
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>&nbsp;&nbsp;<td>
775
+ }else{
776
+ @ <td><i>(None)</i><td>&nbsp;&nbsp;<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>
732796
db_prepare(&q,
733
- "SELECT substr(name, 6), value FROM config"
797
+ "SELECT substr(name, 6) FROM config"
734798
" WHERE name GLOB 'skin:*'"
735799
" ORDER BY name"
736800
);
737801
once = 1;
738802
while( db_step(&q)==SQLITE_ROW ){
739803
const char *zN = db_column_text(&q, 0);
740
- const char *zV = db_column_text(&q, 1);
741804
i++;
742805
if( once ){
743806
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>
746808
}
747809
@ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
748810
@ <form action="%R/setup_skin_admin" method="post">
749811
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">
758814
@ <input type="submit" name="rename" value="Rename">
759815
@ <input type="hidden" name="sn" value="%h(zN)">
760816
@ </form></tr>
761817
}
762818
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>&nbsp;&nbsp;<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>&nbsp;<td colspan="3"><p>
776
- @ Note: The current skin is an exact copy of "%h(zInstalled)".
777
- @ </tr>
778
- }
779819
db_prepare(&q,
780820
"SELECT DISTINCT substr(name, 1, 6) FROM config"
781821
" WHERE name GLOB 'draft[1-9]-*'"
782822
" ORDER BY name"
783823
);
@@ -785,18 +825,19 @@
785825
while( db_step(&q)==SQLITE_ROW ){
786826
const char *zN = db_column_text(&q, 0);
787827
i++;
788828
if( once ){
789829
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>
792831
}
793832
@ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
794833
@ <form action="%R/setup_skin_admin" method="post">
795834
login_insert_csrf_secret();
835
+ @ <input type="submit" name="load" value="Install">
796836
@ <input type="submit" name="draftdel" value="Delete">
797837
@ <input type="hidden" name="name" value="%h(zN)">
838
+ @ <input type="hidden" name="sn" value="%h(zN+5)">
798839
@ </form></tr>
799840
}
800841
db_finalize(&q);
801842
802843
@ </table>
@@ -812,35 +853,38 @@
812853
const char *zVarName, /* Variable name for the <select> */
813854
const char *zDefault, /* The default value, if not NULL */
814855
const char *zExcept /* Omit this skin if not NULL */
815856
){
816857
int i;
858
+ Stmt s;
817859
@ <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>
820862
}
821863
for(i=0; i<count(aBuiltinSkin); i++){
822864
const char *zName = aBuiltinSkin[i].zLabel;
823865
if( fossil_strcmp(zName, zExcept)==0 ) continue;
824866
if( fossil_strcmp(zDefault, zName)==0 ){
825867
@ <option value='%s(zName)' selected>\
826
- @ %h(aBuiltinSkin[i].zDesc) (built-in)</option>
868
+ @ %h(aBuiltinSkin[i].zDesc)</option>
827869
}else{
828870
@ <option value='%s(zName)'>\
829
- @ %h(aBuiltinSkin[i].zDesc) (built-in)</option>
871
+ @ %h(aBuiltinSkin[i].zDesc)</option>
830872
}
831873
}
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);
835878
if( fossil_strcmp(zName, zExcept)==0 ) continue;
836879
if( fossil_strcmp(zDefault, zName)==0 ){
837880
@ <option value='%s(zName)' selected>%s(zName)</option>
838881
}else{
839882
@ <option value='%s(zName)'>%s(zName)</option>
840883
}
841884
}
885
+ db_finalize(&s);
842886
@ </select>
843887
}
844888
845889
/*
846890
** Return the text of one of the skin files.
@@ -1054,16 +1098,18 @@
10541098
/* Publish draft iSkin */
10551099
for(i=0; i<count(azSkinFile); i++){
10561100
char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
10571101
db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0);
10581102
}
1103
+ db_unset("default-skin", 0);
10591104
}
10601105
10611106
/*
10621107
** WEBPAGE: setup_skin
10631108
**
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.
10651111
*/
10661112
void setup_skin(void){
10671113
int i; /* Loop counter */
10681114
int iSkin; /* Which draft skin is being edited */
10691115
int isSetup; /* True for an administrator */
@@ -1186,18 +1232,20 @@
11861232
@
11871233
if( !isEditor ){
11881234
@ <p>You are not allowed to initialize draft%d(iSkin). Contact
11891235
@ the administrator for this repository for more information.
11901236
}else{
1237
+ char *zDraft = mprintf("draft%d", iSkin);
11911238
@ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins
11921239
@ or a preexisting skin, to use as a baseline.</p>
11931240
@
11941241
@ <form method='POST' action='%R/setup_skin#step4' id='f03'>
11951242
@ <p class='skinInput'>
11961243
@ <input type='hidden' name='sk' value='%d(iSkin)'>
11971244
@ 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);
11991247
@ <input type='submit' name='init3' value='Go'>
12001248
@ </p>
12011249
@ </form>
12021250
}
12031251
@
12041252
--- 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>&nbsp;&nbsp;<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>&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;<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>&nbsp;&nbsp;<td>
775 }else{
776 @ <td><i>(None)</i><td>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button