Fossil

Check-in [f3702b86c3]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f3702b86c3d75fb501a88adf406dc2a1c42a5bbd2e49c7a8b0fedc74edb40d18
User & Date: drh 2024-02-23 20:52:28.111
Context
2024-02-23
21:57
In the source of the home page (<code>www/index.wiki</code>) move the "What Is It?" header ahead of the floating sidebar. This fixes appearence under the custom skin where that sidebar (from the content) collides with another floating sidebar (emitted by the header of a skin). check-in: 3a78497bd7 user: george tags: trunk
20:52
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. check-in: f3702b86c3 user: drh tags: trunk
18:18
Revive the default-skin setting. I now think it will be useful after all, when used in combination with other changes that are planned. check-in: 18d76fffb1 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/skins.c.
557
558
559
560
561
562
563










564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579



580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611




612

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631











632
633
634
635
636
637
638


639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659




660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678






679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694



695
696
697



698
699
700
701
702
703
704
705
706
707
708
709
710
711
    "VALUES('skin:%q',%Q,now())",
    zNewName, zCurrent
  );
  db_protect_pop();
  return 0;
}











/*
** WEBPAGE: setup_skin_admin
**
** Administrative actions on skins.  For administrators only.
*/
void setup_skin_admin(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent = 0;  /* Current skin */
  int i;                     /* Loop counter */
  Stmt q;
  int seenCurrent = 0;
  int once;
  const char *zInstalled = 0;
  const char *zOverride = 0;




  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  db_begin_transaction();
  zCurrent = getSkin(0);
  for(i=0; i<count(aBuiltinSkin); i++){
    aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
  }

  style_set_current_feature("skins");

  if( cgi_csrf_safe(2) ){
    /* Process requests to delete a user-defined skin */
    if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
      style_header("Confirm Custom Skin Delete");
      @ <form action="%R/setup_skin_admin" method="post"><div>
      @ <p>Deletion of a custom skin is a permanent action that cannot
      @ be undone.  Please confirm that this is what you want to do:</p>
      @ <input type="hidden" name="sn" value="%h(P("sn"))">
      @ <input type="submit" name="del2" value="Confirm - Delete The Skin">
      @ <input type="submit" name="cancel" value="Cancel - Do Not Delete">
      login_insert_csrf_secret();
      @ </div></form>
      style_finish_page();
      db_end_transaction(1);
      return;
    }
    if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
      db_unprotect(PROTECT_CONFIG);




      db_multi_exec("DELETE FROM config WHERE name=%Q", zName);

      db_protect_pop();
    }
    if( P("draftdel")!=0 ){
      const char *zDraft = P("name");
      if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft);
        db_protect_pop();
      }
    }
    if( P("editdraft")!=0 ){
      db_end_transaction(0);
      cgi_redirectf("%R/setup_skin");
      return;
    }
    if( skinRename() || skinSave(zCurrent) ){
      db_end_transaction(0);
      return;
    }












    /* The user pressed one of the "Install" buttons. */
    if( P("load") && (z = P("sn"))!=0 && z[0] ){
      int seen = 0;

      /* Check to see if the current skin is already saved.  If it is, there
      ** is no need to create a backup */


      zCurrent = getSkin(0);
      for(i=0; i<count(aBuiltinSkin); i++){
        if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
          seen = 1;
          break;
        }
      }
      if( !seen ){
        seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
                         " AND value=%Q", zCurrent);
        if( !seen ){
          db_unprotect(PROTECT_CONFIG);
          db_multi_exec(
            "INSERT INTO config(name,value,mtime) VALUES("
            "  strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
            "  %Q,now())", zCurrent
          );
          db_protect_pop();
        }
      }

      seen = 0;




      for(i=0; i<count(aBuiltinSkin); i++){
        if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
          seen = 1;
          zCurrent = aBuiltinSkin[i].zSQL;
          db_unprotect(PROTECT_CONFIG);
          db_multi_exec("%s", zCurrent/*safe-for-%s*/);
          db_protect_pop();
          break;
        }
      }
      if( !seen ){
        zName = skinVarName(z,0);
        zCurrent = db_get(zName, 0);
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec("%s", zCurrent/*safe-for-%s*/);
        db_protect_pop();
      }
    }
  }







  style_header("Skins");
  if( zErr ){
    @ <p style="color:red">%h(zErr)</p>
  }
  @ <table border="0">
  @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></th>
  for(i=0; i<count(aBuiltinSkin); i++){
    z = aBuiltinSkin[i].zDesc;
    @ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<td>
    if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
      @ (Installed)
      zInstalled = z;
      seenCurrent = 1;
    }else{
      @ <form action="%R/setup_skin_admin" method="post">



      @ <input type="hidden" name="sn" value="%h(z)">
      @ <input type="submit" name="load" value="Install">
      login_insert_csrf_secret();



      if( pAltSkin==&aBuiltinSkin[i] ){
        zOverride = z;
        @ (Currently Used)
      }
      @ </form>
    }
    @ </tr>
  }
  if( zOverride ){
    @ <tr><td>&nbsp;<td colspan="3">
    @ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of
    switch( iSkinSource ){
      case SKIN_FROM_CMDLINE:
        @ the --skin command-line option.







>
>
>
>
>
>
>
>
>
>












<

<

>
>
>
















|













|

>
>
>
>
|
>



















>
>
>
>
>
>
>
>
>
>
>







>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

>
>
>
>
|


















>
>
>
>
>
>






|



<
<
<
<
<
|
>
>
>
|
|
|
>
>
>
|
|
<
|
|
<
<







557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

586

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728





729
730
731
732
733
734
735
736
737
738
739
740

741
742


743
744
745
746
747
748
749
    "VALUES('skin:%q',%Q,now())",
    zNewName, zCurrent
  );
  db_protect_pop();
  return 0;
}

