Fossil SCM

The routines which emit fossil.XYZ.js modules now understand their dependencies, emit any deps in dependency order (recursively), and do not emit a given module more than once (simplifies usage and is an and overall improvement in cacheability). Added the pikchr click support to more pages.

stephan 2020-09-18 07:37 trunk
Commit 9b2b6f5b1cc695e52e89ae579850a4270115bbe43a64377743200fa9d82dcc58
--- src/browse.c
+++ src/browse.c
@@ -392,10 +392,11 @@
392392
Blob content;
393393
const char *zMime = mimetype_from_name(zName);
394394
content_get(rid, &content);
395395
safe_html_context(DOCSRC_FILE);
396396
wiki_render_by_mimetype(&content, zMime);
397
+ document_emit_js();
397398
}
398399
}
399400
}
400401
db_finalize(&q);
401402
style_footer();
402403
--- src/browse.c
+++ src/browse.c
@@ -392,10 +392,11 @@
392 Blob content;
393 const char *zMime = mimetype_from_name(zName);
394 content_get(rid, &content);
395 safe_html_context(DOCSRC_FILE);
396 wiki_render_by_mimetype(&content, zMime);
 
397 }
398 }
399 }
400 db_finalize(&q);
401 style_footer();
402
--- src/browse.c
+++ src/browse.c
@@ -392,10 +392,11 @@
392 Blob content;
393 const char *zMime = mimetype_from_name(zName);
394 content_get(rid, &content);
395 safe_html_context(DOCSRC_FILE);
396 wiki_render_by_mimetype(&content, zMime);
397 document_emit_js();
398 }
399 }
400 }
401 db_finalize(&q);
402 style_footer();
403
+168 -104
--- src/builtin.c
+++ src/builtin.c
@@ -662,10 +662,113 @@
662662
/* The remaining window.fossil bootstrap code is not dependent on
663663
** C-runtime state... */
664664
builtin_request_js("fossil.bootstrap.js");
665665
}
666666
}
667
+
668
+/*
669
+** Given the NAME part of fossil.NAME.js, this function checks whether
670
+** that module has been emitted by this function before. If it has,
671
+** it returns -1 with no side effects. If it has not, it queues up
672
+** (via builtin_request_js()) an emit of the module via and all of its
673
+** known (by this function) fossil.XYZ.js dependencies (in their
674
+** dependency order) and returns 1. If it does not find the given
675
+** module name it returns 0.
676
+**
677
+** As a special case, if passed 0 then it queues up all known modules
678
+** and returns -1.
679
+**
680
+** The very first time this is called, it unconditionally calls
681
+** builtin_emit_script_fossil_bootstrap().
682
+**
683
+** Any given module is only queued once, whether it is explicitly
684
+** passed to the function or resolved as a dependency. Any attempts to
685
+** re-queue them later are harmless no-ops.
686
+*/
687
+static int builtin_emit_fossil_js_once(const char * zName){
688
+ static int once = 0;
689
+ int i;
690
+ static struct FossilJs {
691
+ const char * zName; /* NAME part of fossil.NAME.js */
692
+ int emitted; /* True if already emitted. */
693
+ const char * zDeps; /* \0-delimited list of other FossilJs
694
+ ** entries: all known deps of this one. Each
695
+ ** REQUIRES an EXPLICIT trailing \0, including
696
+ ** the final one! */
697
+ } fjs[] = {
698
+ /* This list ordering isn't strictly important. */
699
+ {"confirmer", 0, 0},
700
+ {"copybutton", 0, "dom\0"},
701
+ {"dom", 0, 0},
702
+ {"fetch", 0, 0},
703
+ {"numbered-lines", 0, "popupwidget\0copybutton\0"},
704
+ {"pikchr", 0, "dom\0"},
705
+ {"popupwidget", 0, "dom\0"},
706
+ {"storage", 0, 0},
707
+ {"tabs", 0, "dom\0"}
708
+ };
709
+ const int nFjs = sizeof(fjs) / sizeof(fjs[0]);
710
+ if(0==once){
711
+ ++once;
712
+ builtin_emit_script_fossil_bootstrap(1);
713
+ }
714
+ if(0==zName){
715
+ for( i = 0; i < nFjs; ++i ){
716
+ builtin_emit_fossil_js_once(fjs[i].zName);
717
+ }
718
+ return 0;
719
+ }
720
+ for( i = 0; i < nFjs; ++i ){
721
+ if(0==strcmp(zName, fjs[i].zName)){
722
+ if(fjs[i].emitted){
723
+ return -1;
724
+ }else{
725
+ char nameBuffer[50];
726
+ if(fjs[i].zDeps){
727
+ const char * zDep = fjs[i].zDeps;
728
+ while(*zDep!=0){
729
+ builtin_emit_fossil_js_once(zDep);
730
+ zDep += strlen(zDep)+1/*NUL delimiter*/;
731
+ }
732
+ }
733
+ sqlite3_snprintf(sizeof(nameBuffer)-1, nameBuffer,
734
+ "fossil.%s.js", fjs[i].zName);
735
+ builtin_request_js(nameBuffer);
736
+ fjs[i].emitted = 1;
737
+ return 1;
738
+ }
739
+ }
740
+ }
741
+ return 0;
742
+}
743
+
744
+/*
745
+** COMMAND: test-js-once
746
+**
747
+** Tester for builtin_emit_fossil_js_once().
748
+**
749
+** Usage: %fossil test-js-once filename
750
+*/
751
+void test_js_once(void){
752
+ int i;
753
+ if(g.argc<2){
754
+ usage("?FILENAME...?");
755
+ }
756
+ if(2==g.argc){
757
+ builtin_emit_fossil_js_once(0);
758
+ assert(builtin.nReq>8);
759
+ }else{
760
+ for(i = 2; i < g.argc; ++i){
761
+ builtin_emit_fossil_js_once(g.argv[i]);
762
+ }
763
+ assert(builtin.nReq>1 && "don't forget implicit fossil.bootstrap.js");
764
+ }
765
+ for(i = 0; i < builtin.nReq; ++i){
766
+ fossil_print("ndx#%d = %d = %s\n", i, builtin.aReq[i],
767
+ aBuiltinFiles[builtin.aReq[i]].zName);
768
+ }
769
+}
667770
668771
/*
669772
** Convenience wrapper which calls builtin_request_js() for a series
670773
** of builtin scripts named fossil.NAME.js. The first time it is
671774
** called, it also calls builtin_emit_script_fossil_bootstrap() to
@@ -672,101 +775,57 @@
672775
** initialize the window.fossil JS API. The first argument is the NAME
673776
** part of the first API to emit. All subsequent arguments must be
674777
** strings of the NAME part of additional fossil.NAME.js files,
675778
** followed by a NULL argument to terminate the list.
676779
**
677
-** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3
678
-** APIs. Do not forget the trailing 0!
780
+** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3 APIs (or
781
+** pass it ("fetch","tabs",0), as "dom" is a dependency of "tabs", so
782
+** it will be automatically loaded). Do not forget the trailing 0!
783
+**
784
+** If it is JS_BUNDLED then this routine queues up an emit of ALL of
785
+** the JS fossil.XYZ.js APIs which are not strictly specific to a
786
+** single page, and then calls builtin_fulfill_js_requests(). The idea
787
+** is that we can get better bundle caching and reduced HTTP requests
788
+** by including all JS, rather than creating separate bundles on a
789
+** per-page basis. In this case, all arguments are ignored!
790
+**
791
+** This function has an internal mapping of the dependencies for each
792
+** of the known fossil.XYZ.js modules and ensures that the
793
+** dependencies also get queued (recursively) and that each module is
794
+** queued only once.
795
+**
796
+** If passed a name which is not a base fossil module name then it
797
+** will fail fatally!
798
+**
799
+** DO NOT use this for loading fossil.page.*.js: use
800
+** builtin_request_js() for those.
801
+**
802
+** If the current JS delivery mode is *not* JS_BUNDLED then this
803
+** function queues up a request for each given module and its known
804
+** dependencies, but does not immediately fulfill the request, thus it
805
+** can be called multiple times.
806
+**
807
+** If a given module is ever passed to this more than once, either in
808
+** a single invocation or multiples, it is only queued for emit a
809
+** single time (i.e. the 2nd and subsequent ones become
810
+** no-ops). Likewise, if a module is requested but was already
811
+** automatically queued to fulfill a dependency, the explicit request
812
+** becomes a no-op.
813
+**
814
+** Bundled mode is the only mode in which this API greatly improves
815
+** aggregate over-the-wire and HTTP request costs. For other modes,
816
+** reducing the inclusion of fossil.XYZ APIs to their bare minimum
817
+** provides the lowest aggregate costs. For debate and details, see
818
+** the discussion at:
819
+**
820
+** https://fossil-scm.org/forum/forumpost/3fa2633f3e
679821
**
680822
** In practice it is normally necessary (or preferred) to call
681823
** builtin_fulfill_js_requests() after calling this, before proceeding
682824
** to call builtin_request_js() for page-specific JS, in order to
683825
** improve cachability.
684826
**
685
-** Achtung: the fossil.page.XYZ.js files are page-specific, containing
686
-** the app-level logic for that specific page, and loading more than
687
-** one of them in a single pagee will break that page. Each of those
688
-** expects to "own" the page it is loaded in, and it should be loaded
689
-** as late in the JS-loading process as feasible, ideally bundled (via
690
-** builtin_request_js()) with any other app-/page-specific JS it may
691
-** need.
692
-*/
693
-void builtin_emit_fossil_js_apis( const char * zApi, ... ) {
694
- static int once = 0;
695
- const char *zArg;
696
- char * zName;
697
- va_list vargs;
698
-
699
- if(0==once++){
700
- builtin_emit_script_fossil_bootstrap(1);
701
- }
702
- zName = mprintf("fossil.%s.js", zApi);
703
- builtin_request_js(zName);
704
- fossil_free(zName);
705
- va_start(vargs,zApi);
706
- while( (zArg = va_arg (vargs, const char *))!=0 ){
707
- zName = mprintf("fossil.%s.js", zArg);
708
- builtin_request_js(zName);
709
- fossil_free(zName);
710
- }
711
- va_end(vargs);
712
-}
713
-
714
-/*
715
-** This is a variant of builtin_emit_fossil_js_apis() which is
716
-** equivalent to:
717
-**
718
-** if(!builtin_bundle_all_fossil_js_apis()){
719
-** builtin_emit_fossil_js_apis(zApi, ...args);
720
-** }
721
-**
722
-*/
723
-void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
724
- const char *zArg;
725
- char * zName;
726
- va_list vargs;
727
- static int once = 0;
728
-
729
- if(builtin_bundle_all_fossil_js_apis()){
730
- return;
731
- }
732
- if(0==once++){
733
- builtin_emit_script_fossil_bootstrap(1);
734
- }
735
- zName = mprintf("fossil.%s.js", zApi);
736
- builtin_request_js(zName);
737
- fossil_free(zName);
738
- va_start(vargs,zApi);
739
- while( (zArg = va_arg (vargs, const char *))!=0 ){
740
- zName = mprintf("fossil.%s.js", zArg);
741
- builtin_request_js(zName);
742
- fossil_free(zName);
743
- }
744
- va_end(vargs);
745
-}
746
-
747
-
748
-/*
749
-** If builtin_get_js_delivery_mode() returns JS_BUNDLED then this
750
-** function emits, via builtin_request_js(), all JS fossil.XYZ APIs
751
-** which are not strictly specific to a single page, and then calls
752
-** builtin_fulfill_js_requests(). The idea is that we can get better
753
-** bundle caching and reduced HTTP requests by including all JS,
754
-** rather than creating separate bundles on a per-page basis. It then
755
-** returns true. As a special case, if this is called more than once
756
-** in bundled mode, subsequent calls are a no-op.
757
-**
758
-** If the current JS delivery mode is *not* JS_BUNDLED then this
759
-** function is a no-op and returns false. The reason is simply because
760
-** bundled mode is the only mode in which this API improves aggregate
761
-** over-the-wire and HTTP request costs. For other modes, reducing the
762
-** inclusion of fossil.XYZ APIs to their bare minimum provides the
763
-** lowest aggregate costs. For debate and details, see the discussion
764
-** at:
765
-**
766
-** https://fossil-scm.org/forum/forumpost/3fa2633f3e
767
-**
768827
** Minor caveat: the purpose of emitting all of the fossil.XYZ JS APIs
769828
** at once is to reduce over-the-wire transfers by enabling cross-page
770829
** caching, but if there are other JS scripts pending via
771830
** builtin_request_js() when this is called then they will be included
772831
** in the JS request emitted by this routine, resulting in a different
@@ -773,39 +832,44 @@
773832
** script URL than if they were not included. Thus, if a given page
774833
** has its own scripts to install via builtin_request_js(), they
775834
** should, if possible, be delayed until after this is called OR the
776835
** page should call builtin_fulfill_js_requests() to flush the request
777836
** queue before calling this routine.
837
+**
838
+** Achtung: the fossil.page.XYZ.js files are page-specific, containing
839
+** the app-level logic for that specific page, and loading more than
840
+** one of them in a single page will break that page. Each of those
841
+** expects to "own" the page it is loaded in, and it should be loaded
842
+** as late in the JS-loading process as feasible, ideally bundled (via
843
+** builtin_request_js()) with any other app-/page-specific JS it may
844
+** need.
778845
**
779846
** Example usage:
780847
**
781
-** if(!builtin_bundle_all_fossil_js_apis()){
782
-** builtin_emit_fossil_js_apis("dom", "fetch", 0);
783
-** }
848
+** builtin_fossil_js_bundle_or("dom", "fetch", 0);
784849
**
785
-** In bundled mode, that will emit all builtin fossil JS APIs, and in
850
+** In bundled mode, that will (the first time it is called) emit all
851
+** builtin fossil JS APIs and "fulfill" the queue immediately. In
786852
** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
787853
** emitted the next time builtin_fulfill_js_requests() is called.
788854
*/
789
-int builtin_bundle_all_fossil_js_apis(void){
855
+void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
790856
static int bundled = 0;
857
+ const char *zArg;
858
+ va_list vargs;
859
+
791860
if(JS_BUNDLED == builtin_get_js_delivery_mode()){
792861
if(!bundled){
793862
bundled = 1;
794
- builtin_emit_fossil_js_apis(
795
- /* The order of the following arguments is important: any
796
- which have dependencies must be listed after their
797
- dependencies. ALL of them depend on the core window.fossil
798
- bootstrapping bits, and those are initialize by this
799
- call. */
800
- "dom", "fetch", "storage", "tabs",
801
- "confirmer", "popupwidget",
802
- "copybutton", "numbered-lines",
803
- "pikchr",
804
- 0);
863
+ builtin_emit_fossil_js_once(0);
805864
builtin_fulfill_js_requests();
806865
}
807
- return 1;
808
- }else{
809
- return 0;
866
+ return;
867
+ }
868
+ va_start(vargs,zApi);
869
+ for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){
870
+ if(0==builtin_emit_fossil_js_once(zArg)){
871
+ fossil_fatal("Unknown fossil JS module: %s\n", zArg);
872
+ }
810873
}
874
+ va_end(vargs);
811875
}
812876
--- src/builtin.c
+++ src/builtin.c
@@ -662,10 +662,113 @@
662 /* The remaining window.fossil bootstrap code is not dependent on
663 ** C-runtime state... */
664 builtin_request_js("fossil.bootstrap.js");
665 }
666 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
668 /*
669 ** Convenience wrapper which calls builtin_request_js() for a series
670 ** of builtin scripts named fossil.NAME.js. The first time it is
671 ** called, it also calls builtin_emit_script_fossil_bootstrap() to
@@ -672,101 +775,57 @@
672 ** initialize the window.fossil JS API. The first argument is the NAME
673 ** part of the first API to emit. All subsequent arguments must be
674 ** strings of the NAME part of additional fossil.NAME.js files,
675 ** followed by a NULL argument to terminate the list.
676 **
677 ** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3
678 ** APIs. Do not forget the trailing 0!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679 **
680 ** In practice it is normally necessary (or preferred) to call
681 ** builtin_fulfill_js_requests() after calling this, before proceeding
682 ** to call builtin_request_js() for page-specific JS, in order to
683 ** improve cachability.
684 **
685 ** Achtung: the fossil.page.XYZ.js files are page-specific, containing
686 ** the app-level logic for that specific page, and loading more than
687 ** one of them in a single pagee will break that page. Each of those
688 ** expects to "own" the page it is loaded in, and it should be loaded
689 ** as late in the JS-loading process as feasible, ideally bundled (via
690 ** builtin_request_js()) with any other app-/page-specific JS it may
691 ** need.
692 */
693 void builtin_emit_fossil_js_apis( const char * zApi, ... ) {
694 static int once = 0;
695 const char *zArg;
696 char * zName;
697 va_list vargs;
698
699 if(0==once++){
700 builtin_emit_script_fossil_bootstrap(1);
701 }
702 zName = mprintf("fossil.%s.js", zApi);
703 builtin_request_js(zName);
704 fossil_free(zName);
705 va_start(vargs,zApi);
706 while( (zArg = va_arg (vargs, const char *))!=0 ){
707 zName = mprintf("fossil.%s.js", zArg);
708 builtin_request_js(zName);
709 fossil_free(zName);
710 }
711 va_end(vargs);
712 }
713
714 /*
715 ** This is a variant of builtin_emit_fossil_js_apis() which is
716 ** equivalent to:
717 **
718 ** if(!builtin_bundle_all_fossil_js_apis()){
719 ** builtin_emit_fossil_js_apis(zApi, ...args);
720 ** }
721 **
722 */
723 void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
724 const char *zArg;
725 char * zName;
726 va_list vargs;
727 static int once = 0;
728
729 if(builtin_bundle_all_fossil_js_apis()){
730 return;
731 }
732 if(0==once++){
733 builtin_emit_script_fossil_bootstrap(1);
734 }
735 zName = mprintf("fossil.%s.js", zApi);
736 builtin_request_js(zName);
737 fossil_free(zName);
738 va_start(vargs,zApi);
739 while( (zArg = va_arg (vargs, const char *))!=0 ){
740 zName = mprintf("fossil.%s.js", zArg);
741 builtin_request_js(zName);
742 fossil_free(zName);
743 }
744 va_end(vargs);
745 }
746
747
748 /*
749 ** If builtin_get_js_delivery_mode() returns JS_BUNDLED then this
750 ** function emits, via builtin_request_js(), all JS fossil.XYZ APIs
751 ** which are not strictly specific to a single page, and then calls
752 ** builtin_fulfill_js_requests(). The idea is that we can get better
753 ** bundle caching and reduced HTTP requests by including all JS,
754 ** rather than creating separate bundles on a per-page basis. It then
755 ** returns true. As a special case, if this is called more than once
756 ** in bundled mode, subsequent calls are a no-op.
757 **
758 ** If the current JS delivery mode is *not* JS_BUNDLED then this
759 ** function is a no-op and returns false. The reason is simply because
760 ** bundled mode is the only mode in which this API improves aggregate
761 ** over-the-wire and HTTP request costs. For other modes, reducing the
762 ** inclusion of fossil.XYZ APIs to their bare minimum provides the
763 ** lowest aggregate costs. For debate and details, see the discussion
764 ** at:
765 **
766 ** https://fossil-scm.org/forum/forumpost/3fa2633f3e
767 **
768 ** Minor caveat: the purpose of emitting all of the fossil.XYZ JS APIs
769 ** at once is to reduce over-the-wire transfers by enabling cross-page
770 ** caching, but if there are other JS scripts pending via
771 ** builtin_request_js() when this is called then they will be included
772 ** in the JS request emitted by this routine, resulting in a different
@@ -773,39 +832,44 @@
773 ** script URL than if they were not included. Thus, if a given page
774 ** has its own scripts to install via builtin_request_js(), they
775 ** should, if possible, be delayed until after this is called OR the
776 ** page should call builtin_fulfill_js_requests() to flush the request
777 ** queue before calling this routine.
 
 
 
 
 
 
 
 
778 **
779 ** Example usage:
780 **
781 ** if(!builtin_bundle_all_fossil_js_apis()){
782 ** builtin_emit_fossil_js_apis("dom", "fetch", 0);
783 ** }
784 **
785 ** In bundled mode, that will emit all builtin fossil JS APIs, and in
 
786 ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
787 ** emitted the next time builtin_fulfill_js_requests() is called.
788 */
789 int builtin_bundle_all_fossil_js_apis(void){
790 static int bundled = 0;
 
 
 
791 if(JS_BUNDLED == builtin_get_js_delivery_mode()){
792 if(!bundled){
793 bundled = 1;
794 builtin_emit_fossil_js_apis(
795 /* The order of the following arguments is important: any
796 which have dependencies must be listed after their
797 dependencies. ALL of them depend on the core window.fossil
798 bootstrapping bits, and those are initialize by this
799 call. */
800 "dom", "fetch", "storage", "tabs",
801 "confirmer", "popupwidget",
802 "copybutton", "numbered-lines",
803 "pikchr",
804 0);
805 builtin_fulfill_js_requests();
806 }
807 return 1;
808 }else{
809 return 0;
 
 
 
 
810 }
 
811 }
812
--- src/builtin.c
+++ src/builtin.c
@@ -662,10 +662,113 @@
662 /* The remaining window.fossil bootstrap code is not dependent on
663 ** C-runtime state... */
664 builtin_request_js("fossil.bootstrap.js");
665 }
666 }
667
668 /*
669 ** Given the NAME part of fossil.NAME.js, this function checks whether
670 ** that module has been emitted by this function before. If it has,
671 ** it returns -1 with no side effects. If it has not, it queues up
672 ** (via builtin_request_js()) an emit of the module via and all of its
673 ** known (by this function) fossil.XYZ.js dependencies (in their
674 ** dependency order) and returns 1. If it does not find the given
675 ** module name it returns 0.
676 **
677 ** As a special case, if passed 0 then it queues up all known modules
678 ** and returns -1.
679 **
680 ** The very first time this is called, it unconditionally calls
681 ** builtin_emit_script_fossil_bootstrap().
682 **
683 ** Any given module is only queued once, whether it is explicitly
684 ** passed to the function or resolved as a dependency. Any attempts to
685 ** re-queue them later are harmless no-ops.
686 */
687 static int builtin_emit_fossil_js_once(const char * zName){
688 static int once = 0;
689 int i;
690 static struct FossilJs {
691 const char * zName; /* NAME part of fossil.NAME.js */
692 int emitted; /* True if already emitted. */
693 const char * zDeps; /* \0-delimited list of other FossilJs
694 ** entries: all known deps of this one. Each
695 ** REQUIRES an EXPLICIT trailing \0, including
696 ** the final one! */
697 } fjs[] = {
698 /* This list ordering isn't strictly important. */
699 {"confirmer", 0, 0},
700 {"copybutton", 0, "dom\0"},
701 {"dom", 0, 0},
702 {"fetch", 0, 0},
703 {"numbered-lines", 0, "popupwidget\0copybutton\0"},
704 {"pikchr", 0, "dom\0"},
705 {"popupwidget", 0, "dom\0"},
706 {"storage", 0, 0},
707 {"tabs", 0, "dom\0"}
708 };
709 const int nFjs = sizeof(fjs) / sizeof(fjs[0]);
710 if(0==once){
711 ++once;
712 builtin_emit_script_fossil_bootstrap(1);
713 }
714 if(0==zName){
715 for( i = 0; i < nFjs; ++i ){
716 builtin_emit_fossil_js_once(fjs[i].zName);
717 }
718 return 0;
719 }
720 for( i = 0; i < nFjs; ++i ){
721 if(0==strcmp(zName, fjs[i].zName)){
722 if(fjs[i].emitted){
723 return -1;
724 }else{
725 char nameBuffer[50];
726 if(fjs[i].zDeps){
727 const char * zDep = fjs[i].zDeps;
728 while(*zDep!=0){
729 builtin_emit_fossil_js_once(zDep);
730 zDep += strlen(zDep)+1/*NUL delimiter*/;
731 }
732 }
733 sqlite3_snprintf(sizeof(nameBuffer)-1, nameBuffer,
734 "fossil.%s.js", fjs[i].zName);
735 builtin_request_js(nameBuffer);
736 fjs[i].emitted = 1;
737 return 1;
738 }
739 }
740 }
741 return 0;
742 }
743
744 /*
745 ** COMMAND: test-js-once
746 **
747 ** Tester for builtin_emit_fossil_js_once().
748 **
749 ** Usage: %fossil test-js-once filename
750 */
751 void test_js_once(void){
752 int i;
753 if(g.argc<2){
754 usage("?FILENAME...?");
755 }
756 if(2==g.argc){
757 builtin_emit_fossil_js_once(0);
758 assert(builtin.nReq>8);
759 }else{
760 for(i = 2; i < g.argc; ++i){
761 builtin_emit_fossil_js_once(g.argv[i]);
762 }
763 assert(builtin.nReq>1 && "don't forget implicit fossil.bootstrap.js");
764 }
765 for(i = 0; i < builtin.nReq; ++i){
766 fossil_print("ndx#%d = %d = %s\n", i, builtin.aReq[i],
767 aBuiltinFiles[builtin.aReq[i]].zName);
768 }
769 }
770
771 /*
772 ** Convenience wrapper which calls builtin_request_js() for a series
773 ** of builtin scripts named fossil.NAME.js. The first time it is
774 ** called, it also calls builtin_emit_script_fossil_bootstrap() to
@@ -672,101 +775,57 @@
775 ** initialize the window.fossil JS API. The first argument is the NAME
776 ** part of the first API to emit. All subsequent arguments must be
777 ** strings of the NAME part of additional fossil.NAME.js files,
778 ** followed by a NULL argument to terminate the list.
779 **
780 ** e.g. pass it ("fetch", "dom", "tabs", 0) to load those 3 APIs (or
781 ** pass it ("fetch","tabs",0), as "dom" is a dependency of "tabs", so
782 ** it will be automatically loaded). Do not forget the trailing 0!
783 **
784 ** If it is JS_BUNDLED then this routine queues up an emit of ALL of
785 ** the JS fossil.XYZ.js APIs which are not strictly specific to a
786 ** single page, and then calls builtin_fulfill_js_requests(). The idea
787 ** is that we can get better bundle caching and reduced HTTP requests
788 ** by including all JS, rather than creating separate bundles on a
789 ** per-page basis. In this case, all arguments are ignored!
790 **
791 ** This function has an internal mapping of the dependencies for each
792 ** of the known fossil.XYZ.js modules and ensures that the
793 ** dependencies also get queued (recursively) and that each module is
794 ** queued only once.
795 **
796 ** If passed a name which is not a base fossil module name then it
797 ** will fail fatally!
798 **
799 ** DO NOT use this for loading fossil.page.*.js: use
800 ** builtin_request_js() for those.
801 **
802 ** If the current JS delivery mode is *not* JS_BUNDLED then this
803 ** function queues up a request for each given module and its known
804 ** dependencies, but does not immediately fulfill the request, thus it
805 ** can be called multiple times.
806 **
807 ** If a given module is ever passed to this more than once, either in
808 ** a single invocation or multiples, it is only queued for emit a
809 ** single time (i.e. the 2nd and subsequent ones become
810 ** no-ops). Likewise, if a module is requested but was already
811 ** automatically queued to fulfill a dependency, the explicit request
812 ** becomes a no-op.
813 **
814 ** Bundled mode is the only mode in which this API greatly improves
815 ** aggregate over-the-wire and HTTP request costs. For other modes,
816 ** reducing the inclusion of fossil.XYZ APIs to their bare minimum
817 ** provides the lowest aggregate costs. For debate and details, see
818 ** the discussion at:
819 **
820 ** https://fossil-scm.org/forum/forumpost/3fa2633f3e
821 **
822 ** In practice it is normally necessary (or preferred) to call
823 ** builtin_fulfill_js_requests() after calling this, before proceeding
824 ** to call builtin_request_js() for page-specific JS, in order to
825 ** improve cachability.
826 **
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827 ** Minor caveat: the purpose of emitting all of the fossil.XYZ JS APIs
828 ** at once is to reduce over-the-wire transfers by enabling cross-page
829 ** caching, but if there are other JS scripts pending via
830 ** builtin_request_js() when this is called then they will be included
831 ** in the JS request emitted by this routine, resulting in a different
@@ -773,39 +832,44 @@
832 ** script URL than if they were not included. Thus, if a given page
833 ** has its own scripts to install via builtin_request_js(), they
834 ** should, if possible, be delayed until after this is called OR the
835 ** page should call builtin_fulfill_js_requests() to flush the request
836 ** queue before calling this routine.
837 **
838 ** Achtung: the fossil.page.XYZ.js files are page-specific, containing
839 ** the app-level logic for that specific page, and loading more than
840 ** one of them in a single page will break that page. Each of those
841 ** expects to "own" the page it is loaded in, and it should be loaded
842 ** as late in the JS-loading process as feasible, ideally bundled (via
843 ** builtin_request_js()) with any other app-/page-specific JS it may
844 ** need.
845 **
846 ** Example usage:
847 **
848 ** builtin_fossil_js_bundle_or("dom", "fetch", 0);
 
 
849 **
850 ** In bundled mode, that will (the first time it is called) emit all
851 ** builtin fossil JS APIs and "fulfill" the queue immediately. In
852 ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be
853 ** emitted the next time builtin_fulfill_js_requests() is called.
854 */
855 void builtin_fossil_js_bundle_or( const char * zApi, ... ) {
856 static int bundled = 0;
857 const char *zArg;
858 va_list vargs;
859
860 if(JS_BUNDLED == builtin_get_js_delivery_mode()){
861 if(!bundled){
862 bundled = 1;
863 builtin_emit_fossil_js_once(0);
 
 
 
 
 
 
 
 
 
 
864 builtin_fulfill_js_requests();
865 }
866 return;
867 }
868 va_start(vargs,zApi);
869 for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){
870 if(0==builtin_emit_fossil_js_once(zArg)){
871 fossil_fatal("Unknown fossil JS module: %s\n", zArg);
872 }
873 }
874 va_end(vargs);
875 }
876
+11 -7
--- src/doc.c
+++ src/doc.c
@@ -401,19 +401,23 @@
401401
}
402402
403403
/*
404404
** Emit Javascript which applies (or optionally can apply) to both the
405405
** /doc and /wiki pages. None of this implements required
406
-** functionality, just nice-to-haves. Only call this once per page.
406
+** functionality, just nice-to-haves. Any calls after the first are
407
+** no-ops.
407408
*/
408409
void document_emit_js(void){
409
- builtin_fossil_js_bundle_or("dom", "copybutton", "pikchr", 0);
410
- style_script_begin(__FILE__,__LINE__);
411
- CX("window.addEventListener('load', "
412
- "()=>window.fossil.pikchr.addSrcView(), "
413
- "false);\n");
414
- style_script_end();
410
+ static int once = 0;
411
+ if(0==once++){
412
+ builtin_fossil_js_bundle_or("pikchr", 0);
413
+ style_script_begin(__FILE__,__LINE__);
414
+ CX("window.addEventListener('load', "
415
+ "()=>window.fossil.pikchr.addSrcView(), "
416
+ "false);\n");
417
+ style_script_end();
418
+ }
415419
}
416420
417421
/*
418422
** Guess the mime-type of a document based on its name.
419423
*/
420424
--- src/doc.c
+++ src/doc.c
@@ -401,19 +401,23 @@
401 }
402
403 /*
404 ** Emit Javascript which applies (or optionally can apply) to both the
405 ** /doc and /wiki pages. None of this implements required
406 ** functionality, just nice-to-haves. Only call this once per page.
 
407 */
408 void document_emit_js(void){
409 builtin_fossil_js_bundle_or("dom", "copybutton", "pikchr", 0);
410 style_script_begin(__FILE__,__LINE__);
411 CX("window.addEventListener('load', "
412 "()=>window.fossil.pikchr.addSrcView(), "
413 "false);\n");
414 style_script_end();
 
 
 
415 }
416
417 /*
418 ** Guess the mime-type of a document based on its name.
419 */
420
--- src/doc.c
+++ src/doc.c
@@ -401,19 +401,23 @@
401 }
402
403 /*
404 ** Emit Javascript which applies (or optionally can apply) to both the
405 ** /doc and /wiki pages. None of this implements required
406 ** functionality, just nice-to-haves. Any calls after the first are
407 ** no-ops.
408 */
409 void document_emit_js(void){
410 static int once = 0;
411 if(0==once++){
412 builtin_fossil_js_bundle_or("pikchr", 0);
413 style_script_begin(__FILE__,__LINE__);
414 CX("window.addEventListener('load', "
415 "()=>window.fossil.pikchr.addSrcView(), "
416 "false);\n");
417 style_script_end();
418 }
419 }
420
421 /*
422 ** Guess the mime-type of a document based on its name.
423 */
424
--- src/event.c
+++ src/event.c
@@ -228,10 +228,11 @@
228228
zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
229229
" FROM tag"
230230
" WHERE tagname GLOB 'event-%q*'",
231231
zId);
232232
attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
233
+ document_emit_js();
233234
style_footer();
234235
manifest_destroy(pTNote);
235236
}
236237
237238
/*
238239
--- src/event.c
+++ src/event.c
@@ -228,10 +228,11 @@
228 zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
229 " FROM tag"
230 " WHERE tagname GLOB 'event-%q*'",
231 zId);
232 attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
 
233 style_footer();
234 manifest_destroy(pTNote);
235 }
236
237 /*
238
--- src/event.c
+++ src/event.c
@@ -228,10 +228,11 @@
228 zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
229 " FROM tag"
230 " WHERE tagname GLOB 'event-%q*'",
231 zId);
232 attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
233 document_emit_js();
234 style_footer();
235 manifest_destroy(pTNote);
236 }
237
238 /*
239
+2 -2
--- src/forum.c
+++ src/forum.c
@@ -742,12 +742,12 @@
742742
** Emit Forum Javascript which applies (or optionally can apply)
743743
** to all forum-related pages. It does not include page-specific
744744
** code (e.g. "forum.js").
745745
*/
746746
static void forum_emit_js(void){
747
- builtin_fossil_js_bundle_or("dom", "copybutton", "pikchr", 0);
748
- builtin_emit_fossil_js_apis("page.forumpost", 0);
747
+ builtin_fossil_js_bundle_or("copybutton", "pikchr", 0);
748
+ builtin_request_js("fossil.page.forumpost.js");
749749
}
750750
751751
/*
752752
** WEBPAGE: forumpost
753753
**
754754
--- src/forum.c
+++ src/forum.c
@@ -742,12 +742,12 @@
742 ** Emit Forum Javascript which applies (or optionally can apply)
743 ** to all forum-related pages. It does not include page-specific
744 ** code (e.g. "forum.js").
745 */
746 static void forum_emit_js(void){
747 builtin_fossil_js_bundle_or("dom", "copybutton", "pikchr", 0);
748 builtin_emit_fossil_js_apis("page.forumpost", 0);
749 }
750
751 /*
752 ** WEBPAGE: forumpost
753 **
754
--- src/forum.c
+++ src/forum.c
@@ -742,12 +742,12 @@
742 ** Emit Forum Javascript which applies (or optionally can apply)
743 ** to all forum-related pages. It does not include page-specific
744 ** code (e.g. "forum.js").
745 */
746 static void forum_emit_js(void){
747 builtin_fossil_js_bundle_or("copybutton", "pikchr", 0);
748 builtin_request_js("fossil.page.forumpost.js");
749 }
750
751 /*
752 ** WEBPAGE: forumpost
753 **
754
+1 -1
--- src/fuzz.c
+++ src/fuzz.c
@@ -26,11 +26,11 @@
2626
** Then edit the Makefile as follows:
2727
**
2828
** (1) Change CC to be "clang-6.0" or some other compiler that
2929
** supports libFuzzer
3030
**
31
-** (2) Chagne APPNAME to "fossil-fuzz"
31
+** (2) Change APPNAME to "fossil-fuzz"
3232
**
3333
** (3) Add "-fsanitize=fuzzer" and "-DFOSSIL_FUZZ" to TCCFLAGS. Perhaps
3434
** make the first change "-fsanitize=fuzzer,undefined,address" for
3535
** extra, but slower, testing.
3636
**
3737
--- src/fuzz.c
+++ src/fuzz.c
@@ -26,11 +26,11 @@
26 ** Then edit the Makefile as follows:
27 **
28 ** (1) Change CC to be "clang-6.0" or some other compiler that
29 ** supports libFuzzer
30 **
31 ** (2) Chagne APPNAME to "fossil-fuzz"
32 **
33 ** (3) Add "-fsanitize=fuzzer" and "-DFOSSIL_FUZZ" to TCCFLAGS. Perhaps
34 ** make the first change "-fsanitize=fuzzer,undefined,address" for
35 ** extra, but slower, testing.
36 **
37
--- src/fuzz.c
+++ src/fuzz.c
@@ -26,11 +26,11 @@
26 ** Then edit the Makefile as follows:
27 **
28 ** (1) Change CC to be "clang-6.0" or some other compiler that
29 ** supports libFuzzer
30 **
31 ** (2) Change APPNAME to "fossil-fuzz"
32 **
33 ** (3) Add "-fsanitize=fuzzer" and "-DFOSSIL_FUZZ" to TCCFLAGS. Perhaps
34 ** make the first change "-fsanitize=fuzzer,undefined,address" for
35 ** extra, but slower, testing.
36 **
37
+3 -2
--- src/info.c
+++ src/info.c
@@ -1047,10 +1047,11 @@
10471047
blob_init(&wiki, pWiki->zWiki, -1);
10481048
safe_html_context(DOCSRC_WIKI);
10491049
wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
10501050
blob_reset(&wiki);
10511051
manifest_destroy(pWiki);
1052
+ document_emit_js();
10521053
style_footer();
10531054
}
10541055
10551056
/*
10561057
** Find an check-in based on query parameter zParam and parse its
@@ -2129,12 +2130,11 @@
21292130
if(includeJS && !emittedJS){
21302131
emittedJS = 1;
21312132
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
21322133
builtin_request_js("scroll.js");
21332134
}
2134
- builtin_fossil_js_bundle_or("dom", "copybutton", "popupwidget",
2135
- "numbered-lines", 0);
2135
+ builtin_fossil_js_bundle_or("numbered-lines", 0);
21362136
}
21372137
}
21382138
21392139
/*
21402140
** COMMAND: test-line-numbers
@@ -2437,10 +2437,11 @@
24372437
@ <hr />
24382438
content_get(rid, &content);
24392439
if( renderAsWiki ){
24402440
safe_html_context(DOCSRC_FILE);
24412441
wiki_render_by_mimetype(&content, zMime);
2442
+ document_emit_js();
24422443
}else if( renderAsHtml ){
24432444
@ <iframe src="%R/raw/%s(zUuid)"
24442445
@ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
24452446
@ sandbox="allow-same-origin" id="ifm1">
24462447
@ </iframe>
24472448
--- src/info.c
+++ src/info.c
@@ -1047,10 +1047,11 @@
1047 blob_init(&wiki, pWiki->zWiki, -1);
1048 safe_html_context(DOCSRC_WIKI);
1049 wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
1050 blob_reset(&wiki);
1051 manifest_destroy(pWiki);
 
1052 style_footer();
1053 }
1054
1055 /*
1056 ** Find an check-in based on query parameter zParam and parse its
@@ -2129,12 +2130,11 @@
2129 if(includeJS && !emittedJS){
2130 emittedJS = 1;
2131 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2132 builtin_request_js("scroll.js");
2133 }
2134 builtin_fossil_js_bundle_or("dom", "copybutton", "popupwidget",
2135 "numbered-lines", 0);
2136 }
2137 }
2138
2139 /*
2140 ** COMMAND: test-line-numbers
@@ -2437,10 +2437,11 @@
2437 @ <hr />
2438 content_get(rid, &content);
2439 if( renderAsWiki ){
2440 safe_html_context(DOCSRC_FILE);
2441 wiki_render_by_mimetype(&content, zMime);
 
2442 }else if( renderAsHtml ){
2443 @ <iframe src="%R/raw/%s(zUuid)"
2444 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2445 @ sandbox="allow-same-origin" id="ifm1">
2446 @ </iframe>
2447
--- src/info.c
+++ src/info.c
@@ -1047,10 +1047,11 @@
1047 blob_init(&wiki, pWiki->zWiki, -1);
1048 safe_html_context(DOCSRC_WIKI);
1049 wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
1050 blob_reset(&wiki);
1051 manifest_destroy(pWiki);
1052 document_emit_js();
1053 style_footer();
1054 }
1055
1056 /*
1057 ** Find an check-in based on query parameter zParam and parse its
@@ -2129,12 +2130,11 @@
2130 if(includeJS && !emittedJS){
2131 emittedJS = 1;
2132 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2133 builtin_request_js("scroll.js");
2134 }
2135 builtin_fossil_js_bundle_or("numbered-lines", 0);
 
2136 }
2137 }
2138
2139 /*
2140 ** COMMAND: test-line-numbers
@@ -2437,10 +2437,11 @@
2437 @ <hr />
2438 content_get(rid, &content);
2439 if( renderAsWiki ){
2440 safe_html_context(DOCSRC_FILE);
2441 wiki_render_by_mimetype(&content, zMime);
2442 document_emit_js();
2443 }else if( renderAsHtml ){
2444 @ <iframe src="%R/raw/%s(zUuid)"
2445 @ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
2446 @ sandbox="allow-same-origin" id="ifm1">
2447 @ </iframe>
2448
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -357,13 +357,13 @@
357357
CX("%b", &out);
358358
blob_reset(&out);
359359
} CX("</div>"/*#pikchrshow-output*/);
360360
} CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
361361
} CX("</div>"/*sbs-wrapper*/);
362
- builtin_fossil_js_bundle_or("dom", "fetch", "copybutton",
363
- "popupwidget", "storage", "pikchr", 0);
364
- builtin_emit_fossil_js_apis("page.pikchrshow", 0);
362
+ builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
363
+ "storage", "pikchr", 0);
364
+ builtin_request_js("fossil.page.pikchrshow.js");
365365
builtin_fulfill_js_requests();
366366
style_footer();
367367
}
368368
369369
/*
370370
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -357,13 +357,13 @@
357 CX("%b", &out);
358 blob_reset(&out);
359 } CX("</div>"/*#pikchrshow-output*/);
360 } CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
361 } CX("</div>"/*sbs-wrapper*/);
362 builtin_fossil_js_bundle_or("dom", "fetch", "copybutton",
363 "popupwidget", "storage", "pikchr", 0);
364 builtin_emit_fossil_js_apis("page.pikchrshow", 0);
365 builtin_fulfill_js_requests();
366 style_footer();
367 }
368
369 /*
370
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -357,13 +357,13 @@
357 CX("%b", &out);
358 blob_reset(&out);
359 } CX("</div>"/*#pikchrshow-output*/);
360 } CX("</fieldset>"/*#pikchrshow-output-wrapper*/);
361 } CX("</div>"/*sbs-wrapper*/);
362 builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
363 "storage", "pikchr", 0);
364 builtin_request_js("fossil.page.pikchrshow.js");
365 builtin_fulfill_js_requests();
366 style_footer();
367 }
368
369 /*
370
--- src/timeline.c
+++ src/timeline.c
@@ -2624,10 +2624,11 @@
26242624
selectedRid, secondaryRid, 0);
26252625
db_finalize(&q);
26262626
if( zOlderButton ){
26272627
@ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
26282628
}
2629
+ document_emit_js(/*handles pikchrs rendered above*/);
26292630
style_footer();
26302631
}
26312632
26322633
/*
26332634
** The input query q selects various records. Print a human-readable
26342635
--- src/timeline.c
+++ src/timeline.c
@@ -2624,10 +2624,11 @@
2624 selectedRid, secondaryRid, 0);
2625 db_finalize(&q);
2626 if( zOlderButton ){
2627 @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
2628 }
 
2629 style_footer();
2630 }
2631
2632 /*
2633 ** The input query q selects various records. Print a human-readable
2634
--- src/timeline.c
+++ src/timeline.c
@@ -2624,10 +2624,11 @@
2624 selectedRid, secondaryRid, 0);
2625 db_finalize(&q);
2626 if( zOlderButton ){
2627 @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
2628 }
2629 document_emit_js(/*handles pikchrs rendered above*/);
2630 style_footer();
2631 }
2632
2633 /*
2634 ** The input query q selects various records. Print a human-readable
2635

Keyboard Shortcuts

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