Fossil SCM

Reworked how /fileedit loads its JS - it now fetches them rather than embedding them inline. Moved fossil.fetch() docs from style.c into the JS file.

stephan 2020-05-06 01:51 fileedit-ajaxify
Commit b48212f6ea83876b7d9721081dfdbbc8e6f4743fdad9c3f16551555b78edf155
+126 -117
--- src/default_css.txt
+++ src/default_css.txt
@@ -861,10 +861,79 @@
861861
// #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862862
// max-width: 30em;
863863
// overflow: auto;
864864
// }
865865
// .fileedit-XXX => /fileedit page
866
+.hidden {
867
+ position: absolute;
868
+ opacity: 0;
869
+ pointer-events: none;
870
+}
871
+//.hidden {
872
+// display: none;
873
+//}
874
+#fossil-status-bar {
875
+ display: block;
876
+ font-family: monospace;
877
+ border-width: 1px;
878
+ border-style: inset;
879
+ border-color: inherit;
880
+ min-height: 1.5em;
881
+ font-size: 1.2em;
882
+ padding: 0.2em;
883
+ margin: 0.25em 0;
884
+ flex: 0 0 auto;
885
+}
886
+#fossil-status-bar.error {
887
+ color: darkred;
888
+ background: yellow;
889
+}
890
+//////////////////////////////////
891
+// Styles for fossil.tabs.js:
892
+.tab-container {
893
+ width: 100%;
894
+ display: flex;
895
+ flex-direction: column;
896
+ align-items: stretch;
897
+}
898
+.tab-container > #fossil-status-bar {
899
+ margin-top: 0;
900
+}
901
+.tab-container > .tabs {
902
+ padding: 0.25em;
903
+ margin: 0;
904
+ display: flex;
905
+ flex-direction: column;
906
+ border-width: 1px;
907
+ border-style: outset;
908
+ border-color: inherit;
909
+}
910
+.tab-container > .tabs > .tab-panel {
911
+ align-self: stretch;
912
+ flex: 10 1 auto;
913
+ display: block;
914
+}
915
+.tab-container > .tab-bar {
916
+ display: flex;
917
+ flex-direction: row;
918
+ flex: 1 10 auto;
919
+ align-self: stretch;
920
+ flex-wrap: wrap;
921
+}
922
+.tab-container > .tab-bar > button {
923
+ border-radius: 0.5em 0.5em 0 0;
924
+ margin: 0.5em 0.5em 0 0.5em;
925
+ align-self: baseline;
926
+}
927
+.tab-container > .tab-bar > button.selected {
928
+ font-style: italic;
929
+ font-weight: bold;
930
+ margin: 0 0.5em;
931
+ text-decoration: underline;
932
+}
933
+//////////////////////////////////
934
+// Styles for /fileedit:
866935
form.fileedit textarea {
867936
font-family: monospace;
868937
width: 100%;
869938
}
870939
form.fileedit fieldset {
@@ -917,26 +986,67 @@
917986
}
918987
#fileedit-comment {
919988
width: 100%;
920989
font-family: monospace;
921990
}
922
-#fossil-status-bar {
923
- display: block;
924
- font-family: monospace;
925
- border-width: 1px;
926
- border-style: inset;
927
- border-color: inherit;
928
- min-height: 1.5em;
929
- font-size: 1.2em;
930
- padding: 0.2em;
931
- margin: 0.25em 0;
932
- flex: 0 0 auto;
933
-}
934
-#fossil-status-bar.error {
935
- color: darkred;
936
- background: yellow;
937
-}
991
+.tab-container > .tabs > .tab-panel > .fileedit-options {
992
+ margin-top: 0;
993
+ border: none;
994
+ border-radius: 0;
995
+ border-bottom-width: 1px;
996
+ border-bottom-style: dotted;
997
+}
998
+.tab-container > .tabs > .tab-panel > .fileedit-options > button {
999
+ vertical-align: middle;
1000
+ margin: 0.5em;
1001
+}
1002
+////////////////////////////////////////////////////////////////////
1003
+// Styles developed for /fileedit but which have wider
1004
+// applicability:
1005
+.flex-container {
1006
+ display: flex;
1007
+}
1008
+.flex-container.row {
1009
+ flex-direction: row;
1010
+ flex-wrap: wrap;
1011
+ justify-content: center;
1012
+ align-items: center;
1013
+}
1014
+.flex-container.row.stretch {
1015
+ flex-direction: row;
1016
+ flex-wrap: wrap;
1017
+ align-items: stretch;
1018
+ margin: 0;
1019
+}
1020
+.flex-container.column {
1021
+ flex-direction: column;
1022
+ flex-wrap: wrap;
1023
+ justify-content: center;
1024
+ align-items: center;
1025
+}
1026
+.flex-container.column.stretch {
1027
+ align-items: stretch;
1028
+ margin: 0;
1029
+}
1030
+.font-size-100 {
1031
+ font-size: 100%;
1032
+}
1033
+.font-size-125 {
1034
+ font-size: 125%;
1035
+}
1036
+.font-size-150 {
1037
+ font-size: 150%;
1038
+}
1039
+.font-size-175 {
1040
+ font-size: 175%;
1041
+}
1042
+.font-size-200 {
1043
+ font-size: 200%;
1044
+}
1045
+//////////////////////////////////////////////////////////////////
1046
+// .input-with-label is intended to be a wrapper element which
1047
+// contains a SPAN label and an INPUT control.
9381048
.input-with-label {
9391049
border: 1px inset #808080;
9401050
border-radius: 0.5em;
9411051
padding: 0.25em 0.4em;
9421052
margin: 0 0.5em;
@@ -966,106 +1076,5 @@
9661076
}
9671077
.input-with-label > span {
9681078
margin: 0 0.25em 0 0.25em;
9691079
vertical-align: middle;
9701080
}
971
-.hidden {
972
- position: absolute;
973
- opacity: 0;
974
- pointer-events: none;
975
-}
976
-//.hidden {
977
-// display: none;
978
-//}
979
-.font-size-100 {
980
- font-size: 100%;
981
-}
982
-.font-size-125 {
983
- font-size: 125%;
984
-}
985
-.font-size-150 {
986
- font-size: 150%;
987
-}
988
-.font-size-175 {
989
- font-size: 175%;
990
-}
991
-.font-size-200 {
992
- font-size: 200%;
993
-}
994
-
995
-.tab-container {
996
- width: 100%;
997
- display: flex;
998
- flex-direction: column;
999
- align-items: stretch;
1000
-}
1001
-.tab-container > #fossil-status-bar {
1002
- margin-top: 0;
1003
-}
1004
-.tab-container > .tabs {
1005
- padding: 0.25em;
1006
- margin: 0;
1007
- display: flex;
1008
- flex-direction: column;
1009
- border-width: 1px;
1010
- border-style: outset;
1011
- border-color: inherit;
1012
-}
1013
-.tab-container > .tabs > .tab-panel {
1014
- align-self: stretch;
1015
- flex: 10 1 auto;
1016
- display: block;
1017
-}
1018
-.tab-container > .tab-bar {
1019
- display: flex;
1020
- flex-direction: row;
1021
- flex: 1 10 auto;
1022
- align-self: stretch;
1023
- flex-wrap: wrap;
1024
-}
1025
-.tab-container > .tab-bar > button {
1026
- border-radius: 0.5em 0.5em 0 0;
1027
- margin: 0.5em 0.5em 0 0.5em;
1028
- align-self: baseline;
1029
-}
1030
-.tab-container > .tab-bar > button.selected {
1031
- font-style: italic;
1032
- font-weight: bold;
1033
- margin: 0 0.5em;
1034
- text-decoration: underline;
1035
-}
1036
-.tab-container > .tabs > .tab-panel > .fileedit-options {
1037
- margin-top: 0;
1038
- border: none;
1039
- border-radius: 0;
1040
- border-bottom-width: 1px;
1041
- border-bottom-style: dotted;
1042
-}
1043
-.tab-container > .tabs > .tab-panel > .fileedit-options > button {
1044
- vertical-align: middle;
1045
- margin: 0.5em;
1046
-}
1047
-.flex-container {
1048
- display: flex;
1049
-}
1050
-.flex-container.row {
1051
- flex-direction: row;
1052
- flex-wrap: wrap;
1053
- justify-content: center;
1054
- align-items: center;
1055
-}
1056
-.flex-container.row.stretch {
1057
- flex-direction: row;
1058
- flex-wrap: wrap;
1059
- align-items: stretch;
1060
- margin: 0;
1061
-}
1062
-.flex-container.column {
1063
- flex-direction: column;
1064
- flex-wrap: wrap;
1065
- justify-content: center;
1066
- align-items: center;
1067
-}
1068
-.flex-container.column.stretch {
1069
- align-items: stretch;
1070
- margin: 0;
1071
-}
10721081
--- src/default_css.txt
+++ src/default_css.txt
@@ -861,10 +861,79 @@
861 // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862 // max-width: 30em;
863 // overflow: auto;
864 // }
865 // .fileedit-XXX => /fileedit page
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
866 form.fileedit textarea {
867 font-family: monospace;
868 width: 100%;
869 }
870 form.fileedit fieldset {
@@ -917,26 +986,67 @@
917 }
918 #fileedit-comment {
919 width: 100%;
920 font-family: monospace;
921 }
922 #fossil-status-bar {
923 display: block;
924 font-family: monospace;
925 border-width: 1px;
926 border-style: inset;
927 border-color: inherit;
928 min-height: 1.5em;
929 font-size: 1.2em;
930 padding: 0.2em;
931 margin: 0.25em 0;
932 flex: 0 0 auto;
933 }
934 #fossil-status-bar.error {
935 color: darkred;
936 background: yellow;
937 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
938 .input-with-label {
939 border: 1px inset #808080;
940 border-radius: 0.5em;
941 padding: 0.25em 0.4em;
942 margin: 0 0.5em;
@@ -966,106 +1076,5 @@
966 }
967 .input-with-label > span {
968 margin: 0 0.25em 0 0.25em;
969 vertical-align: middle;
970 }
971 .hidden {
972 position: absolute;
973 opacity: 0;
974 pointer-events: none;
975 }
976 //.hidden {
977 // display: none;
978 //}
979 .font-size-100 {
980 font-size: 100%;
981 }
982 .font-size-125 {
983 font-size: 125%;
984 }
985 .font-size-150 {
986 font-size: 150%;
987 }
988 .font-size-175 {
989 font-size: 175%;
990 }
991 .font-size-200 {
992 font-size: 200%;
993 }
994
995 .tab-container {
996 width: 100%;
997 display: flex;
998 flex-direction: column;
999 align-items: stretch;
1000 }
1001 .tab-container > #fossil-status-bar {
1002 margin-top: 0;
1003 }
1004 .tab-container > .tabs {
1005 padding: 0.25em;
1006 margin: 0;
1007 display: flex;
1008 flex-direction: column;
1009 border-width: 1px;
1010 border-style: outset;
1011 border-color: inherit;
1012 }
1013 .tab-container > .tabs > .tab-panel {
1014 align-self: stretch;
1015 flex: 10 1 auto;
1016 display: block;
1017 }
1018 .tab-container > .tab-bar {
1019 display: flex;
1020 flex-direction: row;
1021 flex: 1 10 auto;
1022 align-self: stretch;
1023 flex-wrap: wrap;
1024 }
1025 .tab-container > .tab-bar > button {
1026 border-radius: 0.5em 0.5em 0 0;
1027 margin: 0.5em 0.5em 0 0.5em;
1028 align-self: baseline;
1029 }
1030 .tab-container > .tab-bar > button.selected {
1031 font-style: italic;
1032 font-weight: bold;
1033 margin: 0 0.5em;
1034 text-decoration: underline;
1035 }
1036 .tab-container > .tabs > .tab-panel > .fileedit-options {
1037 margin-top: 0;
1038 border: none;
1039 border-radius: 0;
1040 border-bottom-width: 1px;
1041 border-bottom-style: dotted;
1042 }
1043 .tab-container > .tabs > .tab-panel > .fileedit-options > button {
1044 vertical-align: middle;
1045 margin: 0.5em;
1046 }
1047 .flex-container {
1048 display: flex;
1049 }
1050 .flex-container.row {
1051 flex-direction: row;
1052 flex-wrap: wrap;
1053 justify-content: center;
1054 align-items: center;
1055 }
1056 .flex-container.row.stretch {
1057 flex-direction: row;
1058 flex-wrap: wrap;
1059 align-items: stretch;
1060 margin: 0;
1061 }
1062 .flex-container.column {
1063 flex-direction: column;
1064 flex-wrap: wrap;
1065 justify-content: center;
1066 align-items: center;
1067 }
1068 .flex-container.column.stretch {
1069 align-items: stretch;
1070 margin: 0;
1071 }
1072
--- src/default_css.txt
+++ src/default_css.txt
@@ -861,10 +861,79 @@
861 // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div {
862 // max-width: 30em;
863 // overflow: auto;
864 // }
865 // .fileedit-XXX => /fileedit page
866 .hidden {
867 position: absolute;
868 opacity: 0;
869 pointer-events: none;
870 }
871 //.hidden {
872 // display: none;
873 //}
874 #fossil-status-bar {
875 display: block;
876 font-family: monospace;
877 border-width: 1px;
878 border-style: inset;
879 border-color: inherit;
880 min-height: 1.5em;
881 font-size: 1.2em;
882 padding: 0.2em;
883 margin: 0.25em 0;
884 flex: 0 0 auto;
885 }
886 #fossil-status-bar.error {
887 color: darkred;
888 background: yellow;
889 }
890 //////////////////////////////////
891 // Styles for fossil.tabs.js:
892 .tab-container {
893 width: 100%;
894 display: flex;
895 flex-direction: column;
896 align-items: stretch;
897 }
898 .tab-container > #fossil-status-bar {
899 margin-top: 0;
900 }
901 .tab-container > .tabs {
902 padding: 0.25em;
903 margin: 0;
904 display: flex;
905 flex-direction: column;
906 border-width: 1px;
907 border-style: outset;
908 border-color: inherit;
909 }
910 .tab-container > .tabs > .tab-panel {
911 align-self: stretch;
912 flex: 10 1 auto;
913 display: block;
914 }
915 .tab-container > .tab-bar {
916 display: flex;
917 flex-direction: row;
918 flex: 1 10 auto;
919 align-self: stretch;
920 flex-wrap: wrap;
921 }
922 .tab-container > .tab-bar > button {
923 border-radius: 0.5em 0.5em 0 0;
924 margin: 0.5em 0.5em 0 0.5em;
925 align-self: baseline;
926 }
927 .tab-container > .tab-bar > button.selected {
928 font-style: italic;
929 font-weight: bold;
930 margin: 0 0.5em;
931 text-decoration: underline;
932 }
933 //////////////////////////////////
934 // Styles for /fileedit:
935 form.fileedit textarea {
936 font-family: monospace;
937 width: 100%;
938 }
939 form.fileedit fieldset {
@@ -917,26 +986,67 @@
986 }
987 #fileedit-comment {
988 width: 100%;
989 font-family: monospace;
990 }
991 .tab-container > .tabs > .tab-panel > .fileedit-options {
992 margin-top: 0;
993 border: none;
994 border-radius: 0;
995 border-bottom-width: 1px;
996 border-bottom-style: dotted;
997 }
998 .tab-container > .tabs > .tab-panel > .fileedit-options > button {
999 vertical-align: middle;
1000 margin: 0.5em;
1001 }
1002 ////////////////////////////////////////////////////////////////////
1003 // Styles developed for /fileedit but which have wider
1004 // applicability:
1005 .flex-container {
1006 display: flex;
1007 }
1008 .flex-container.row {
1009 flex-direction: row;
1010 flex-wrap: wrap;
1011 justify-content: center;
1012 align-items: center;
1013 }
1014 .flex-container.row.stretch {
1015 flex-direction: row;
1016 flex-wrap: wrap;
1017 align-items: stretch;
1018 margin: 0;
1019 }
1020 .flex-container.column {
1021 flex-direction: column;
1022 flex-wrap: wrap;
1023 justify-content: center;
1024 align-items: center;
1025 }
1026 .flex-container.column.stretch {
1027 align-items: stretch;
1028 margin: 0;
1029 }
1030 .font-size-100 {
1031 font-size: 100%;
1032 }
1033 .font-size-125 {
1034 font-size: 125%;
1035 }
1036 .font-size-150 {
1037 font-size: 150%;
1038 }
1039 .font-size-175 {
1040 font-size: 175%;
1041 }
1042 .font-size-200 {
1043 font-size: 200%;
1044 }
1045 //////////////////////////////////////////////////////////////////
1046 // .input-with-label is intended to be a wrapper element which
1047 // contains a SPAN label and an INPUT control.
1048 .input-with-label {
1049 border: 1px inset #808080;
1050 border-radius: 0.5em;
1051 padding: 0.25em 0.4em;
1052 margin: 0 0.5em;
@@ -966,106 +1076,5 @@
1076 }
1077 .input-with-label > span {
1078 margin: 0 0.25em 0 0.25em;
1079 vertical-align: middle;
1080 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1081
+6 -15
--- src/fileedit.c
+++ src/fileedit.c
@@ -1452,20 +1452,10 @@
14521452
blob_reset(&err);
14531453
blob_reset(&manifest);
14541454
CheckinMiniInfo_cleanup(&cimi);
14551455
}
14561456
1457
-
1458
-/*
1459
-** Emits utility script code specific to the /fileedit page.
1460
-*/
1461
-static void fileedit_emit_page_script(){
1462
- style_emit_script_fetch();
1463
- style_emit_script_tabs();
1464
- style_emit_script_builtin("fossil.page.fileedit.js");
1465
-}
1466
-
14671457
/*
14681458
** WEBPAGE: fileedit
14691459
**
14701460
** EXPERIMENTAL and subject to change and removal at any time. The goal
14711461
** is to allow online edits of files.
@@ -1487,11 +1477,10 @@
14871477
const char * zRev; /* checkin version */
14881478
const char * zFileMime = 0; /* File mime type guess */
14891479
CheckinMiniInfo cimi; /* Checkin state */
14901480
int previewHtmlHeight = 0; /* iframe height (EMs) */
14911481
int previewRenderMode = FE_RENDER_GUESS; /* preview mode */
1492
- char * zFileUuid = 0; /* File content UUID */
14931482
Blob err = empty_blob; /* Error report */
14941483
Blob endScript = empty_blob; /* Script code to run at the
14951484
end. This content will be
14961485
combined into a single JS
14971486
function call, thus each
@@ -1788,27 +1777,29 @@
17881777
blob_appendf(&endScript,
17891778
"fossil.page.loadFile('%j','%j');",
17901779
zFilename, cimi.zParentUuid);
17911780
17921781
end_footer:
1793
- fossil_free(zFileUuid);
17941782
if(stmt.pStmt){
17951783
db_finalize(&stmt);
17961784
}
17971785
if(blob_size(&err)){
17981786
CX("<div class='fileedit-error-report'>%s</div>",
17991787
blob_str(&err));
18001788
}
18011789
blob_reset(&err);
18021790
CheckinMiniInfo_cleanup(&cimi);
1803
- fileedit_emit_page_script();
1791
+ style_emit_script_fossil_bootstrap(0);
1792
+ style_emit_script_fetch(0);
1793
+ style_emit_script_tabs(0);
1794
+ style_emit_script_builtin("fossil.page.fileedit.js",0);
18041795
if(blob_size(&endScript)>0){
1805
- style_emit_script_tag(0);
1796
+ style_emit_script_tag(0,0);
18061797
CX("(function(){\n");
18071798
CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
18081799
&endScript);
18091800
CX("})();");
1810
- style_emit_script_tag(1);
1801
+ style_emit_script_tag(1,0);
18111802
}
18121803
db_end_transaction(0);
18131804
style_footer();
18141805
}
18151806
--- src/fileedit.c
+++ src/fileedit.c
@@ -1452,20 +1452,10 @@
1452 blob_reset(&err);
1453 blob_reset(&manifest);
1454 CheckinMiniInfo_cleanup(&cimi);
1455 }
1456
1457
1458 /*
1459 ** Emits utility script code specific to the /fileedit page.
1460 */
1461 static void fileedit_emit_page_script(){
1462 style_emit_script_fetch();
1463 style_emit_script_tabs();
1464 style_emit_script_builtin("fossil.page.fileedit.js");
1465 }
1466
1467 /*
1468 ** WEBPAGE: fileedit
1469 **
1470 ** EXPERIMENTAL and subject to change and removal at any time. The goal
1471 ** is to allow online edits of files.
@@ -1487,11 +1477,10 @@
1487 const char * zRev; /* checkin version */
1488 const char * zFileMime = 0; /* File mime type guess */
1489 CheckinMiniInfo cimi; /* Checkin state */
1490 int previewHtmlHeight = 0; /* iframe height (EMs) */
1491 int previewRenderMode = FE_RENDER_GUESS; /* preview mode */
1492 char * zFileUuid = 0; /* File content UUID */
1493 Blob err = empty_blob; /* Error report */
1494 Blob endScript = empty_blob; /* Script code to run at the
1495 end. This content will be
1496 combined into a single JS
1497 function call, thus each
@@ -1788,27 +1777,29 @@
1788 blob_appendf(&endScript,
1789 "fossil.page.loadFile('%j','%j');",
1790 zFilename, cimi.zParentUuid);
1791
1792 end_footer:
1793 fossil_free(zFileUuid);
1794 if(stmt.pStmt){
1795 db_finalize(&stmt);
1796 }
1797 if(blob_size(&err)){
1798 CX("<div class='fileedit-error-report'>%s</div>",
1799 blob_str(&err));
1800 }
1801 blob_reset(&err);
1802 CheckinMiniInfo_cleanup(&cimi);
1803 fileedit_emit_page_script();
 
 
 
1804 if(blob_size(&endScript)>0){
1805 style_emit_script_tag(0);
1806 CX("(function(){\n");
1807 CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
1808 &endScript);
1809 CX("})();");
1810 style_emit_script_tag(1);
1811 }
1812 db_end_transaction(0);
1813 style_footer();
1814 }
1815
--- src/fileedit.c
+++ src/fileedit.c
@@ -1452,20 +1452,10 @@
1452 blob_reset(&err);
1453 blob_reset(&manifest);
1454 CheckinMiniInfo_cleanup(&cimi);
1455 }
1456
 
 
 
 
 
 
 
 
 
 
1457 /*
1458 ** WEBPAGE: fileedit
1459 **
1460 ** EXPERIMENTAL and subject to change and removal at any time. The goal
1461 ** is to allow online edits of files.
@@ -1487,11 +1477,10 @@
1477 const char * zRev; /* checkin version */
1478 const char * zFileMime = 0; /* File mime type guess */
1479 CheckinMiniInfo cimi; /* Checkin state */
1480 int previewHtmlHeight = 0; /* iframe height (EMs) */
1481 int previewRenderMode = FE_RENDER_GUESS; /* preview mode */
 