/*
** Return true if a custom skin exists
*/
static int skin_exists_custom(void){
  return db_exists("SELECT 1 FROM config WHERE name IN"
                        " ('css','details','footer','header','js')");
}

static void skin_publish(int);  /* Forward reference */

/*
** WEBPAGE: setup_skin_admin
**
** Administrative actions on skins.  For administrators only.
*/
void setup_skin_admin(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent = 0;  /* Current skin */
  int i;                     /* Loop counter */
  Stmt q;

  int once;

  const char *zOverride = 0;
  const char *zDfltSkin = 0;
  int seenDefault = 0;
  int hasCustom;

  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  db_begin_transaction();
  zCurrent = getSkin(0);
  for(i=0; i<count(aBuiltinSkin); i++){
    aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
  }

  style_set_current_feature("skins");

  if( cgi_csrf_safe(2) ){
    /* Process requests to delete a user-defined skin */
    if( P("del1") && P("sn")!=0 ){
      style_header("Confirm Custom Skin Delete");
      @ <form action="%R/setup_skin_admin" method="post"><div>
      @ <p>Deletion of a custom skin is a permanent action that cannot
      @ be undone.  Please confirm that this is what you want to do:</p>
      @ <input type="hidden" name="sn" value="%h(P("sn"))">
      @ <input type="submit" name="del2" value="Confirm - Delete The Skin">
      @ <input type="submit" name="cancel" value="Cancel - Do Not Delete">
      login_insert_csrf_secret();
      @ </div></form>
      style_finish_page();
      db_end_transaction(1);
      return;
    }
    if( P("del2")!=0 ){
      db_unprotect(PROTECT_CONFIG);
      if( fossil_strcmp(P("sn"),"custom")==0 ){
        db_multi_exec("DELETE FROM config WHERE name IN" 
                      "('css','details','footer','header','js')");
      }else if( (zName = skinVarName(P("sn"), 1))!=0 ){
        db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
      }
      db_protect_pop();
    }
    if( P("draftdel")!=0 ){
      const char *zDraft = P("name");
      if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft);
        db_protect_pop();
      }
    }
    if( P("editdraft")!=0 ){
      db_end_transaction(0);
      cgi_redirectf("%R/setup_skin");
      return;
    }
    if( skinRename() || skinSave(zCurrent) ){
      db_end_transaction(0);
      return;
    }

    if( P("setdflt") && (z = P("bisl"))!=0 ){
      if( z[0] ){
        db_set("default-skin", z, 0);
      }else{
        db_unset("default-skin", 0);
      }
      db_end_transaction(0);
      cgi_redirectf("%R/setup_skin_admin");
      return;
    }

    /* The user pressed one of the "Install" buttons. */
    if( P("load") && (z = P("sn"))!=0 && z[0] ){
      int seen = 0;

      /* Check to see if the current skin is already saved.  If it is, there
      ** is no need to create a backup */
      hasCustom = skin_exists_custom();
      if( hasCustom ){
        zCurrent = getSkin(0);
        for(i=0; i<count(aBuiltinSkin); i++){
          if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
            seen = 1;
            break;
          }
        }
        if( !seen ){
          seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
                           " AND value=%Q", zCurrent);
          if( !seen ){
            db_unprotect(PROTECT_CONFIG);
            db_multi_exec(
              "INSERT INTO config(name,value,mtime) VALUES("
              "  strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
              "  %Q,now())", zCurrent
            );
            db_protect_pop();
          }
        }
      }
      seen = 0;
      if( z[0]>='1' && z[0]<='9' && z[1]==0 ){
        skin_publish(z[0]-'0');
        seen = 1;
      }
      for(i=0; seen==0 && i<count(aBuiltinSkin); i++){
        if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
          seen = 1;
          zCurrent = aBuiltinSkin[i].zSQL;
          db_unprotect(PROTECT_CONFIG);
          db_multi_exec("%s", zCurrent/*safe-for-%s*/);
          db_protect_pop();
          break;
        }
      }
      if( !seen ){
        zName = skinVarName(z,0);
        zCurrent = db_get(zName, 0);
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec("%s", zCurrent/*safe-for-%s*/);
        db_protect_pop();
      }
    }
  }

  zDfltSkin = db_get("default-skin",0);
  hasCustom = skin_exists_custom();
  if( !hasCustom && zDfltSkin==0 ){
    zDfltSkin = "default";
  }

  style_header("Skins");
  if( zErr ){
    @ <p style="color:red">%h(zErr)</p>
  }
  @ <table border="0">
  @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></tr>
  for(i=0; i<count(aBuiltinSkin); i++){
    z = aBuiltinSkin[i].zDesc;
    @ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<td>





    @ <form action="%R/setup_skin_admin" method="POST">
    login_insert_csrf_secret();
    if( zDfltSkin==0 || fossil_strcmp(aBuiltinSkin[i].zLabel, zDfltSkin)!=0 ){
                                /* vvvv--- mnemonic: Built-In Skin Label */
      @ <input type="hidden" name="bisl" value="%h(aBuiltinSkin[i].zLabel)">
      @ <input type="submit" name="setdflt" value="Set">
    }else{
      @ (Selected)
      seenDefault = 1;
    }
    if( pAltSkin==&aBuiltinSkin[i] && iSkinSource!=SKIN_FROM_SETTING ){
      @ (Override)

    }
    @ </form></td></tr>


  }
  if( zOverride ){
    @ <tr><td>&nbsp;<td colspan="3">
    @ <p>Note: Built-in skin "%h(zOverride)" is currently being used because of
    switch( iSkinSource ){
      case SKIN_FROM_CMDLINE:
        @ the --skin command-line option.
725
726
727
728
729
730
731


























732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795

796
797

798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833

834
835
836
837
838
839
840
841

842
843
844
845
846
847
848
        break;
      default:
        @ reasons unknown.  (Fix me!)
        break;
    }
    @ </tr>
  }


























  db_prepare(&q,
     "SELECT substr(name, 6), value FROM config"
     " WHERE name GLOB 'skin:*'"
     " ORDER BY name"
  );
  once = 1;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);
    const char *zV = db_column_text(&q, 1);
    i++;
    if( once ){
      once = 0;
      @ <tr><td colspan=4><h2>Backup skins saved as "skin:*' entries \
      @ in the CONFIG table:</h2></td></tr>
    }
    @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
    @ <form action="%R/setup_skin_admin" method="post">
    login_insert_csrf_secret();
    if( fossil_strcmp(zV, zCurrent)==0 ){
      @ (Installed)
      zInstalled = mprintf("%s", zN);
      seenCurrent = 1;
    }else{
      @ <input type="submit" name="load" value="Install">
      @ <input type="submit" name="del1" value="Delete">
    }
    @ <input type="submit" name="rename" value="Rename">
    @ <input type="hidden" name="sn" value="%h(zN)">
    @ </form></tr>
  }
  db_finalize(&q);
  i++;
  @ <tr><td colspan=4><h2>Current skin in css/details/footer/header/js \
  @ entries in the CONFIG table:</h2></td></tr>
  @ <tr><td>%d(i).<td><i>Current</i><td>&nbsp;&nbsp;<td>
  @ <form action="%R/setup_skin_admin" method="post">
  if( !seenCurrent ){
    @ <input type="submit" name="save" value="Backup">
  }
  @ <input type="submit" name="editdraft" value="Edit">
  login_insert_csrf_secret();
  @ </form>
  if( zInstalled ){
    @ <tr><td>&nbsp;<td colspan="3"><p>
    @ Note: The current skin is an exact copy of "%h(zInstalled)".
    @ </tr>
  }
  db_prepare(&q,
     "SELECT DISTINCT substr(name, 1, 6) FROM config"
     " WHERE name GLOB 'draft[1-9]-*'"
     " ORDER BY name"
  );
  once = 1;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);
    i++;
    if( once ){
      once = 0;
      @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
      @ in the CONFIG table:</h2></td></tr>
    }
    @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
    @ <form action="%R/setup_skin_admin" method="post">
    login_insert_csrf_secret();

    @ <input type="submit" name="draftdel" value="Delete">
    @ <input type="hidden" name="name" value="%h(zN)">

    @ </form></tr>
  }
  db_finalize(&q);

  @ </table>
  style_finish_page();
  db_end_transaction(0);
}

