Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Moved C routines which emit fossil.XYZ JS APIs from style.c to builtin.c, and renamed appropriately. Added flag to output_text_with_line_numbers() to disable emit of JS (needed for fileedit preview, at a minimum). The experimental emitting of all fossil.XYZ APIs at once is now limited to bundled mode, as that's the only place it's potentially of benefit. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | misc-js-experiments |
| Files: | files | file ages | folders |
| SHA3-256: |
c515e5fd9f41fc3f311a74af3c598c28 |
| User & Date: | stephan 2020-08-24 22:20:00.157 |
Context
|
2020-08-24
| ||
| 22:46 | Improved cross-page caching of wikiedit/fileedit bundle, reducing those pages to a single request of 10-13k once cache is warm. Fixed non-bundled JS distribution of fileedit and wikiedit. check-in: 20c50cd1e5 user: stephan tags: misc-js-experiments | |
| 22:20 | Moved C routines which emit fossil.XYZ JS APIs from style.c to builtin.c, and renamed appropriately. Added flag to output_text_with_line_numbers() to disable emit of JS (needed for fileedit preview, at a minimum). The experimental emitting of all fossil.XYZ APIs at once is now limited to bundled mode, as that's the only place it's potentially of benefit. check-in: c515e5fd9f user: stephan tags: misc-js-experiments | |
| 20:49 | Experimentally added '?' help buttons in wikiedit. Experimentally emit all fossil.XYZ APIs, rather than selected ones, to test whether that reduces overall transmission together with caching. DOM init-time timing workarounds to get confirmer buttons to pin their sizes properly. check-in: 9edbb7eab1 user: stephan tags: misc-js-experiments | |
Changes
Changes to src/ajax.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | ** Emits JS code which initializes the ** fossil.page.previewModes object to a map of AJAX_RENDER_xxx values ** and symbolic names for use by client-side scripts. ** ** If addScriptTag is true then the output is wrapped in a SCRIPT tag ** with the current nonce, else no SCRIPT tag is emitted. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
** Emits JS code which initializes the
** fossil.page.previewModes object to a map of AJAX_RENDER_xxx values
** and symbolic names for use by client-side scripts.
**
** If addScriptTag is true then the output is wrapped in a SCRIPT tag
** with the current nonce, else no SCRIPT tag is emitted.
**
** Requires that builtin_emit_script_fossil_bootstrap() has already been
** called in order to initialize the window.fossil.page object.
*/
void ajax_emit_js_preview_modes(int addScriptTag){
if(addScriptTag){
style_emit_script_tag(0,0);
CX("\n");
}
|
| ︙ | ︙ | |||
129 130 131 132 133 134 135 |
safe_html_context(DOCSRC_FILE);
wiki_render_by_mimetype(pContent, zMime);
break;
default:{
const char *zContent = blob_str(pContent);
if(AJAX_PREVIEW_LINE_NUMBERS & flags){
output_text_with_line_numbers(zContent, blob_size(pContent),
| | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
safe_html_context(DOCSRC_FILE);
wiki_render_by_mimetype(pContent, zMime);
break;
default:{
const char *zContent = blob_str(pContent);
if(AJAX_PREVIEW_LINE_NUMBERS & flags){
output_text_with_line_numbers(zContent, blob_size(pContent),
zName, "on", 0);
}else{
const char *zExt = strrchr(zName,'.');
if(zExt && zExt[1]){
CX("<pre><code class='language-%s'>%h</code></pre>",
zExt+1, zContent);
}else{
CX("<pre>%h</pre>", zContent);
|
| ︙ | ︙ |
Changes to src/attach.c.
| ︙ | ︙ | |||
615 616 617 618 619 620 621 |
blob_zero(&attach);
if( fShowContent ){
const char *z;
content_get(ridSrc, &attach);
blob_to_utf8_no_bom(&attach, 0);
z = blob_str(&attach);
if( zLn ){
| | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
blob_zero(&attach);
if( fShowContent ){
const char *z;
content_get(ridSrc, &attach);
blob_to_utf8_no_bom(&attach, 0);
z = blob_str(&attach);
if( zLn ){
output_text_with_line_numbers(z, blob_size(&attach), zName, zLn, 1);
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
|
| ︙ | ︙ |
Changes to src/builtin.c.
| ︙ | ︙ | |||
256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
if( strcmp(zMode, "bundled")==0 ){
builtin.eDelivery = JS_BUNDLED;
}else if( !bSilent ){
fossil_fatal("unknown javascript delivery mode \"%s\" - should be"
" one of: inline separate bundled", zMode);
}
}
/*
** The caller wants the Javascript file named by zFilename to be
** included in the generated page. Add the file to the queue of
** requested javascript resources, if it is not there already.
**
** The current implementation queues the file to be included in the
| > > > > > > > > | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
if( strcmp(zMode, "bundled")==0 ){
builtin.eDelivery = JS_BUNDLED;
}else if( !bSilent ){
fossil_fatal("unknown javascript delivery mode \"%s\" - should be"
" one of: inline separate bundled", zMode);
}
}
/*
** Returns the current JS delivery mode: one of JS_INLINE,
** JS_SEPARATE, JS_BUNDLED.
*/
int builtin_get_js_delivery_mode(void){
return builtin.eDelivery;
}
/*
** The caller wants the Javascript file named by zFilename to be
** included in the generated page. Add the file to the queue of
** requested javascript resources, if it is not there already.
**
** The current implementation queues the file to be included in the
|
| ︙ | ︙ | |||
557 558 559 560 561 562 563 |
*/
int builtin_vtab_register(sqlite3 *db){
int rc = sqlite3_create_module(db, "builtin", &builtinVtabModule, 0);
return rc;
}
/* End of the builtin virtual table
******************************************************************************/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
*/
int builtin_vtab_register(sqlite3 *db){
int rc = sqlite3_create_module(db, "builtin", &builtinVtabModule, 0);
return rc;
}
/* End of the builtin virtual table
******************************************************************************/
/*
** The first time this is called, it emits code to install and
** bootstrap the window.fossil object, using the built-in file
** fossil.bootstrap.js (not to be confused with bootstrap.js).
**
** Subsequent calls are no-ops.
**
** It emits 2 parts:
**
** 1) window.fossil core object, some of which depends on C-level
** runtime data. That part of the script is always emitted inline. If
** addScriptTag is true then it is wrapped in its own SCRIPT tag, else
** it is assumed that the caller already opened a tag.
**
** 2) Emits the static fossil.bootstrap.js using builtin_request_js().
*/
void builtin_emit_script_fossil_bootstrap(int addScriptTag){
static int once = 0;
if(0==once++){
char * zName;
/* Set up the generic/app-agnostic parts of window.fossil
** which require C-level state... */
if(addScriptTag!=0){
style_emit_script_tag(0,0);
}
CX("(function(){\n");
CX(/*MSIE NodeList.forEach polyfill, courtesy of Mozilla:
https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#Polyfill
*/
"if(window.NodeList && !NodeList.prototype.forEach){"
"NodeList.prototype.forEach = Array.prototype.forEach;"
"}\n");
CX("if(!window.fossil) window.fossil={};\n"
"window.fossil.version = %!j;\n"
/* fossil.rootPath is the top-most CGI/server path,
** including a trailing slash. */
"window.fossil.rootPath = %!j+'/';\n",
get_version(), g.zTop);
/* fossil.config = {...various config-level options...} */
CX("window.fossil.config = {");
zName = db_get("project-name", "");
CX("projectName: %!j,\n", zName);
fossil_free(zName);
zName = db_get("short-project-name", "");
CX("shortProjectName: %!j,\n", zName);
fossil_free(zName);
zName = db_get("project-code", "");
CX("projectCode: %!j,\n", zName);
fossil_free(zName);
CX("/* Length of UUID hashes for display purposes. */");
CX("hashDigits: %d, hashDigitsUrl: %d,\n",
hash_digits(0), hash_digits(1));
CX("editStateMarkers: {"
"/*Symbolic markers to denote certain edit states.*/"
"isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
CX("confirmerButtonTicks: 3 "
"/*default fossil.confirmer tick count.*/\n");
CX("};\n"/* fossil.config */);
#if 0
/* Is it safe to emit the CSRF token here? Some pages add it
** as a hidden form field. */
if(g.zCsrfToken[0]!=0){
CX("window.fossil.csrfToken = %!j;\n",
g.zCsrfToken);
}
#endif
/*
** 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");
if(addScriptTag!=0){
style_emit_script_tag(1,0);
}
/* The remaining window.fossil bootstrap code is not dependent on
** C-runtime state... */
builtin_request_js("fossil.bootstrap.js");
}
}
/*
** Convenience wrapper which calls builtin_request_js() for a series
** of builtin scripts named fossil.NAME.js. The first time it is
** called, it also calls builtin_emit_script_fossil_bootstrap() to
** initialize the window.fossil JS API. The first argument is the NAME
** part of the first API to emit. All subsequent arguments must be
** strings of the NAME part of additional fossil.NAME.js files,
** followed by a NULL argument to terminate the list.
**
** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3
** APIs. Do not forget the trailing 0!
*/
void builtin_emit_fossil_js_apis( const char * zApi, ... ) {
static int once = 0;
const char *zArg;
char * zName;
va_list vargs;
if(0==once++){
builtin_emit_script_fossil_bootstrap(1);
}
zName = mprintf("fossil.%s.js", zApi);
builtin_request_js(zName);
fossil_free(zName);
va_start(vargs,zApi);
while( (zArg = va_arg (vargs, const char *))!=0 ){
zName = mprintf("fossil.%s.js", zArg);
builtin_request_js(zName);
fossil_free(zName);
}
va_end(vargs);
}
/*
** If builtin_get_js_delivery_mode() returns JS_BUNDLED then this
** function emits, via builtin_request_js(), all JS fossil.XYZ APIs
** which are not strictly specific to a single page, and then calls
** builtin_fulfill_js_requests(). The idea is that we can get better
** bundle caching and reduced HTTP requests by including all JS,
** rather than creating separate bundles on a per-page basis. It then
** returns true. As a special case, if this is called more than once
** in bundled mode, subsequent calls are a no-op.
**
** If the current JS delivery mode is *not* JS_BUNDLED then this
** function is a no-op and returns false.
*/
int builtin_bundle_all_fossil_js_apis(void){
static int bundled = 0;
if(JS_BUNDLED == builtin_get_js_delivery_mode()){
if(!bundled){
bundled = 1;
builtin_emit_fossil_js_apis("dom", "fetch",
"storage", "tabs",
"confirmer", "popupwidget",
"copybutton", "numbered-lines",
0);
builtin_fulfill_js_requests();
}
return 1;
}else{
return 0;
}
}
|
Changes to src/default.css.
| ︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | display: inline-block; min-width: 1rem; max-width: 1rem; min-height: 1rem; max-height: 1rem; font-size: 0.9em; border-radius: 0.5rem; | | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | display: inline-block; min-width: 1rem; max-width: 1rem; min-height: 1rem; max-height: 1rem; font-size: 0.9em; border-radius: 0.5rem; background-color: rgba(54, 54, 255,1); color: rgb(255, 255, 255); cursor: pointer; font-family: monspace; text-align: center; margin: 0 0 0 0.35em; border-width: 1px; border-style: outset; |
| ︙ | ︙ |
Changes to src/fileedit.c.
| ︙ | ︙ | |||
1703 1704 1705 1706 1707 1708 1709 |
{
CX("<div id='fileedit-tab-content' "
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Content' "
"class='hidden'"
">");
CX("<div class='flex-container flex-row child-gap-small'>");
| > | > > | | > | | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
{
CX("<div id='fileedit-tab-content' "
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Content' "
"class='hidden'"
">");
CX("<div class='flex-container flex-row child-gap-small'>");
CX("<div class='input-with-label'>"
"<button class='fileedit-content-reload confirmer' "
">Discard & Reload</button>"
"<div class='help-buttonlet'>"
"Reload the file from the server, discarding "
"any local edits. To help avoid accidental loss of "
"edits, it requires confirmation (a second click) within "
"a few seconds or it will not reload."
"</div>"
"</div>");
style_select_list_int("select-font-size",
"editor_font_size", "Editor font size",
NULL/*tooltip*/,
100,
"100%", 100, "125%", 125,
"150%", 150, "175%", 175,
"200%", 200, NULL);
|
| ︙ | ︙ | |||
1744 1745 1746 1747 1748 1749 1750 |
** the text editor with their own. */
"data-f-preview-via='_postPreview' "
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='#fileedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Toggle auto-update of preview when the Preview tab is selected. */
| > > | < | < > | | > > | 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 |
** the text editor with their own. */
"data-f-preview-via='_postPreview' "
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='#fileedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Toggle auto-update of preview when the Preview tab is selected. */
CX("<div class='input-with-label'>"
"<input type='checkbox' value='1' "
"id='cb-preview-autorefresh' checked>"
"<label for='cb-preview-autorefresh'>Auto-refresh?</label>"
"<div class='help-buttonlet'>"
"If on, the preview will automatically "
"refresh (if needed) when this tab is selected."
"</div>"
"</div>");
/* Default preview rendering mode selection... */
previewRenderMode = zFileMime
? ajax_render_mode_for_mimetype(zFileMime)
: AJAX_RENDER_GUESS;
style_select_list_int("select-preview-mode",
"preview_render_mode",
|
| ︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 |
"committing or force-reloading a file, local edits to that "
"file/check-in combination are discarded.</li>");
CX("</ul>");
}
CX("</div>"/*#fileedit-tab-help*/);
builtin_request_js("sbsdiff.js");
| | | | < < < < < < > | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 |
"committing or force-reloading a file, local edits to that "
"file/check-in combination are discarded.</li>");
CX("</ul>");
}
CX("</div>"/*#fileedit-tab-help*/);
builtin_request_js("sbsdiff.js");
if(!builtin_bundle_all_fossil_js_apis()){
builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
"storage", 0);
}
/*
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
** used for dynamically toggling certain UI components on and off.
** Must come after window.fossil has been intialized and before
** fossil.page.fileedit.js. Potential TODO: move this into the
** window.fossil bootstrapping so that we don't have to "fulfill"
** the JS multiple times.
|
| ︙ | ︙ |
Changes to src/forum.c.
| ︙ | ︙ | |||
802 803 804 805 806 807 808 |
style_submenu_checkbox("unf", "Unformatted", 0, 0);
style_submenu_checkbox("hist", "History", 0, 0);
/* Display the thread. */
forum_display_thread(froot, fpid, mode, bUnf, bHist);
/* Emit Forum Javascript. */
| | | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 |
style_submenu_checkbox("unf", "Unformatted", 0, 0);
style_submenu_checkbox("hist", "History", 0, 0);
/* Display the thread. */
forum_display_thread(froot, fpid, mode, bUnf, bHist);
/* Emit Forum Javascript. */
builtin_emit_script_fossil_bootstrap(1);
builtin_request_js("forum.js");
builtin_request_js("fossil.dom.js");
builtin_request_js("fossil.page.forumpost.js");
/* Emit the page style. */
style_footer();
}
|
| ︙ | ︙ |
Changes to src/fossil.bootstrap.js.
1 2 3 4 5 6 7 8 9 |
"use strict";
(function () {
/* CustomEvent polyfill, courtesy of Mozilla:
https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
*/
if(typeof window.CustomEvent === "function") return false;
window.CustomEvent = function(event, params) {
if(!params) params = {bubbles: false, cancelable: false, detail: null};
const evt = document.createEvent('CustomEvent');
| | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
"use strict";
(function () {
/* CustomEvent polyfill, courtesy of Mozilla:
https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
*/
if(typeof window.CustomEvent === "function") return false;
window.CustomEvent = function(event, params) {
if(!params) params = {bubbles: false, cancelable: false, detail: null};
const evt = document.createEvent('CustomEvent');
evt.initCustomEvent( event, !!params.bubbles, !!params.cancelable, params.detail );
return evt;
};
})();
(function(global){
/* Bootstrapping bits for the global.fossil object. Must be loaded
after style.c:builtin_emit_script_fossil_bootstrap() has
initialized that object.
*/
const F = global.fossil;
/**
Returns the current time in something approximating
ISO-8601 format.
|
| ︙ | ︙ |
Changes to src/fossil.page.fileedit.js.
| ︙ | ︙ | |||
462 463 464 465 466 467 468 |
e:{/*DOM element(s)*/},
init: function(domInsertPoint/*insert widget BEFORE this element*/){
const wrapper = D.addClass(
D.attr(D.div(),'id','fileedit-stash-selector'),
'input-with-label'
);
const sel = this.e.select = D.select();
| | > > > > > > > > | | | < < < < < | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
e:{/*DOM element(s)*/},
init: function(domInsertPoint/*insert widget BEFORE this element*/){
const wrapper = D.addClass(
D.attr(D.div(),'id','fileedit-stash-selector'),
'input-with-label'
);
const sel = this.e.select = D.select();
const btnClear = this.e.btnClear = D.button("Discard Edits"),
btnHelp = D.append(
D.addClass(D.div(), "help-buttonlet"),
'Locally-edited files. Timestamps are the last local edit time. ',
'Only the ',P.config.defaultMaxStashSize,' most recent files ',
'are retained. Saving or reloading a file removes it from this list. ',
D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
);
D.append(wrapper, "Local edits (",
D.append(D.code(),
F.storage.storageImplName()),
"):",
btnHelp, sel, btnClear);
F.helpButtonlets.setup(btnHelp);
D.option(D.disable(sel), "(empty)");
F.page.addEventListener('fileedit-stash-updated',(e)=>this.updateList(e.detail));
F.page.addEventListener('fileedit-file-loaded',(e)=>this.updateList($stash, e.detail));
sel.addEventListener('change',function(e){
const opt = this.selectedOptions[0];
if(opt && opt._finfo) P.loadFile(opt._finfo);
});
|
| ︙ | ︙ | |||
654 655 656 657 658 659 660 |
selectPreviewMode: E('#select-preview-mode select'),
selectHtmlEmsWrap: E('#select-preview-html-ems'),
selectEolWrap: E('#select-eol-style'),
selectEol: E('#select-eol-style select[name=eol]'),
selectFontSizeWrap: E('#select-font-size'),
selectDiffWS: E('select[name=diff_ws]'),
cbLineNumbersWrap: E('#cb-line-numbers'),
| | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
selectPreviewMode: E('#select-preview-mode select'),
selectHtmlEmsWrap: E('#select-preview-html-ems'),
selectEolWrap: E('#select-eol-style'),
selectEol: E('#select-eol-style select[name=eol]'),
selectFontSizeWrap: E('#select-font-size'),
selectDiffWS: E('select[name=diff_ws]'),
cbLineNumbersWrap: E('#cb-line-numbers'),
cbAutoPreview: E('#cb-preview-autorefresh'),
previewTarget: E('#fileedit-tab-preview-wrapper'),
manifestTarget: E('#fileedit-manifest'),
diffTarget: E('#fileedit-tab-diff-wrapper'),
cbIsExe: E('input[type=checkbox][name=exec_bit]'),
cbManifest: E('input[type=checkbox][name=include_manifest]'),
editStatus: E('#fileedit-edit-status'),
tabs:{
|
| ︙ | ︙ |
Changes to src/fossil.page.wikiedit.js.
| ︙ | ︙ | |||
846 847 848 849 850 851 852 |
taEditor: E('#wikiedit-content-editor'),
btnReload: E("#wikiedit-tab-content button.wikiedit-content-reload"),
btnSave: E("button.wikiedit-save"),
btnSaveClose: E("button.wikiedit-save-close"),
selectMimetype: E('select[name=mimetype]'),
selectFontSizeWrap: E('#select-font-size'),
// selectDiffWS: E('select[name=diff_ws]'),
| | | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
taEditor: E('#wikiedit-content-editor'),
btnReload: E("#wikiedit-tab-content button.wikiedit-content-reload"),
btnSave: E("button.wikiedit-save"),
btnSaveClose: E("button.wikiedit-save-close"),
selectMimetype: E('select[name=mimetype]'),
selectFontSizeWrap: E('#select-font-size'),
// selectDiffWS: E('select[name=diff_ws]'),
cbAutoPreview: E('#cb-preview-autorefresh'),
previewTarget: E('#wikiedit-tab-preview-wrapper'),
diffTarget: E('#wikiedit-tab-diff-wrapper'),
editStatus: E('#wikiedit-edit-status'),
tabContainer: E('#wikiedit-tabs'),
tabs:{
pageList: E('#wikiedit-tab-pages'),
content: E('#wikiedit-tab-content'),
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | ** the X part of a "language-X" CSS class on the generated CODE block. ** ** zLn is the ?ln= parameter for the HTTP query. If there is an argument, ** then highlight that line number and scroll to it once the page loads. ** If there are two line numbers, highlight the range of lines. ** Multiple ranges can be highlighed by adding additional line numbers ** separated by a non-digit character (also not one of [-,.]). */ void output_text_with_line_numbers( const char *z, int nZ, const char *zName, | > > > > > > > | > > | 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 2051 2052 2053 2054 2055 2056 2057 2058 |
** the X part of a "language-X" CSS class on the generated CODE block.
**
** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
** then highlight that line number and scroll to it once the page loads.
** If there are two line numbers, highlight the range of lines.
** Multiple ranges can be highlighed by adding additional line numbers
** separated by a non-digit character (also not one of [-,.]).
**
** If includeJS is true then the JS code associated with line
** numbering is also emitted, else it is not. If this routine is
** called multiple times in a single app run, the JS is emitted only
** once. Note that when using this routine to emit Ajax responses, the
** JS should be not be included, as it will not get imported properly
** into the response's rendering.
*/
void output_text_with_line_numbers(
const char *z,
int nZ,
const char *zName,
const char *zLn,
int includeJS
){
int iStart, iEnd; /* Start and end of region to highlight */
int n = 0; /* Current line number */
int i = 0; /* Loop index */
int iTop = 0; /* Scroll so that this line is on top of screen. */
int nLine = 0; /* content line count */
int nSpans = 0; /* number of distinct zLn spans */
const char *zExt = file_extension(zName);
static int emittedJS = 0; /* emitted shared JS yet? */
Stmt q;
iStart = iEnd = atoi(zLn);
db_multi_exec(
"CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
if( iStart>0 ){
do{
|
| ︙ | ︙ | |||
2113 2114 2115 2116 2117 2118 2119 |
if(zExt && *zExt){
cgi_printf("<code class='language-%h'>",zExt);
}else{
cgi_append_content("<code>", -1);
}
cgi_printf("%z", htmlize(z, nZ));
CX("</code></pre></td></tr></tbody></table>\n");
| > > | | | < > | | < < < > > | 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 |
if(zExt && *zExt){
cgi_printf("<code class='language-%h'>",zExt);
}else{
cgi_append_content("<code>", -1);
}
cgi_printf("%z", htmlize(z, nZ));
CX("</code></pre></td></tr></tbody></table>\n");
if(includeJS && !emittedJS){
emittedJS = 1;
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
builtin_request_js("scroll.js");
}
if(!builtin_bundle_all_fossil_js_apis()){
builtin_emit_fossil_js_apis("dom", "copybutton", "popupwidget",
"numbered-lines", 0);
}
}
}
/*
** COMMAND: test-line-numbers
**
** Usage: %fossil test-line-numbers FILE ?LN-SPEC?
**
|
| ︙ | ︙ | |||
2146 2147 2148 2149 2150 2151 2152 |
}
db_find_and_open_repository(0,0);
zFilename = g.argv[2];
fossil_print("%s %s\n", zFilename, zLn);
blob_read_from_file(&content, zFilename, ExtFILE);
output_text_with_line_numbers(blob_str(&content), blob_size(&content),
| | | 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 |
}
db_find_and_open_repository(0,0);
zFilename = g.argv[2];
fossil_print("%s %s\n", zFilename, zLn);
blob_read_from_file(&content, zFilename, ExtFILE);
output_text_with_line_numbers(blob_str(&content), blob_size(&content),
zFilename, zLn, 0);
blob_reset(&content);
fossil_print("%b\n", cgi_output_blob());
}
/*
** WEBPAGE: artifact
** WEBPAGE: file
|
| ︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 |
"SELECT name FROM mlink, filename"
" WHERE filename.fnid=mlink.fnid"
" AND mlink.fid=%d",
rid);
zExt = zFileName ? file_extension(zFileName) : 0;
if( zLn ){
output_text_with_line_numbers(z, blob_size(&content),
| | | 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 |
"SELECT name FROM mlink, filename"
" WHERE filename.fnid=mlink.fnid"
" AND mlink.fid=%d",
rid);
zExt = zFileName ? file_extension(zFileName) : 0;
if( zLn ){
output_text_with_line_numbers(z, blob_size(&content),
zFileName, zLn, 1);
}else if( zExt && zExt[1] ){
@ <pre>
@ <code class="language-%s(zExt)">%h(z)</code>
@ </pre>
}else{
@ <pre>
@ %h(z)
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 |
}
CX("</select>\n");
CX("</div>\n");
va_end(vargs);
fossil_free(zLabelID);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 |
}
CX("</select>\n");
CX("</div>\n");
va_end(vargs);
fossil_free(zLabelID);
}
/*
** If passed 0 as its first argument, it emits a script opener tag
** with this request's nonce. If passed non-0 it emits a script
** closing tag. Mnemonic for remembering the order in which to pass 0
** or 1 as the first argument to this function: 0 comes before 1.
**
** If passed 0 as its first argument and a non-NULL/non-empty zSrc,
|
| ︙ | ︙ | |||
1528 1529 1530 1531 1532 1533 1534 |
}else{
CX("<script nonce='%s'>", style_nonce());
}
}else{
CX("</script>\n");
}
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1443 1444 1445 1446 1447 1448 1449 |
}else{
CX("<script nonce='%s'>", style_nonce());
}
}else{
CX("</script>\n");
}
}
|
Changes to src/style.fileedit.css.
| ︙ | ︙ | |||
218 219 220 221 222 223 224 225 |
white-space: nowrap;
}
body.fileedit #fileedit-edit-status span.links > *::before {
content: "[";
}
body.fileedit #fileedit-edit-status span.links > *::after {
content: "]";
}
| > > > > > > > > > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
white-space: nowrap;
}
body.fileedit #fileedit-edit-status span.links > *::before {
content: "[";
}
body.fileedit #fileedit-edit-status span.links > *::after {
content: "]";
}
/* JS selection of line numbers cannot work in preview mode,
so disable the UI indications which imply that it does
something... */
body.fileedit table.numbered-lines td.line-numbers > span {
cursor: unset;
}
body.fileedit table.numbered-lines td.line-numbers > span:hover {
background-color: inherit;
}
|
Changes to src/style.wikiedit.css.
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
}
body.wikiedit #wikiedit-stash-selector select {
margin: 0 1em 0 0.5em;
height: initial;
font-family: monospace;
flex: 10 1 auto;
}
| < < | 187 188 189 190 191 192 193 194 195 196 197 198 199 |
}
body.wikiedit #wikiedit-stash-selector select {
margin: 0 1em 0 0.5em;
height: initial;
font-family: monospace;
flex: 10 1 auto;
}
body.wikiedit fieldset.page-types-list > div > span {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
}
|
Changes to src/wiki.c.
| ︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 |
"<button class='wikiedit-save'>"
"Save</button>"
"</div>" /*will get moved around dynamically*/);
CX("<div class='input-with-label'>"
"<button class='wikiedit-save-close'>"
"Save & Close</button>"
"<div class='help-buttonlet'>"
| | | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 |
"<button class='wikiedit-save'>"
"Save</button>"
"</div>" /*will get moved around dynamically*/);
CX("<div class='input-with-label'>"
"<button class='wikiedit-save-close'>"
"Save & Close</button>"
"<div class='help-buttonlet'>"
"Save edits to this page and returns to the wiki page viewer."
"</div>"
"</div>" /*will get moved around dynamically*/);
CX("<span class='save-button-slot'></span>");
CX("<div class='input-with-label'>"
"<button class='wikiedit-content-reload' "
">Discard & Reload</button>"
|
| ︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 |
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='#wikiedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Toggle auto-update of preview when the Preview tab is selected. */
CX("<div class='input-with-label'>"
"<input type='checkbox' value='1' "
| | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 |
/* ^^^ fossil.page[methodName](content, callback) */
"data-f-preview-to='#wikiedit-tab-preview-wrapper' "
/* ^^^ dest elem ID */
">Refresh</button>");
/* Toggle auto-update of preview when the Preview tab is selected. */
CX("<div class='input-with-label'>"
"<input type='checkbox' value='1' "
"id='cb-preview-autorefresh' checked>"
"<label for='cb-preview-autorefresh'>Auto-refresh?</label>"
"<div class='help-buttonlet'>"
"If on, the preview will automatically "
"refresh (if needed) when this tab is selected."
"</div>"
"</div>");
CX("<span class='save-button-slot'></span>");
CX("</div>"/*.wikiedit-options*/);
CX("<div id='wikiedit-tab-preview-wrapper'></div>");
CX("</div>"/*#wikiedit-tab-preview*/);
}
|
| ︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 |
"sandbox page will fail.</p>");
CX("<h2>Wiki Name Rules</h2>");
well_formed_wiki_name_rules();
CX("</div>"/*#wikiedit-tab-save*/);
}
builtin_request_js("sbsdiff.js");
| | | | < < < > < < | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 |
"sandbox page will fail.</p>");
CX("<h2>Wiki Name Rules</h2>");
well_formed_wiki_name_rules();
CX("</div>"/*#wikiedit-tab-save*/);
}
builtin_request_js("sbsdiff.js");
if(!builtin_bundle_all_fossil_js_apis()){
builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
"storage", "page.wikiedit", 0);
}
builtin_request_js("fossil.page.wikiedit.js");
/* Dynamically populate the editor... */
style_emit_script_tag(0,0);
{
/* Render the current page list to save us an XHR request
during page initialization. This must be OUTSIDE of
an onPageLoad() handler or else it does not get applied
until after the wiki list widget is initialized. Similarly,
|
| ︙ | ︙ |