1482 Blob err = empty_blob; /* Error report */
1483 Blob endScript = empty_blob; /* Script code to run at the
1484 end. This content will be
1485 combined into a single JS
1486 function call, thus each
@@ -1788,27 +1777,29 @@
1777 blob_appendf(&endScript,
1778 "fossil.page.loadFile('%j','%j');",
1779 zFilename, cimi.zParentUuid);
1780
1781 end_footer:
 
1782 if(stmt.pStmt){
1783 db_finalize(&stmt);
1784 }
1785 if(blob_size(&err)){
1786 CX("<div class='fileedit-error-report'>%s</div>",
1787 blob_str(&err));
1788 }
1789 blob_reset(&err);
1790 CheckinMiniInfo_cleanup(&cimi);
1791 style_emit_script_fossil_bootstrap(0);
1792 style_emit_script_fetch(0);
1793 style_emit_script_tabs(0);
1794 style_emit_script_builtin("fossil.page.fileedit.js",0);
1795 if(blob_size(&endScript)>0){
1796 style_emit_script_tag(0,0);
1797 CX("(function(){\n");
1798 CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
1799 &endScript);
1800 CX("})();");
1801 style_emit_script_tag(1,0);
1802 }
1803 db_end_transaction(0);
1804 style_footer();
1805 }
1806
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,18 +3,21 @@
33
/* Bootstrapping bits for the global.fossil object. Must be
44
loaded after style.c:style_emit_script_tag() has initialized
55
that object.
66
*/
77
8
+ /**
9
+ Returns the current time in something approximating
10
+ ISO-8601 format.
11
+ */
812
const timestring = function f(){
913
if(!f.rx1){
1014
f.rx1 = /\.\d+Z$/;
1115
}
1216
const d = new Date();
1317
return d.toISOString().replace(f.rx1,'').split('T').join(' ');
1418
};
15
-
1619
1720
/*
1821
** By default fossil.message() sends its arguments console.debug(). If
1922
** fossil.message.targetElement is set, it is assumed to be a DOM
2023
** element, its innerText gets assigned to the concatenation of all
@@ -25,11 +28,11 @@
2528
** Returns this object.
2629
*/
2730
global.fossil.message = function f(msg){
2831
const args = Array.prototype.slice.call(arguments,0);
2932
const tgt = f.targetElement;
30
- args.unshift(timestring()+' UTC:');
33
+ args.unshift(timestring(),'UTC:');
3134
if(tgt){
3235
tgt.classList.remove('error');
3336
tgt.innerText = args.join(' ');
3437
}
3538
else{
@@ -52,11 +55,11 @@
5255
** Returns this object.
5356
*/
5457
global.fossil.error = function f(msg){
5558
const args = Array.prototype.slice.call(arguments,0);
5659
const tgt = global.fossil.message.targetElement;
57
- args.unshift(timestring()+' UTC:');
60
+ args.unshift(timestring(),'UTC:');
5861
if(tgt){
5962
tgt.classList.add('error');
6063
tgt.innerText = args.join(' ');
6164
}
6265
else{
6366
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,18 +3,21 @@
3 /* Bootstrapping bits for the global.fossil object. Must be
4 loaded after style.c:style_emit_script_tag() has initialized
5 that object.
6 */
7
 
 
 
 
8 const timestring = function f(){
9 if(!f.rx1){
10 f.rx1 = /\.\d+Z$/;
11 }
12 const d = new Date();
13 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
14 };
15
16
17 /*
18 ** By default fossil.message() sends its arguments console.debug(). If
19 ** fossil.message.targetElement is set, it is assumed to be a DOM
20 ** element, its innerText gets assigned to the concatenation of all
@@ -25,11 +28,11 @@
25 ** Returns this object.
26 */
27 global.fossil.message = function f(msg){
28 const args = Array.prototype.slice.call(arguments,0);
29 const tgt = f.targetElement;
30 args.unshift(timestring()+' UTC:');
31 if(tgt){
32 tgt.classList.remove('error');
33 tgt.innerText = args.join(' ');
34 }
35 else{
@@ -52,11 +55,11 @@
52 ** Returns this object.
53 */
54 global.fossil.error = function f(msg){
55 const args = Array.prototype.slice.call(arguments,0);
56 const tgt = global.fossil.message.targetElement;
57 args.unshift(timestring()+' UTC:');
58 if(tgt){
59 tgt.classList.add('error');
60 tgt.innerText = args.join(' ');
61 }
62 else{
63
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,18 +3,21 @@
3 /* Bootstrapping bits for the global.fossil object. Must be
4 loaded after style.c:style_emit_script_tag() has initialized
5 that object.
6 */
7
8 /**
9 Returns the current time in something approximating
10 ISO-8601 format.
11 */
12 const timestring = function f(){
13 if(!f.rx1){
14 f.rx1 = /\.\d+Z$/;
15 }
16 const d = new Date();
17 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
18 };
 
19
20 /*
21 ** By default fossil.message() sends its arguments console.debug(). If
22 ** fossil.message.targetElement is set, it is assumed to be a DOM
23 ** element, its innerText gets assigned to the concatenation of all
@@ -25,11 +28,11 @@
28 ** Returns this object.
29 */
30 global.fossil.message = function f(msg){
31 const args = Array.prototype.slice.call(arguments,0);
32 const tgt = f.targetElement;
33 args.unshift(timestring(),'UTC:');
34 if(tgt){
35 tgt.classList.remove('error');
36 tgt.innerText = args.join(' ');
37 }
38 else{
@@ -52,11 +55,11 @@
55 ** Returns this object.
56 */
57 global.fossil.error = function f(msg){
58 const args = Array.prototype.slice.call(arguments,0);
59 const tgt = global.fossil.message.targetElement;
60 args.unshift(timestring(),'UTC:');
61 if(tgt){
62 tgt.classList.add('error');
63 tgt.innerText = args.join(' ');
64 }
65 else{
66
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,67 @@
11
"use strict";
22
/**
3
- Documented in style.c:style_emit_script_fetch(). Requires that
4
- window.fossil has already been set up (which happens via the routine
5
- which emits this code C-side).
3
+ Requires that window.fossil has already been set up.
4
+
5
+ window.fossil.fetch() is an HTTP request/response mini-framework
6
+ similar (but not identical) to the not-quite-ubiquitous
7
+ window.fetch().
8
+
9
+ JS usages:
10
+
11
+ fossil.fetch( URI [, onLoadCallback] );
12
+
13
+ fossil.fetch( URI [, optionsObject = {}] );
14
+
15
+ Noting that URI must be relative to the top of the repository and
16
+ should not start with a slash (if it does, it is stripped). It gets
17
+ the equivalent of "%R/" prepended to it.
18
+
19
+ The optionsObject may be an onload callback or an object with any
20
+ of these properties:
21
+
22
+ - onload: callback(responseData) (default = output response to
23
+ the console).
24
+
25
+ - onerror: callback(XHR onload event | exception)
26
+ (default = event or exception to the console).
27
+
28
+ - method: 'POST' | 'GET' (default = 'GET')
29
+
30
+ - payload: anything acceptable by XHR2.send(ARG) (DOMString,
31
+ Document, FormData, Blob, File, ArrayBuffer), or a plain object or
32
+ array, either of which gets JSON.stringify()'d. If payload is set
33
+ then the method is automatically set to 'POST'. If an object/array
34
+ is converted to JSON, the contentType option is automatically set
35
+ to 'application/json'. By default XHR2 will set the content type
36
+ based on the payload type.
37
+
38
+ - contentType: Optional request content type when POSTing. Ignored
39
+ if the method is not 'POST'.
40
+
41
+ - responseType: optional string. One of ("text", "arraybuffer",
42
+ "blob", or "document") (as specified by XHR2). Default = "text".
43
+ As an extension, it supports "json", which tells it that the
44
+ response is expected to be text and that it should be JSON.parse()d
45
+ before passing it on to the onload() callback.
46
+
47
+ - urlParams: string|object. If a string, it is assumed to be a
48
+ URI-encoded list of params in the form "key1=val1&key2=val2...",
49
+ with NO leading '?'. If it is an object, all of its properties get
50
+ converted to that form. Either way, the parameters get appended to
51
+ the URL before submitting the request.
52
+
53
+ When an options object does not provide onload() or onerror()
54
+ handlers of its own, this function falls back to
55
+ fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
56
+ default implementations route the data through the dev console and
57
+ (for onerror()) through fossil.error(). Individual pages may
58
+ overwrite those members to provide default implementations suitable
59
+ for the page's use.
60
+
61
+ Returns this object, noting that the XHR request is asynchronous,
62
+ and still in transit (or has yet to be sent) when that happens.
663
*/
764
window.fossil.fetch = function f(uri,opt){
865
if(!f.onerror){
966
f.onerror = function(e/*event or exception*/){
1067
console.error("Ajax error:",e);
@@ -13,12 +70,12 @@
1370
}
1471
else if(e.originalTarget && e.originalTarget.responseType==='text'){
1572
const txt = e.originalTarget.responseText;
1673
try{
1774
/* The convention from the /filepage_xyz routes is to
18
- ** return error responses in JSON form if possible:
19
- ** {error: "..."}
75
+ return error responses in JSON form if possible:
76
+ {error: "..."}
2077
*/
2178
const j = JSON.parse(txt);
2279
console.error("Error JSON:",j);
2380
if(j.error){ fossil.error(j.error) };
2481
}catch(e){/* Try harder */
2582
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,67 @@
1 "use strict";
2 /**
3 Documented in style.c:style_emit_script_fetch(). Requires that
4 window.fossil has already been set up (which happens via the routine
5 which emits this code C-side).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6 */
7 window.fossil.fetch = function f(uri,opt){
8 if(!f.onerror){
9 f.onerror = function(e/*event or exception*/){
10 console.error("Ajax error:",e);
@@ -13,12 +70,12 @@
13 }
14 else if(e.originalTarget && e.originalTarget.responseType==='text'){
15 const txt = e.originalTarget.responseText;
16 try{
17 /* The convention from the /filepage_xyz routes is to
18 ** return error responses in JSON form if possible:
19 ** {error: "..."}
20 */
21 const j = JSON.parse(txt);
22 console.error("Error JSON:",j);
23 if(j.error){ fossil.error(j.error) };
24 }catch(e){/* Try harder */
25
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,67 @@
1 "use strict";
2 /**
3 Requires that window.fossil has already been set up.
4
5 window.fossil.fetch() is an HTTP request/response mini-framework
6 similar (but not identical) to the not-quite-ubiquitous
7 window.fetch().
8
9 JS usages:
10
11 fossil.fetch( URI [, onLoadCallback] );
12
13 fossil.fetch( URI [, optionsObject = {}] );
14
15 Noting that URI must be relative to the top of the repository and
16 should not start with a slash (if it does, it is stripped). It gets
17 the equivalent of "%R/" prepended to it.
18
19 The optionsObject may be an onload callback or an object with any
20 of these properties:
21
22 - onload: callback(responseData) (default = output response to
23 the console).
24
25 - onerror: callback(XHR onload event | exception)
26 (default = event or exception to the console).
27
28 - method: 'POST' | 'GET' (default = 'GET')
29
30 - payload: anything acceptable by XHR2.send(ARG) (DOMString,
31 Document, FormData, Blob, File, ArrayBuffer), or a plain object or
32 array, either of which gets JSON.stringify()'d. If payload is set
33 then the method is automatically set to 'POST'. If an object/array
34 is converted to JSON, the contentType option is automatically set
35 to 'application/json'. By default XHR2 will set the content type
36 based on the payload type.
37
38 - contentType: Optional request content type when POSTing. Ignored
39 if the method is not 'POST'.
40
41 - responseType: optional string. One of ("text", "arraybuffer",
42 "blob", or "document") (as specified by XHR2). Default = "text".
43 As an extension, it supports "json", which tells it that the
44 response is expected to be text and that it should be JSON.parse()d
45 before passing it on to the onload() callback.
46
47 - urlParams: string|object. If a string, it is assumed to be a
48 URI-encoded list of params in the form "key1=val1&key2=val2...",
49 with NO leading '?'. If it is an object, all of its properties get
50 converted to that form. Either way, the parameters get appended to
51 the URL before submitting the request.
52
53 When an options object does not provide onload() or onerror()
54 handlers of its own, this function falls back to
55 fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
56 default implementations route the data through the dev console and
57 (for onerror()) through fossil.error(). Individual pages may
58 overwrite those members to provide default implementations suitable
59 for the page's use.
60
61 Returns this object, noting that the XHR request is asynchronous,
62 and still in transit (or has yet to be sent) when that happens.
63 */
64 window.fossil.fetch = function f(uri,opt){
65 if(!f.onerror){
66 f.onerror = function(e/*event or exception*/){
67 console.error("Ajax error:",e);
@@ -13,12 +70,12 @@
70 }
71 else if(e.originalTarget && e.originalTarget.responseType==='text'){
72 const txt = e.originalTarget.responseText;
73 try{
74 /* The convention from the /filepage_xyz routes is to
75 return error responses in JSON form if possible:
76 {error: "..."}
77 */
78 const j = JSON.parse(txt);
79 console.error("Error JSON:",j);
80 if(j.error){ fossil.error(j.error) };
81 }catch(e){/* Try harder */
82
+90 -98
--- src/style.c
+++ src/style.c
@@ -1425,20 +1425,28 @@
14251425
}
14261426
14271427
/*
14281428
** The first time this is called, it emits code to install and
14291429
** bootstrap the window.fossil object, using the built-in file
1430
-** fossil.bootstrap.js (not to be confused with bootstrap.js). It does
1431
-** NOT wrap that in a script tag because it's called from
1432
-** style_emit_script_tag().
1430
+** fossil.bootstrap.js (not to be confused with bootstrap.js).
14331431
**
14341432
** Subsequent calls are no-ops.
1433
+**
1434
+** If passed a true value, it emits the contents directly to the page
1435
+** output, else it emits a script tag with a src=builtin/... to load
1436
+** the script. It always outputs a small pre-bootstrap element in its
1437
+** own script tag to initialize parts which need C-runtime-level
1438
+** information, because loading the main fossil.bootstrap.js either
1439
+** inline or via a <script src=...>, as specified by the first
1440
+** argument.
14351441
*/
1436
-static void style_emit_script_fossil_bootstrap(){
1442
+void style_emit_script_fossil_bootstrap(int asInline){
14371443
static int once = 0;
14381444
if(0==once++){
1439
- /* Set up the generic/app-agnostic parts of window.fossil */
1445
+ /* Set up the generic/app-agnostic parts of window.fossil
1446
+ ** which require C-level state... */
1447
+ style_emit_script_tag(0,0);
14401448
CX("(function(){\n"
14411449
"if(!window.fossil) window.fossil={};\n"
14421450
"window.fossil.version = \"%j\";\n"
14431451
/* fossil.rootPath is the top-most CGI/server path,
14441452
including a trailing slash. */
@@ -1450,137 +1458,121 @@
14501458
** own page-specific state.
14511459
*/
14521460
CX("window.fossil.page = {"
14531461
"page:\"%T\""
14541462
"};\n", g.zPath);
1463
+ CX("})();\n");
14551464
/* The remaining code is not dependent on C-runtime state... */
1456
- CX("%s\n", builtin_text("fossil.bootstrap.js"));
1457
- CX("})();\n");
1465
+ if(asInline){
1466
+ CX("%s\n", builtin_text("fossil.bootstrap.js"));
1467
+ }
1468
+ style_emit_script_tag(1,0);
1469
+ if(asInline==0){
1470
+ style_emit_script_tag(0,"builtin/fossil.bootstrap.js");
1471
+ }
14581472
}
14591473
}
14601474
14611475
/*
1462
-** If passed 0, it emits a script opener tag with this request's
1463
-** nonce. If passed non-0 it emits a script closing tag.
1476
+** If passed 0 as its first argument, it emits a script opener tag
1477
+** with this request's nonce. If passed non-0 it emits a script
1478
+** closing tag. Mnemonic for remembering the order in which to pass 0
1479
+** or 1 as the first argument to this function: 0 comes before 1.
1480
+**
1481
+** If passed 0 as its first argument and a non-NULL/non-empty zSrc,
1482
+** then it instead emits:
1483
+**
1484
+** <script src='%R/{{zSrc}}'></script>
1485
+**
1486
+** zSrc is always assumed to be a repository-relative path without
1487
+** a leading slash, and has %R/ prepended to it.
14641488
**
1465
-** The very first time it is called, it emits some bootstrapping JS
1466
-** code immediately after the script opener. Specifically, it defines
1467
-** window.fossil if it's not already defined, and sets up its most
1468
-** basic functionality.
1489
+** Meaning that no follow-up call to pass a non-0 first argument
1490
+** to close the tag. zSrc is ignored if the first argument is not
1491
+** 0.
1492
+**
14691493
*/
1470
-void style_emit_script_tag(int phase){
1471
- static int once = 0;
1472
- if(0==phase){
1473
- CX("<script nonce='%s'>", style_nonce());
1474
- if(0==once++){
1475
- style_emit_script_fossil_bootstrap();
1494
+void style_emit_script_tag(int isCloser, const char * zSrc){
1495
+ if(0==isCloser){
1496
+ if(zSrc!=0 && zSrc[0]!=0){
1497
+ CX("<script src='%R/%T'></script>\n", zSrc);
1498
+ }else{
1499
+ CX("<script nonce='%s'>", style_nonce());
14761500
}
14771501
}else{
14781502
CX("</script>\n");
14791503
}
14801504
}
14811505
14821506
/*
1483
-** Emits the text of builtin_text(zName), which is assumed to be
1484
-** JavaScript code, and wrapps that in a pair of calls to
1485
-** style_emit_script_tag().
1507
+** Emits a script tag which uses content from a builtin script file.
1508
+**
1509
+** If asInline is true, it is emitted directly as an opening tag, the
1510
+** content of the zName builtin file, and a closing tag. If it is false,
1511
+** a script tag loading it via src=builtin/{{zName}} is emitted.
14861512
*/
1487
-void style_emit_script_builtin(char const * zName){
1488
- style_emit_script_tag(0);
1513
+void style_emit_script_builtin(char const * zName, int asInline){
1514
+ if(asInline){
1515
+ style_emit_script_tag(0,0);
14891516
CX("%s", builtin_text(zName));
1490
- style_emit_script_tag(1);
1517
+ style_emit_script_tag(1,0);
1518
+ }else{
1519
+ char * zFull = mprintf("builtin/%s",zName);
1520
+ style_emit_script_tag(0,zFull);
1521
+ fossil_free(zFull);
1522
+ }
14911523
}
14921524
14931525
/*
1494
-** The first time this is called, it emits a JS script block,
1495
-** including tags, using the contents of the built-in file
1496
-** fossil.fetch.js, which defines window.fossil.fetch(), an HTTP
1497
-** request/response mini-framework similar (but not identical) to the
1498
-** not-quite-ubiquitous window.fetch(). It calls
1499
-** style_emit_script_tag(), which may inject other JS bootstrapping
1500
-** bits. Subsequent calls are no-ops.
1501
-**
1502
-** JS usages:
1503
-**
1504
-** fossil.fetch( URI [, onLoadCallback] );
1505
-**
1506
-** fossil.fetch( URI [, optionsObject = {}] );
1507
-**
1508
-** Noting that URI must be relative to the top of the repository and
1509
-** should not start with a slash (if it does, it is stripped). It gets
1510
-** the equivalent of "%R/" prepended to it.
1511
-**
1512
-** The optionsObject may be an onload callback or an object with any
1513
-** of these properties:
1514
-**
1515
-** - onload: callback(responseData) (default = output response to
1516
-** the console).
1517
-**
1518
-** - onerror: callback(XHR onload event | exception)
1519
-** (default = event or exception to the console).
1520
-**
1521
-** - method: 'POST' | 'GET' (default = 'GET')
1522
-**
1523
-** - payload: anything acceptable by XHR2.send(ARG) (DOMString,
1524
-** Document, FormData, Blob, File, ArrayBuffer), or a plain object
1525
-** or array, either of which gets JSON.stringify()'d. If payload is
1526
-** set then the method is automatically set to 'POST'. If an
1527
-** object/array is converted to JSON, the contentType option is
1528
-** automatically set to 'application/json'. By default XHR2 will set
1529
-** the content type based on the payload type.
1530
-**
1531
-** - contentType: Optional request content type when POSTing. Ignored
1532
-** if the method is not 'POST'.
1533
-**
1534
-** - responseType: optional string. One of ("text", "arraybuffer",
1535
-** "blob", or "document") (as specified by XHR2). Default = "text".
1536
-** As an extension, it supports "json", which tells it that the
1537
-** response is expected to be text and that it should be
1538
-** JSON.parse()d before passing it on to the onload() callback.
1539
-**
1540
-** - urlParams: string|object. If a string, it is assumed to be a
1541
-** URI-encoded list of params in the form "key1=val1&key2=val2...",
1542
-** with NO leading '?'. If it is an object, all of its properties
1543
-** get converted to that form. Either way, the parameters get
1544
-** appended to the URL before submitting the request.
1545
-**
1546
-** When an options object does not provide onload() or onerror()
1547
-** handlers of its own, this function falls back to
1548
-** fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
1549
-** default implementations route the data through the dev console and
1550
-** (for onerror()) through fossil.error(). Individual pages may
1551
-** overwrite those members to provide default implementations suitable
1552
-** for the page's use.
1553
-**
1554
-** Returns this object, noting that the XHR request is asynchronous,
1555
-** and still in transit (or has yet to be sent) when that happens.
1556
-*/
1557
-void style_emit_script_fetch(){
1526
+** The first time this is called, it emits the JS code from the
1527
+** built-in file fossil.fossil.js. Subsequent calls are no-ops.
1528
+**
1529
+** If passed a true value, it emits the contents directly
1530
+** to the page output, else it emits a script tag with a
1531
+** src=builtin/... to load the script.
1532
+**
1533
+** Note that this code relies on that loaded via
1534
+** style_emit_script_fossil_bootstrap() but it does not call that
1535
+** routine.
1536
+*/
1537
+void style_emit_script_fetch(int asInline){
15581538
static int once = 0;
15591539
if(0==once++){
1560
- style_emit_script_builtin("fossil.fetch.js");
1540
+ style_emit_script_builtin("fossil.fetch.js", asInline);
15611541
}
15621542
}
15631543
15641544
/*
15651545
** The first time this is called, it emits the JS code from the
15661546
** built-in file fossil.dom.js. Subsequent calls are no-ops.
1547
+**
1548
+** If passed a true value, it emits the contents directly
1549
+** to the page output, else it emits a script tag with a
1550
+** src=builtin/... to load the script.
1551
+**
1552
+** Note that this code relies on that loaded via
1553
+** style_emit_script_fossil_bootstrap(), but it does not call that
1554
+** routine.
15671555
*/
1568
-void style_emit_script_dom(){
1556
+void style_emit_script_dom(int asInline){
15691557
static int once = 0;
15701558
if(0==once++){
1571
- style_emit_script_builtin("fossil.dom.js");
1559
+ style_emit_script_builtin("fossil.dom.js", asInline);
15721560
}
15731561
}
15741562
15751563
/*
1576
-** The first time this is called, it calls style_emit_script_dom() and
1577
-** emits the JS code from the built-in file fossil.tabs.js.
1578
-** Subsequent calls are no-ops.
1564
+** The first time this is called, it calls style_emit_script_dom(),
1565
+** passing it the given asInline value, and emits the JS code from the
1566
+** built-in file fossil.tabs.js. Subsequent calls are no-ops.
1567
+**
1568
+** If passed a true value, it emits the contents directly
1569
+** to the page output, else it emits a script tag with a
1570
+** src=builtin/... to load the script.
15791571
*/
1580
-void style_emit_script_tabs(){
1572
+void style_emit_script_tabs(int asInline){
15811573
static int once = 0;
15821574
if(0==once++){
1583
- style_emit_script_dom();
1584
- style_emit_script_builtin("fossil.tabs.js");
1575
+ style_emit_script_dom(asInline);
1576
+ style_emit_script_builtin("fossil.tabs.js",asInline);
15851577
}
15861578
}
15871579
--- src/style.c
+++ src/style.c
@@ -1425,20 +1425,28 @@
1425 }
1426
1427 /*
1428 ** The first time this is called, it emits code to install and
1429 ** bootstrap the window.fossil object, using the built-in file
1430 ** fossil.bootstrap.js (not to be confused with bootstrap.js). It does
1431 ** NOT wrap that in a script tag because it's called from
1432 ** style_emit_script_tag().
1433 **
1434 ** Subsequent calls are no-ops.
 
 
 
 
 
 
 
 
1435 */
1436 static void style_emit_script_fossil_bootstrap(){
1437 static int once = 0;
1438 if(0==once++){
1439 /* Set up the generic/app-agnostic parts of window.fossil */
 
 
1440 CX("(function(){\n"
1441 "if(!window.fossil) window.fossil={};\n"
1442 "window.fossil.version = \"%j\";\n"
1443 /* fossil.rootPath is the top-most CGI/server path,
1444 including a trailing slash. */
@@ -1450,137 +1458,121 @@
1450 ** own page-specific state.
1451 */
1452 CX("window.fossil.page = {"
1453 "page:\"%T\""
1454 "};\n", g.zPath);
 
1455 /* The remaining code is not dependent on C-runtime state... */
1456 CX("%s\n", builtin_text("fossil.bootstrap.js"));
1457 CX("})();\n");
 
 
 
 
 
1458 }
1459 }
1460
1461 /*
1462 ** If passed 0, it emits a script opener tag with this request's
1463 ** nonce. If passed non-0 it emits a script closing tag.
 
 
 
 
 
 
 
 
 
 
1464 **
1465 ** The very first time it is called, it emits some bootstrapping JS
1466 ** code immediately after the script opener. Specifically, it defines
1467 ** window.fossil if it's not already defined, and sets up its most
1468 ** basic functionality.
1469 */
1470 void style_emit_script_tag(int phase){
1471 static int once = 0;
1472 if(0==phase){
1473 CX("<script nonce='%s'>", style_nonce());
1474 if(0==once++){
1475 style_emit_script_fossil_bootstrap();
1476 }
1477 }else{
1478 CX("</script>\n");
1479 }
1480 }
1481
1482 /*
1483 ** Emits the text of builtin_text(zName), which is assumed to be
1484 ** JavaScript code, and wrapps that in a pair of calls to
1485 ** style_emit_script_tag().
 
 
1486 */
1487 void style_emit_script_builtin(char const * zName){
1488 style_emit_script_tag(0);
 
1489 CX("%s", builtin_text(zName));
1490 style_emit_script_tag(1);
 
 
 
 
 
1491 }
1492
1493 /*
1494 ** The first time this is called, it emits a JS script block,
1495 ** including tags, using the contents of the built-in file
1496 ** fossil.fetch.js, which defines window.fossil.fetch(), an HTTP
1497 ** request/response mini-framework similar (but not identical) to the
1498 ** not-quite-ubiquitous window.fetch(). It calls
1499 ** style_emit_script_tag(), which may inject other JS bootstrapping
1500 ** bits. Subsequent calls are no-ops.
1501 **
1502 ** JS usages:
1503 **
1504 ** fossil.fetch( URI [, onLoadCallback] );
1505 **
1506 ** fossil.fetch( URI [, optionsObject = {}] );
1507 **
1508 ** Noting that URI must be relative to the top of the repository and
1509 ** should not start with a slash (if it does, it is stripped). It gets
1510 ** the equivalent of "%R/" prepended to it.
1511 **
1512 ** The optionsObject may be an onload callback or an object with any
1513 ** of these properties:
1514 **
1515 ** - onload: callback(responseData) (default = output response to
1516 ** the console).
1517 **
1518 ** - onerror: callback(XHR onload event | exception)
1519 ** (default = event or exception to the console).
1520 **
1521 ** - method: 'POST' | 'GET' (default = 'GET')
1522 **
1523 ** - payload: anything acceptable by XHR2.send(ARG) (DOMString,
1524 ** Document, FormData, Blob, File, ArrayBuffer), or a plain object
1525 ** or array, either of which gets JSON.stringify()'d. If payload is
1526 ** set then the method is automatically set to 'POST'. If an
1527 ** object/array is converted to JSON, the contentType option is
1528 ** automatically set to 'application/json'. By default XHR2 will set
1529 ** the content type based on the payload type.
1530 **
1531 ** - contentType: Optional request content type when POSTing. Ignored
1532 ** if the method is not 'POST'.
1533 **
1534 ** - responseType: optional string. One of ("text", "arraybuffer",
1535 ** "blob", or "document") (as specified by XHR2). Default = "text".
1536 ** As an extension, it supports "json", which tells it that the
1537 ** response is expected to be text and that it should be
1538 ** JSON.parse()d before passing it on to the onload() callback.
1539 **
1540 ** - urlParams: string|object. If a string, it is assumed to be a
1541 ** URI-encoded list of params in the form "key1=val1&key2=val2...",
1542 ** with NO leading '?'. If it is an object, all of its properties
1543 ** get converted to that form. Either way, the parameters get
1544 ** appended to the URL before submitting the request.
1545 **
1546 ** When an options object does not provide onload() or onerror()
1547 ** handlers of its own, this function falls back to
1548 ** fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
1549 ** default implementations route the data through the dev console and
1550 ** (for onerror()) through fossil.error(). Individual pages may
1551 ** overwrite those members to provide default implementations suitable
1552 ** for the page's use.
1553 **
1554 ** Returns this object, noting that the XHR request is asynchronous,
1555 ** and still in transit (or has yet to be sent) when that happens.
1556 */
1557 void style_emit_script_fetch(){
1558 static int once = 0;
1559 if(0==once++){
1560 style_emit_script_builtin("fossil.fetch.js");
1561 }
1562 }
1563
1564 /*
1565 ** The first time this is called, it emits the JS code from the
1566 ** built-in file fossil.dom.js. Subsequent calls are no-ops.
 
 
 
 
 
 
 
 
1567 */
1568 void style_emit_script_dom(){
1569 static int once = 0;
1570 if(0==once++){
1571 style_emit_script_builtin("fossil.dom.js");
1572 }
1573 }
1574
1575 /*
1576 ** The first time this is called, it calls style_emit_script_dom() and
1577 ** emits the JS code from the built-in file fossil.tabs.js.
1578 ** Subsequent calls are no-ops.
 
 
 
 
1579 */
1580 void style_emit_script_tabs(){
1581 static int once = 0;
1582 if(0==once++){
1583 style_emit_script_dom();
1584 style_emit_script_builtin("fossil.tabs.js");
1585 }
1586 }
1587
--- src/style.c
+++ src/style.c
@@ -1425,20 +1425,28 @@
1425 }
1426
1427 /*
1428 ** The first time this is called, it emits code to install and
1429 ** bootstrap the window.fossil object, using the built-in file
1430 ** fossil.bootstrap.js (not to be confused with bootstrap.js).
 
 
1431 **
1432 ** Subsequent calls are no-ops.
1433 **
1434 ** If passed a true value, it emits the contents directly to the page
1435 ** output, else it emits a script tag with a src=builtin/... to load
1436 ** the script. It always outputs a small pre-bootstrap element in its
1437 ** own script tag to initialize parts which need C-runtime-level
1438 ** information, because loading the main fossil.bootstrap.js either
1439 ** inline or via a <script src=...>, as specified by the first
1440 ** argument.
1441 */
1442 void style_emit_script_fossil_bootstrap(int asInline){
1443 static int once = 0;
1444 if(0==once++){
1445 /* Set up the generic/app-agnostic parts of window.fossil
1446 ** which require C-level state... */
1447 style_emit_script_tag(0,0);
1448 CX("(function(){\n"
1449 "if(!window.fossil) window.fossil={};\n"
1450 "window.fossil.version = \"%j\";\n"
1451 /* fossil.rootPath is the top-most CGI/server path,
1452 including a trailing slash. */
@@ -1450,137 +1458,121 @@
1458 ** own page-specific state.
1459 */
1460 CX("window.fossil.page = {"
1461 "page:\"%T\""
1462 "};\n", g.zPath);
1463 CX("})();\n");
1464 /* The remaining code is not dependent on C-runtime state... */
1465 if(asInline){
1466 CX("%s\n", builtin_text("fossil.bootstrap.js"));
1467 }
1468 style_emit_script_tag(1,0);
1469 if(asInline==0){
1470 style_emit_script_tag(0,"builtin/fossil.bootstrap.js");
1471 }
1472 }
1473 }
1474
1475 /*
1476 ** If passed 0 as its first argument, it emits a script opener tag
1477 ** with this request's nonce. If passed non-0 it emits a script
1478 ** closing tag. Mnemonic for remembering the order in which to pass 0
1479 ** or 1 as the first argument to this function: 0 comes before 1.
1480 **
1481 ** If passed 0 as its first argument and a non-NULL/non-empty zSrc,
1482 ** then it instead emits:
1483 **
1484 ** <script src='%R/{{zSrc}}'></script>
1485 **
1486 ** zSrc is always assumed to be a repository-relative path without
1487 ** a leading slash, and has %R/ prepended to it.
1488 **
1489 ** Meaning that no follow-up call to pass a non-0 first argument
1490 ** to close the tag. zSrc is ignored if the first argument is not
1491 ** 0.
1492 **
1493 */
1494 void style_emit_script_tag(int isCloser, const char * zSrc){
1495 if(0==isCloser){
1496 if(zSrc!=0 && zSrc[0]!=0){
1497 CX("<script src='%R/%T'></script>\n", zSrc);
1498 }else{
1499 CX("<script nonce='%s'>", style_nonce());
1500 }
1501 }else{
1502 CX("</script>\n");
1503 }
1504 }
1505
1506 /*
1507 ** Emits a script tag which uses content from a builtin script file.
1508 **
1509 ** If asInline is true, it is emitted directly as an opening tag, the
1510 ** content of the zName builtin file, and a closing tag. If it is false,
1511 ** a script tag loading it via src=builtin/{{zName}} is emitted.
1512 */
1513 void style_emit_script_builtin(char const * zName, int asInline){
1514 if(asInline){
1515 style_emit_script_tag(0,0);
1516 CX("%s", builtin_text(zName));
1517 style_emit_script_tag(1,0);
1518 }else{
1519 char * zFull = mprintf("builtin/%s",zName);
1520 style_emit_script_tag(0,zFull);
1521 fossil_free(zFull);
1522 }
1523 }
1524
1525 /*
1526 ** The first time this is called, it emits the JS code from the
1527 ** built-in file fossil.fossil.js. Subsequent calls are no-ops.
1528 **
1529 ** If passed a true value, it emits the contents directly
1530 ** to the page output, else it emits a script tag with a
1531 ** src=builtin/... to load the script.
1532 **
1533 ** Note that this code relies on that loaded via
1534 ** style_emit_script_fossil_bootstrap() but it does not call that
1535 ** routine.
1536 */
1537 void style_emit_script_fetch(int asInline){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1538 static int once = 0;
1539 if(0==once++){
1540 style_emit_script_builtin("fossil.fetch.js", asInline);
1541 }
1542 }
1543
1544 /*
1545 ** The first time this is called, it emits the JS code from the
1546 ** built-in file fossil.dom.js. Subsequent calls are no-ops.
1547 **
1548 ** If passed a true value, it emits the contents directly
1549 ** to the page output, else it emits a script tag with a
1550 ** src=builtin/... to load the script.
1551 **
1552 ** Note that this code relies on that loaded via
1553 ** style_emit_script_fossil_bootstrap(), but it does not call that
1554 ** routine.
1555 */
1556 void style_emit_script_dom(int asInline){
1557 static int once = 0;
1558 if(0==once++){
1559 style_emit_script_builtin("fossil.dom.js", asInline);
1560 }
1561 }
1562
1563 /*
1564 ** The first time this is called, it calls style_emit_script_dom(),
1565 ** passing it the given asInline value, and emits the JS code from the
1566 ** built-in file fossil.tabs.js. Subsequent calls are no-ops.
1567 **
1568 ** If passed a true value, it emits the contents directly
1569 ** to the page output, else it emits a script tag with a
1570 ** src=builtin/... to load the script.
1571 */
1572 void style_emit_script_tabs(int asInline){
1573 static int once = 0;
1574 if(0==once++){
1575 style_emit_script_dom(asInline);
1576 style_emit_script_builtin("fossil.tabs.js",asInline);
1577 }
1578 }
1579

Keyboard Shortcuts

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