/*
** Generate HTML for a <select> that lists all the available skin names,
** except for zExcept if zExcept!=NULL.
*/
static void skin_emit_skin_selector(
  const char *zVarName,      /* Variable name for the <select> */
  const char *zDefault,      /* The default value, if not NULL */
  const char *zExcept        /* Omit this skin if not NULL */
){
  int i;

  @ <select size='1' name='%s(zVarName)'>
  if( fossil_strcmp(zExcept, "current")!=0 ){
    @ <option value='current'>Currently In Use</option>
  }
  for(i=0; i<count(aBuiltinSkin); i++){
    const char *zName = aBuiltinSkin[i].zLabel;
    if( fossil_strcmp(zName, zExcept)==0 ) continue;
    if( fossil_strcmp(zDefault, zName)==0 ){
      @ <option value='%s(zName)' selected>\
      @ %h(aBuiltinSkin[i].zDesc) (built-in)</option>
    }else{
      @ <option value='%s(zName)'>\
      @ %h(aBuiltinSkin[i].zDesc) (built-in)</option>
    }
  }
  for(i=1; i<=9; i++){
    char zName[20];

    sqlite3_snprintf(sizeof(zName), zName, "draft%d", i);
    if( fossil_strcmp(zName, zExcept)==0 ) continue;
    if( fossil_strcmp(zDefault, zName)==0 ){
      @ <option value='%s(zName)' selected>%s(zName)</option>
    }else{
      @ <option value='%s(zName)'>%s(zName)</option>
    }
  }

  @ </select>
}

