Fossil

Check-in [c145140d3e]
Login

Check-in [c145140d3e]

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

Overview
Comment:/fileedit now squelches errors related to 'missing' URL args, as they are now optional. It also now displays an informative warning at the top of the page if fileedit-glob is not set or is empty. Added a hint about hyperlink in the preview page. Added a Help tab with useful(?) tips.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | fileedit-ajaxify
Files: files | file ages | folders
SHA3-256: c145140d3ee52d25d09a3f114d3496577dc90e52f7846a3853021638f8c1a5a7
User & Date: stephan 2020-05-12 10:24:59.810
Context
2020-05-12
13:18
Added fossil.fetch() responseHeaders option to pass on one or more response headers to the onload() callback. ... (check-in: bbb738d07d user: stephan tags: fileedit-ajaxify)
10:24
/fileedit now squelches errors related to 'missing' URL args, as they are now optional. It also now displays an informative warning at the top of the page if fileedit-glob is not set or is empty. Added a hint about hyperlink in the preview page. Added a Help tab with useful(?) tips. ... (check-in: c145140d3e user: stephan tags: fileedit-ajaxify)
08:54
Double-clicking the status message bar now clears the message (useful when a long HTML-format error comes in via ajax). Removed the unsightly 'new and experimental' banner. ... (check-in: ff7ad7125f user: stephan tags: fileedit-ajaxify)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/default_css.txt.
879
880
881
882
883
884
885
886
887
888



889
890
891
892
893
894
895
  border-color: inherit;
  min-height: 1.5em;
  font-size: 1.2em;
  padding: 0.2em;
  margin: 0.25em 0;
  flex: 0 0 auto;
}
#fossil-status-bar.error {
  color: darkred;
  background: yellow;



}
//////////////////////////////////
// Styles for fossil.tabs.js:
.tab-container {
  width: 100%;
  display: flex;
  flex-direction: column;







|


>
>
>







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
  border-color: inherit;
  min-height: 1.5em;
  font-size: 1.2em;
  padding: 0.2em;
  margin: 0.25em 0;
  flex: 0 0 auto;
}
.error {
  color: darkred;
  background: yellow;
}
body.fileedit .error {
  padding: 0.25em;
}
//////////////////////////////////
// Styles for fossil.tabs.js:
.tab-container {
  width: 100%;
  display: flex;
  flex-direction: column;
Changes to src/fileedit.c.
871
872
873
874
875
876
877

















878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    fossil_warning("The checkout state is now out of sync "
                   "with regards to this commit. It needs to be "
                   "'update'd or 'close'd and re-'open'ed.");
  }
  CheckinMiniInfo_cleanup(&cimi);
}



















/*
** Returns true if the given filename qualifies for online editing by
** the current user, else returns false.
**
** Editing requires that the user have the Write permission and that
** the filename match the glob defined by the fileedit-glob setting.
** A missing or empty value for that glob disables all editing.
*/
int fileedit_is_editable(const char *zFilename){
  static Glob * pGlobs = 0;
  static int once = 0;
  if(0==g.perm.Write || zFilename==0 || *zFilename==0
     || (once!=0 && pGlobs==0)){
    return 0;
  }else if(0==pGlobs){
    char * zGlobs = db_get("fileedit-glob",0);
    once = 1;
    if(0==zGlobs) return 0;
    pGlobs = glob_create(zGlobs);
    fossil_free(zGlobs);
  }
  return glob_match(pGlobs, zFilename);
}


enum fileedit_render_preview_flags {
FE_PREVIEW_LINE_NUMBERS = 1
};
enum fileedit_render_modes {
/* GUESS must be 0. All others have unspecified values. */
FE_RENDER_GUESS = 0,







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










|
<
|
<
|
|
<
<
|
<
<

<

<







871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905

906

907
908


909


910

911

912
913
914
915
916
917
918
    fossil_warning("The checkout state is now out of sync "
                   "with regards to this commit. It needs to be "
                   "'update'd or 'close'd and re-'open'ed.");
  }
  CheckinMiniInfo_cleanup(&cimi);
}

/*
** If the fileedit-glob setting has a value, this returns its Glob
** object (in memory owned by this function), else it returns NULL.
*/
static Glob * fileedit_glob(void){
  static Glob * pGlobs = 0;
  static int once = 0;
  if(0==pGlobs && once==0){
    char * zGlobs = db_get("fileedit-glob",0);
    once = 1;
    if(0!=zGlobs && 0!=*zGlobs){
      pGlobs = glob_create(zGlobs);
    }
    fossil_free(zGlobs);
  }
  return pGlobs;
}