/*
** Return the text of one of the skin files.
*/
static const char *skin_file_content(const char *zLabel, const char *zFile){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|






<



|
<




<
<
<
<
<
|
|
<





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<











|
<




>


>



















>

|
|






|


|


|
|
>
|







>







763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803

804
805
806
807

808
809
810
811





812
813

814
815
816
817
818
















819
820
821
822
823
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
        break;
      default:
        @ reasons unknown.  (Fix me!)
        break;
    }
    @ </tr>
  }
  i++;
  @ <tr><td colspan=4><h2>Custom skin:</h2></td></tr>
  @ <tr><td>%d(i).
  if( hasCustom ){
    @ <td>Custom<td>&nbsp;&nbsp;<td>
  }else{
    @ <td><i>(None)</i><td>&nbsp;&nbsp;<td>
  }
  @ <form method="post">
  login_insert_csrf_secret();
  if( hasCustom ){
    @ <input type="submit" name="save" value="Backup">
    @ <input type="submit" name="editdraft" value="Edit">
    if( !seenDefault ){
      @ (Selected)
    }else{
      @ <input type="hidden" name="bisl" value="">
      @ <input type="submit" name="setdflt" value="Set">
      @ <input type="submit" name="del1" value="Delete">
      @ <input type="hidden" name="sn" value="custom">
    }
  }else{
    @ <input type="submit" name="editdraft" value="Create">
  }
  @ </form>
  @ </td></tr>
  db_prepare(&q,
     "SELECT substr(name, 6) FROM config"
     " WHERE name GLOB 'skin:*'"
     " ORDER BY name"
  );
  once = 1;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);

    i++;
    if( once ){
      once = 0;
      @ <tr><td colspan=4><h2>Backups of past custom skins:</h2></td></tr>

    }
    @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
    @ <form action="%R/setup_skin_admin" method="post">
    login_insert_csrf_secret();





    @ <input type="submit" name="load" value="Install">
    @ <input type="submit" name="del1" value="Delete">

    @ <input type="submit" name="rename" value="Rename">
    @ <input type="hidden" name="sn" value="%h(zN)">
    @ </form></tr>
  }
  db_finalize(&q);
















  db_prepare(&q,
     "SELECT DISTINCT substr(name, 1, 6) FROM config"
     " WHERE name GLOB 'draft[1-9]-*'"
     " ORDER BY name"
  );
  once = 1;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);
    i++;
    if( once ){
      once = 0;
      @ <tr><td colspan=4><h2>Draft skins:</h2></td></tr>

    }
    @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
    @ <form action="%R/setup_skin_admin" method="post">
    login_insert_csrf_secret();
    @ <input type="submit" name="load" value="Install">
    @ <input type="submit" name="draftdel" value="Delete">
    @ <input type="hidden" name="name" value="%h(zN)">
    @ <input type="hidden" name="sn" value="%h(zN+5)">
    @ </form></tr>
  }
  db_finalize(&q);

  @ </table>
  style_finish_page();
  db_end_transaction(0);
}

/*
** Generate HTML for a <select> that lists all the available skin names,
** except for zExcept if zExcept!=NULL.
*/
static void skin_emit_skin_selector(
  const char *zVarName,      /* Variable name for the <select> */
  const char *zDefault,      /* The default value, if not NULL */
  const char *zExcept        /* Omit this skin if not NULL */
){
  int i;
  Stmt s;
  @ <select size='1' name='%s(zVarName)'>
  if( fossil_strcmp(zExcept, "current")!=0 && skin_exists_custom() ){
    @ <option value='current'>Current Custom Skin</option>
  }
  for(i=0; i<count(aBuiltinSkin); i++){
    const char *zName = aBuiltinSkin[i].zLabel;
    if( fossil_strcmp(zName, zExcept)==0 ) continue;
    if( fossil_strcmp(zDefault, zName)==0 ){
      @ <option value='%s(zName)' selected>\
      @ %h(aBuiltinSkin[i].zDesc)</option>
    }else{
      @ <option value='%s(zName)'>\
      @ %h(aBuiltinSkin[i].zDesc)</option>
    }
  }
  db_prepare(&s, "SELECT DISTINCT substr(name,1,6) FROM config"
                 " WHERE name GLOB 'draft[1-9]-*' ORDER BY 1");
  while( db_step(&s)==SQLITE_ROW ){
    const char *zName = db_column_text(&s, 0);
    if( fossil_strcmp(zName, zExcept)==0 ) continue;
    if( fossil_strcmp(zDefault, zName)==0 ){
      @ <option value='%s(zName)' selected>%s(zName)</option>
    }else{
      @ <option value='%s(zName)'>%s(zName)</option>
    }
  }
  db_finalize(&s);
  @ </select>
}