/*
** Returns true if the given filename qualifies for online editing by
** the current user, else returns false.
**
** Editing requires that the user have the Write permission and that
** the filename match the glob defined by the fileedit-glob setting.
** A missing or empty value for that glob disables all editing.
*/
int fileedit_is_editable(const char *zFilename){
  Glob * pGlobs = fileedit_glob();

  if(pGlobs!=0 && zFilename!=0 && *zFilename!=0 && 0!=g.perm.Write){

    return glob_match(pGlobs, zFilename);
  }else{


    return 0;


  }

}


enum fileedit_render_preview_flags {
FE_PREVIEW_LINE_NUMBERS = 1
};
enum fileedit_render_modes {
/* GUESS must be 0. All others have unspecified values. */
FE_RENDER_GUESS = 0,
1301
1302
1303
1304
1305
1306
1307





1308
1309
1310
1311

1312
1313
1314
1315
1316
1317
1318
1319



1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334



1335
1336
1337
1338
1339
1340
1341
** written to pErr.
**
** It always fails if it cannot completely resolve the 'file' and 'r'
** parameters, including verifying that the refer to a real
** file/version combination and editable by the current user. All
** others are optional (at this level, anyway, but upstream code might
** require them).





**
** Intended to be used only by /filepage and /filepage_commit.
*/
static int fileedit_setup_cimi_from_p(CheckinMiniInfo * p, Blob * pErr){

  char * zFileUuid = 0;          /* UUID of file content */
  const char * zFlag;            /* generic flag */
  int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */ 

#define fail(EXPR) blob_appendf EXPR; goto end_fail
  zFlag = PD("filename",P("fn"));
  if(zFlag==0 || !*zFlag){
    rc = 400;



    fail((pErr,"Missing required 'filename' parameter."));
  }
  p->zFilename = mprintf("%s",zFlag);

  if(0==fileedit_is_editable(p->zFilename)){
    rc = 403;
    fail((pErr,"Filename [%h] is disallowed "
          "by the [fileedit-glob] repository "
          "setting.",
          p->zFilename));
  }

  zFlag = PD("checkin",P("ci"));
  if(!zFlag){
    rc = 400;



    fail((pErr,"Missing required 'checkin' parameter."));
  }
  vid = symbolic_name_to_rid(zFlag, "ci");
  if(0==vid){
    rc = 404;
    fail((pErr,"Could not resolve checkin version."));
  }else if(vid<0){







>
>
>
>
>



|
>








>
>
>















>
>
>







1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
** written to pErr.
**
** It always fails if it cannot completely resolve the 'file' and 'r'
** parameters, including verifying that the refer to a real
** file/version combination and editable by the current user. All
** others are optional (at this level, anyway, but upstream code might
** require them).
**
** If the 3rd argument is not NULL and an error is related to a
** missing arg then *bIsMissingArg is set to true. This is
** intended to allow /fileedit to squelch certain initialization
** errors.
**
** Intended to be used only by /filepage and /filepage_commit.
*/
static int fileedit_setup_cimi_from_p(CheckinMiniInfo * p, Blob * pErr,
                                      int * bIsMissingArg){
  char * zFileUuid = 0;          /* UUID of file content */
  const char * zFlag;            /* generic flag */
  int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */ 

#define fail(EXPR) blob_appendf EXPR; goto end_fail
  zFlag = PD("filename",P("fn"));
  if(zFlag==0 || !*zFlag){
    rc = 400;
    if(bIsMissingArg){
      *bIsMissingArg = 1;
    }
    fail((pErr,"Missing required 'filename' parameter."));
  }
  p->zFilename = mprintf("%s",zFlag);

  if(0==fileedit_is_editable(p->zFilename)){
    rc = 403;
    fail((pErr,"Filename [%h] is disallowed "
          "by the [fileedit-glob] repository "
          "setting.",
          p->zFilename));
  }

  zFlag = PD("checkin",P("ci"));
  if(!zFlag){
    rc = 400;
    if(bIsMissingArg){
      *bIsMissingArg = 1;
    }
    fail((pErr,"Missing required 'checkin' parameter."));
  }
  vid = symbolic_name_to_rid(zFlag, "ci");
  if(0==vid){
    rc = 404;
    fail((pErr,"Could not resolve checkin version."));
  }else if(vid<0){
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
  char * zNewUuid = 0;        /* newVid's UUID */

  if(!fileedit_ajax_boostrap()){
    return;
  }
  db_begin_transaction();
  CheckinMiniInfo_init(&cimi);
  rc = fileedit_setup_cimi_from_p(&cimi, &err);
  if(0!=rc){
    fileedit_ajax_error(rc,"%b",&err);
    goto end_cleanup;
  }
  if(blob_size(&cimi.comment)==0){
    fileedit_ajax_error(400,"Empty checkin comment is not permitted.");
    goto end_cleanup;







|







1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
  char * zNewUuid = 0;        /* newVid's UUID */

  if(!fileedit_ajax_boostrap()){
    return;
  }
  db_begin_transaction();
  CheckinMiniInfo_init(&cimi);
  rc = fileedit_setup_cimi_from_p(&cimi, &err, 0);
  if(0!=rc){
    fileedit_ajax_error(rc,"%b",&err);
    goto end_cleanup;
  }
  if(blob_size(&cimi.comment)==0){
    fileedit_ajax_error(400,"Empty checkin comment is not permitted.");
    goto end_cleanup;
1641
1642
1643
1644
1645
1646
1647


1648
1649
1650
1651
1652
1653





1654
1655
1656
1657
1658
1659
1660
  db_begin_transaction();
  CheckinMiniInfo_init(&cimi);
  style_header("File Editor");
  /* As of this point, don't use return or fossil_fatal(). Write any
  ** error in (&err) and goto end_footer instead so that we can be
  ** sure to do any cleanup and end the transaction cleanly.
  */


  if(fileedit_setup_cimi_from_p(&cimi, &err)==0){
    zFilename = cimi.zFilename;
    zRev = cimi.zParentUuid;
    assert(zRev);
    assert(zFilename);
    zFileMime = mimetype_from_name(cimi.zFilename);





  }

  /********************************************************************
  ** All errors which "could" have happened up to this point are of a
  ** degree which keep us from rendering the rest of the page, and
  ** thus have already caused us to skipped to the end of the page to
  ** render the errors. Any up-coming errors, barring malloc failure







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







1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
  db_begin_transaction();
  CheckinMiniInfo_init(&cimi);
  style_header("File Editor");
  /* As of this point, don't use return or fossil_fatal(). Write any
  ** error in (&err) and goto end_footer instead so that we can be
  ** sure to do any cleanup and end the transaction cleanly.
  */
  {
    int isMissingArg = 0;
    if(fileedit_setup_cimi_from_p(&cimi, &err, &isMissingArg)==0){
      zFilename = cimi.zFilename;
      zRev = cimi.zParentUuid;
      assert(zRev);
      assert(zFilename);
      zFileMime = mimetype_from_name(cimi.zFilename);
    }else if(isMissingArg!=0){
      /* Squelch these startup warnings - they're non-fatal now but
      ** used to be. */
      blob_reset(&err);
    }
  }

  /********************************************************************
  ** All errors which "could" have happened up to this point are of a
  ** degree which keep us from rendering the rest of the page, and
  ** thus have already caused us to skipped to the end of the page to
  ** render the errors. Any up-coming errors, barring malloc failure
1670
1671
1672
1673
1674
1675
1676








1677
1678
1679
1680
1681
1682
1683
    ** whatever CSS we wish...
    */
    style_emit_script_tag(0,0);
    CX("document.body.classList.add('fileedit');\n");
    style_emit_script_tag(1,0);
  }









  /* Status bar */
  CX("<div id='fossil-status-bar' "
     "title='Status message area. Double-click to clear them.'>"
     "Status messages will go here.</div>\n"
     /* will be moved into the tab container via JS */);

  /* Main tab container... */







>
>
>
>
>
>
>
>







1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
    ** whatever CSS we wish...
    */
    style_emit_script_tag(0,0);
    CX("document.body.classList.add('fileedit');\n");
    style_emit_script_tag(1,0);
  }

  if(fileedit_glob()==0){
    CX("<div class='error'>To enable online editing, the "
       "<code>fileedit-glob</code> repository setting must be set to a "
       "comma- or newine-delimited list of glob values matching files "
       "which may be edited online."
       "</div>");
  }
  
  /* Status bar */
  CX("<div id='fossil-status-bar' "
     "title='Status message area. Double-click to clear them.'>"
     "Status messages will go here.</div>\n"
     /* will be moved into the tab container via JS */);

  /* Main tab container... */
1749
1750
1751
1752
1753
1754
1755
1756

1757
1758
1759
1760
1761
1762
1763
  /****** Preview tab ******/
  {
    CX("<div id='fileedit-tab-preview' "
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='Preview'"
       ">");

    CX("<div class='fileedit-options flex-container flex-row'>");

    CX("<button id='btn-preview-refresh' "
       "data-f-preview-from='fileedit-content-editor' "
       /* ^^^ text source elem ID*/
       "data-f-preview-via='_postPreview' "
       /* ^^^ fossil.page[methodName](content, callback) */
       "data-f-preview-to='fileedit-tab-preview-wrapper' "
       /* ^^^ dest elem ID */







|
>







1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
  /****** Preview tab ******/
  {
    CX("<div id='fileedit-tab-preview' "
       "data-tab-parent='fileedit-tabs' "
       "data-tab-label='Preview'"
       ">");

    CX("<div class='fileedit-options flex-container flex-column'>");
    CX("<div class='flex-container flex-row'>");
    CX("<button id='btn-preview-refresh' "
       "data-f-preview-from='fileedit-content-editor' "
       /* ^^^ text source elem ID*/
       "data-f-preview-via='_postPreview' "
       /* ^^^ fossil.page[methodName](content, callback) */
       "data-f-preview-to='fileedit-tab-preview-wrapper' "
       /* ^^^ dest elem ID */
1814
1815
1816
1817
1818
1819
1820






1821
1822
1823
1824
1825
1826
1827
    /* Selection of line numbers for text preview */
    style_labeled_checkbox("cb-line-numbers",
                           "preview_ln",
                           "Add line numbers to plain-text previews?",
                           "1", P("preview_ln")!=0,
                           "If on, plain-text files (only) will get "
                           "line numbers added to the preview.");






    CX("</div>"/*.fileedit-options*/);
    CX("<div id='fileedit-tab-preview-wrapper'></div>");
    CX("</div>"/*#fileedit-tab-preview*/);
  }

  /****** Diff tab ******/
  {







>
>
>
>
>
>







1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
    /* Selection of line numbers for text preview */
    style_labeled_checkbox("cb-line-numbers",
                           "preview_ln",
                           "Add line numbers to plain-text previews?",
                           "1", P("preview_ln")!=0,
                           "If on, plain-text files (only) will get "
                           "line numbers added to the preview.");
    CX("</div>"/*.flex-container.flex-row (buttons/options)*/);
    CX("<div class='fileedit-hint'>"
       "Note that hyperlinks in previewed HTML are relative to "
       "<em>this</em> page, and therefore not correct. Clicking "
       "them will leave this page, losing any edits."
       "</div>");
    CX("</div>"/*.fileedit-options*/);
    CX("<div id='fileedit-tab-preview-wrapper'></div>");
    CX("</div>"/*#fileedit-tab-preview*/);
  }

  /****** Diff tab ******/
  {
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
       "</div>");
    CX("</div>"/*#fileedit-tab-diff*/);
  }

  /****** Commit ******/
  CX("<div id='fileedit-tab-commit' "
     "data-tab-parent='fileedit-tabs' "
     "data-tab-select='1' "
     "data-tab-label='Commit'"
     ">");

  {
    /******* Commit flags/options *******/
    CX("<div class='fileedit-options flex-container flex-row'>");
    style_labeled_checkbox("cb-dry-run",
                           "dry_run", "Dry-run?", "1", 1,
                           "In dry-run mode, the Save button performs "
                           "all work needed for saving but then rolls "







<


<







1883
1884
1885
1886
1887
1888
1889

1890
1891

1892
1893
1894
1895
1896
1897
1898
       "</div>");
    CX("</div>"/*#fileedit-tab-diff*/);
  }

  /****** Commit ******/
  CX("<div id='fileedit-tab-commit' "
     "data-tab-parent='fileedit-tabs' "

     "data-tab-label='Commit'"
     ">");

  {
    /******* Commit flags/options *******/
    CX("<div class='fileedit-options flex-container flex-row'>");
    style_labeled_checkbox("cb-dry-run",
                           "dry_run", "Dry-run?", "1", 1,
                           "In dry-run mode, the Save button performs "
                           "all work needed for saving but then rolls "
1946
1947
1948
1949
1950
1951
1952

1953

























1954
1955
1956

1957

1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973

1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
    CX("<div class='flex-container flex-column' "
       "id='fileedit-commit-button-wrapper'>"
       "<button id='fileedit-btn-commit'>Commit</button>"
       "</div>\n");
    CX("<div id='fileedit-manifest'></div>\n"
       /* Manifest gets rendered here after a commit. */);
  }



























  CX("</div>"/*#fileedit-tab-commit*/);

  {

    /* Dynamically populate the editor or display a warning

    ** about having no file loaded... */
    blob_appendf(&endScript,
                 "window.addEventListener('load',");
    if(zRev && zFilename){
      assert(0==blob_size(&err));
      blob_appendf(&endScript,
                   "()=>fossil.page.loadFile(\"%j\",'%j')",
                   zFilename, cimi.zParentUuid);
    }else{
      blob_appendf(&endScript,"function(){");
      if(blob_size(&err)>0){
        blob_appendf(&endScript,
                     "fossil.error(\"%j\");\n"
                     "fossil.page.tabs.switchToTab(0);\n",
                     blob_str(&err));
      }else{

        blob_appendf(&endScript,
                     "fossil.error('No file/version selected.')");
      }
      blob_appendf(&endScript,"}");
    }
    blob_appendf(&endScript,", false);\n");
  }

  if(stmt.pStmt){
    db_finalize(&stmt);







>

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

|
>
|
>
|











|
<

<
>
|
|
<







1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039

2040

2041
2042
2043

2044
2045
2046
2047
2048
2049
2050
    CX("<div class='flex-container flex-column' "
       "id='fileedit-commit-button-wrapper'>"
       "<button id='fileedit-btn-commit'>Commit</button>"
       "</div>\n");
    CX("<div id='fileedit-manifest'></div>\n"
       /* Manifest gets rendered here after a commit. */);
  }
  CX("</div>"/*#fileedit-tab-commit*/);

  /****** Help/Tips ******/
  CX("<div id='fileedit-tab-help' "
     "data-tab-parent='fileedit-tabs' "
     "data-tab-label='Help'"
     ">");
  {
    CX("<h1>Help &amp; Tips</h1>");
    CX("<ul>");
    CX("<li><strong>Only files matching the <code>fileedit-glob</code> "
       "</strong> repository setting can be edited online. That setting "
       "must be a comma- or newline-delimited list of glob patterns "
       "for files which may be edited online.</li>");
    CX("<li><strong>Clicking any links</strong> on this page will "
       "leave the page, <strong>losing any edits</strong>.</li>");
    CX("<li>Saving edits creates a new commit with a single modified "
       "file.</li>");
    CX("<li>\"Delta manifests\" (see the checkbox on the Commit tab) "
       "make for smaller commit records, especially in repositories "
       "with many files.</li>");
    CX("<li>The file selector allows, for usability's sake, only files "
       "in leaf checkins to be selected, but files may be edited via "
       "non-leaf checkins by passing them as the <code>filename</code> "
       "and <code>checkin</code> URL arguments to this page.</li>");
    CX("</ul>");
  }
  CX("</div>"/*#fileedit-tab-help*/);

  
  {
    /* Dynamically populate the editor, display a any error
    ** in the err blob, and/or switch to tab #0, where the file
    ** selector lives... */
    blob_appendf(&endScript,
                 "window.addEventListener('load',");
    if(zRev && zFilename){
      assert(0==blob_size(&err));
      blob_appendf(&endScript,
                   "()=>fossil.page.loadFile(\"%j\",'%j')",
                   zFilename, cimi.zParentUuid);
    }else{
      blob_appendf(&endScript,"function(){");
      if(blob_size(&err)>0){
        blob_appendf(&endScript,
                     "fossil.error(\"%j\");\n",

                     blob_str(&err));

      }
      blob_appendf(&endScript,
                   "fossil.page.tabs.switchToTab(0);\n");

      blob_appendf(&endScript,"}");
    }
    blob_appendf(&endScript,", false);\n");
  }

  if(stmt.pStmt){
    db_finalize(&stmt);
Changes to src/fossil.dom.js.
55
56
57
58
59
60
61


62
63
64
65
66
67
68
      f.rx = /(\s+|\s*,\s*)/;
    }
    return str ? str.split(f.rx) : [str];
  };
  
  dom.div = dom.createElemFactory('div');
  dom.p = dom.createElemFactory('p');


  dom.header = dom.createElemFactory('header');
  dom.footer = dom.createElemFactory('footer');
  dom.section = dom.createElemFactory('section');
  dom.span = dom.createElemFactory('span');
  dom.strong = dom.createElemFactory('strong');
  dom.em = dom.createElemFactory('em');
  dom.img = function(src){







>
>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
      f.rx = /(\s+|\s*,\s*)/;
    }
    return str ? str.split(f.rx) : [str];
  };
  
  dom.div = dom.createElemFactory('div');
  dom.p = dom.createElemFactory('p');
  dom.code = dom.createElemFactory('code');
  dom.pre = dom.createElemFactory('pre');
  dom.header = dom.createElemFactory('header');
  dom.footer = dom.createElemFactory('footer');
  dom.section = dom.createElemFactory('section');
  dom.span = dom.createElemFactory('span');
  dom.strong = dom.createElemFactory('strong');
  dom.em = dom.createElemFactory('em');
  dom.img = function(src){
Changes to src/fossil.page.fileedit.js.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80



81
82
83
84
85
86
87
      this.finfo.checkin = ciUuid;
      const selFiles = this.e.selectFiles;
      if(!ciUuid){
        D.clearElement(D.disable(selFiles, this.e.btnLoadFile));
        return this;
      }
      const onload = (response)=>{
        D.clearElement(D.enable(selFiles, this.e.btnLoadFile));
        D.append(
          D.clearElement(this.e.fileListLabel),
          "Editable files for ",
          D.a(F.repoUrl('timeline',{
            c: ciUuid
          }), F.hashDigits(ciUuid)),
          ':'
        );
        this.cache.files[response.checkin] = response;
        response.editableFiles.forEach(function(fn){
          D.option(selFiles, fn);
        });



      };
      const got = this.cache.files[ciUuid];
      if(got){
        onload(got);
        return this;
      }
      D.disable(selFiles,this.e.btnLoadFile);







|





|
<


|


>
>
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
      this.finfo.checkin = ciUuid;
      const selFiles = this.e.selectFiles;
      if(!ciUuid){
        D.clearElement(D.disable(selFiles, this.e.btnLoadFile));
        return this;
      }
      const onload = (response)=>{
        D.clearElement(selFiles, this.e.btnLoadFile);
        D.append(
          D.clearElement(this.e.fileListLabel),
          "Editable files for ",
          D.a(F.repoUrl('timeline',{
            c: ciUuid
          }), F.hashDigits(ciUuid))

        );
        this.cache.files[response.checkin] = response;
        response.editableFiles.forEach(function(fn,n){
          D.option(selFiles, fn);
        });
        if(selFiles.options.length){
          D.enable(selFiles, this.e.btnLoadFile);
        }
      };
      const got = this.cache.files[ciUuid];
      if(got){
        onload(got);
        return this;
      }
      D.disable(selFiles,this.e.btnLoadFile);
Changes to src/style.c.
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
       "};\n", hash_digits(0), hash_digits(1));
    /*
    ** fossil.page holds info about the current page. This is also
    ** where the current page "should" store any of its own
    ** page-specific state, and it is reserved for that purpose.
    */
    CX("window.fossil.page = {"
       "page:\"%T\""
       "};\n", g.zPath);
    CX("})();\n");
    /* The remaining fossil object bootstrap code is not dependent on
    ** C-runtime state... */
    if(asInline){
      CX("%s\n", builtin_text("fossil.bootstrap.js"));
    }







|







1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
       "};\n", hash_digits(0), hash_digits(1));
    /*
    ** fossil.page holds info about the current page. This is also
    ** where the current page "should" store any of its own
    ** page-specific state, and it is reserved for that purpose.
    */
    CX("window.fossil.page = {"
       "name:\"%T\""
       "};\n", g.zPath);
    CX("})();\n");
    /* The remaining fossil object bootstrap code is not dependent on
    ** C-runtime state... */
    if(asInline){
      CX("%s\n", builtin_text("fossil.bootstrap.js"));
    }