/*
** Return the text of one of the skin files.
*/
static const char *skin_file_content(const char *zLabel, const char *zFile){
1052
1053
1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
  }

  /* Publish draft iSkin */
  for(i=0; i<count(azSkinFile); i++){
    char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
    db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0);
  }

}

/*
** WEBPAGE: setup_skin
**
** Generate a page showing the steps needed to customize a skin.

*/
void setup_skin(void){
  int i;          /* Loop counter */
  int iSkin;      /* Which draft skin is being edited */
  int isSetup;    /* True for an administrator */
  int isEditor;   /* Others authorized to make edits */
  char *zAllowedEditors;   /* Who may edit the draft skin */







>





|
>







1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  }

  /* Publish draft iSkin */
  for(i=0; i<count(azSkinFile); i++){
    char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]);
    db_set(azSkinFile[i]/*works-like:"x"*/, zNew, 0);
  }
  db_unset("default-skin", 0);
}

/*
** WEBPAGE: setup_skin
**
** Generate a page showing the steps needed to create or edit
** a custom skin.
*/
void setup_skin(void){
  int i;          /* Loop counter */
  int iSkin;      /* Which draft skin is being edited */
  int isSetup;    /* True for an administrator */
  int isEditor;   /* Others authorized to make edits */
  char *zAllowedEditors;   /* Who may edit the draft skin */
1184
1185
1186
1187
1188
1189
1190

1191
1192
1193
1194
1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
  @ <a name='step3'></a>
  @ <h1>Step 3: Initialize The Draft</h1>
  @
  if( !isEditor ){
    @ <p>You are not allowed to initialize draft%d(iSkin).  Contact
    @ the administrator for this repository for more information.
  }else{

    @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins
    @ or a preexisting skin, to use as a baseline.</p>
    @
    @ <form method='POST' action='%R/setup_skin#step4' id='f03'>
    @ <p class='skinInput'>
    @ <input type='hidden' name='sk' value='%d(iSkin)'>
    @ Initialize skin <b>draft%d(iSkin)</b> using
    skin_emit_skin_selector("initskin", "current", 0);

    @ <input type='submit' name='init3' value='Go'>
    @ </p>
    @ </form>
  }
  @
  @ <a name='step4'></a>
  @ <h1>Step 4: Make Edits</h1>







>







|
>







1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  @ <a name='step3'></a>
  @ <h1>Step 3: Initialize The Draft</h1>
  @
  if( !isEditor ){
    @ <p>You are not allowed to initialize draft%d(iSkin).  Contact
    @ the administrator for this repository for more information.
  }else{
    char *zDraft = mprintf("draft%d", iSkin);
    @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins
    @ or a preexisting skin, to use as a baseline.</p>
    @
    @ <form method='POST' action='%R/setup_skin#step4' id='f03'>
    @ <p class='skinInput'>
    @ <input type='hidden' name='sk' value='%d(iSkin)'>
    @ Initialize skin <b>draft%d(iSkin)</b> using
    skin_emit_skin_selector("initskin", 0, zDraft);
    fossil_free(zDraft);
    @ <input type='submit' name='init3' value='Go'>
    @ </p>
    @ </form>
  }
  @
  @ <a name='step4'></a>
  @ <h1>Step 4: Make Edits</h1>