Fossil SCM

fossil.pikchr.addSrcView() now tags each processed SVG element to avoid potentially processing the same one multiple times. Added fossil.pikchr support to /doc, /wiki, and /wikiedit/fileedit previews. This is harmless if there are no pikchrs or JS is disabled.

stephan 2020-09-15 16:40 trunk
Commit 83f03e91c455e513001d53b2034388b068f6fcb294e5eb0267c5cbdde65c3698
+22
--- src/doc.c
+++ src/doc.c
@@ -397,10 +397,27 @@
397397
assert(!"cannot happen - invalid tokenizerState value.");
398398
}
399399
}
400400
return 0;
401401
}
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
+ if(!builtin_bundle_all_fossil_js_apis()){
410
+ builtin_emit_fossil_js_apis("dom", "copybutton",
411
+ "pikchr", 0);
412
+ }
413
+ style_emit_script_tag(0,0);
414
+ CX("window.addEventListener('load', "
415
+ "()=>window.fossil.pikchr.addSrcView(), "
416
+ "false);\n");
417
+ style_emit_script_tag(1,0);
418
+}
402419
403420
/*
404421
** Guess the mime-type of a document based on its name.
405422
*/
406423
const char *mimetype_from_name(const char *zName){
@@ -750,10 +767,11 @@
750767
wiki_convert(&tail, 0, WIKI_BUTTONS);
751768
}else{
752769
style_header("%s", zDefaultTitle);
753770
wiki_convert(pBody, 0, WIKI_BUTTONS);
754771
}
772
+ document_emit_js();
755773
style_footer();
756774
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
757775
Blob tail = BLOB_INITIALIZER;
758776
markdown_to_html(pBody, &title, &tail);
759777
if( blob_size(&title)>0 ){
@@ -760,22 +778,25 @@
760778
style_header("%s", blob_str(&title));
761779
}else{
762780
style_header("%s", zDefaultTitle);
763781
}
764782
convert_href_and_output(&tail);
783
+ document_emit_js();
765784
style_footer();
766785
}else if( fossil_strcmp(zMime, "text/plain")==0 ){
767786
style_header("%s", zDefaultTitle);
768787
@ <blockquote><pre>
769788
@ %h(blob_str(pBody))
770789
@ </pre></blockquote>
790
+ document_emit_js();
771791
style_footer();
772792
}else if( fossil_strcmp(zMime, "text/html")==0
773793
&& doc_is_embedded_html(pBody, &title) ){
774794
if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
775795
style_header("%s", blob_str(&title));
776796
convert_href_and_output(pBody);
797
+ document_emit_js();
777798
style_footer();
778799
#ifdef FOSSIL_ENABLE_TH1_DOCS
779800
}else if( Th_AreDocsEnabled() &&
780801
fossil_strcmp(zMime, "application/x-th1")==0 ){
781802
int raw = P("raw")!=0;
@@ -792,10 +813,11 @@
792813
}
793814
}else{
794815
Th_Render(blob_str(pBody));
795816
}
796817
if( !raw ){
818
+ document_emit_js();
797819
style_footer();
798820
}
799821
#endif
800822
}else{
801823
fossil_free(style_csp(1));
802824
--- src/doc.c
+++ src/doc.c
@@ -397,10 +397,27 @@
397 assert(!"cannot happen - invalid tokenizerState value.");
398 }
399 }
400 return 0;
401 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
403 /*
404 ** Guess the mime-type of a document based on its name.
405 */
406 const char *mimetype_from_name(const char *zName){
@@ -750,10 +767,11 @@
750 wiki_convert(&tail, 0, WIKI_BUTTONS);
751 }else{
752 style_header("%s", zDefaultTitle);
753 wiki_convert(pBody, 0, WIKI_BUTTONS);
754 }
 
755 style_footer();
756 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
757 Blob tail = BLOB_INITIALIZER;
758 markdown_to_html(pBody, &title, &tail);
759 if( blob_size(&title)>0 ){
@@ -760,22 +778,25 @@
760 style_header("%s", blob_str(&title));
761 }else{
762 style_header("%s", zDefaultTitle);
763 }
764 convert_href_and_output(&tail);
 
765 style_footer();
766 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
767 style_header("%s", zDefaultTitle);
768 @ <blockquote><pre>
769 @ %h(blob_str(pBody))
770 @ </pre></blockquote>
 
771 style_footer();
772 }else if( fossil_strcmp(zMime, "text/html")==0
773 && doc_is_embedded_html(pBody, &title) ){
774 if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
775 style_header("%s", blob_str(&title));
776 convert_href_and_output(pBody);
 
777 style_footer();
778 #ifdef FOSSIL_ENABLE_TH1_DOCS
779 }else if( Th_AreDocsEnabled() &&
780 fossil_strcmp(zMime, "application/x-th1")==0 ){
781 int raw = P("raw")!=0;
@@ -792,10 +813,11 @@
792 }
793 }else{
794 Th_Render(blob_str(pBody));
795 }
796 if( !raw ){
 
797 style_footer();
798 }
799 #endif
800 }else{
801 fossil_free(style_csp(1));
802
--- src/doc.c
+++ src/doc.c
@@ -397,10 +397,27 @@
397 assert(!"cannot happen - invalid tokenizerState value.");
398 }
399 }
400 return 0;
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 if(!builtin_bundle_all_fossil_js_apis()){
410 builtin_emit_fossil_js_apis("dom", "copybutton",
411 "pikchr", 0);
412 }
413 style_emit_script_tag(0,0);
414 CX("window.addEventListener('load', "
415 "()=>window.fossil.pikchr.addSrcView(), "
416 "false);\n");
417 style_emit_script_tag(1,0);
418 }
419
420 /*
421 ** Guess the mime-type of a document based on its name.
422 */
423 const char *mimetype_from_name(const char *zName){
@@ -750,10 +767,11 @@
767 wiki_convert(&tail, 0, WIKI_BUTTONS);
768 }else{
769 style_header("%s", zDefaultTitle);
770 wiki_convert(pBody, 0, WIKI_BUTTONS);
771 }
772 document_emit_js();
773 style_footer();
774 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
775 Blob tail = BLOB_INITIALIZER;
776 markdown_to_html(pBody, &title, &tail);
777 if( blob_size(&title)>0 ){
@@ -760,22 +778,25 @@
778 style_header("%s", blob_str(&title));
779 }else{
780 style_header("%s", zDefaultTitle);
781 }
782 convert_href_and_output(&tail);
783 document_emit_js();
784 style_footer();
785 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
786 style_header("%s", zDefaultTitle);
787 @ <blockquote><pre>
788 @ %h(blob_str(pBody))
789 @ </pre></blockquote>
790 document_emit_js();
791 style_footer();
792 }else if( fossil_strcmp(zMime, "text/html")==0
793 && doc_is_embedded_html(pBody, &title) ){
794 if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
795 style_header("%s", blob_str(&title));
796 convert_href_and_output(pBody);
797 document_emit_js();
798 style_footer();
799 #ifdef FOSSIL_ENABLE_TH1_DOCS
800 }else if( Th_AreDocsEnabled() &&
801 fossil_strcmp(zMime, "application/x-th1")==0 ){
802 int raw = P("raw")!=0;
@@ -792,10 +813,11 @@
813 }
814 }else{
815 Th_Render(blob_str(pBody));
816 }
817 if( !raw ){
818 document_emit_js();
819 style_footer();
820 }
821 #endif
822 }else{
823 fossil_free(style_csp(1));
824
+2 -1
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,12 @@
19891989
}
19901990
CX("</div>"/*#fileedit-tab-help*/);
19911991
19921992
if(!builtin_bundle_all_fossil_js_apis()){
19931993
builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1994
- "storage", "popupwidget", 0);
1994
+ "storage", "popupwidget", "copybutton",
1995
+ "pikchr", 0);
19951996
}
19961997
/*
19971998
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
19981999
** used for dynamically toggling certain UI components on and off.
19992000
** Must come after window.fossil has been intialized and before
20002001
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,12 @@
1989 }
1990 CX("</div>"/*#fileedit-tab-help*/);
1991
1992 if(!builtin_bundle_all_fossil_js_apis()){
1993 builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1994 "storage", "popupwidget", 0);
 
1995 }
1996 /*
1997 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1998 ** used for dynamically toggling certain UI components on and off.
1999 ** Must come after window.fossil has been intialized and before
2000
--- src/fileedit.c
+++ src/fileedit.c
@@ -1989,11 +1989,12 @@
1989 }
1990 CX("</div>"/*#fileedit-tab-help*/);
1991
1992 if(!builtin_bundle_all_fossil_js_apis()){
1993 builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1994 "storage", "popupwidget", "copybutton",
1995 "pikchr", 0);
1996 }
1997 /*
1998 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1999 ** used for dynamically toggling certain UI components on and off.
2000 ** Must come after window.fossil has been intialized and before
2001
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1118,10 +1118,11 @@
11181118
self = this;
11191119
const updateView = function(c){
11201120
D.clearElement(target);
11211121
if('string'===typeof c) D.parseHtml(target,c);
11221122
if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
1123
+ if(F.pikchr) F.pikchr.addSrcView();
11231124
};
11241125
return this._postPreview(this.fileContent(), updateView);
11251126
};
11261127
11271128
/**
11281129
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1118,10 +1118,11 @@
1118 self = this;
1119 const updateView = function(c){
1120 D.clearElement(target);
1121 if('string'===typeof c) D.parseHtml(target,c);
1122 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
 
1123 };
1124 return this._postPreview(this.fileContent(), updateView);
1125 };
1126
1127 /**
1128
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1118,10 +1118,11 @@
1118 self = this;
1119 const updateView = function(c){
1120 D.clearElement(target);
1121 if('string'===typeof c) D.parseHtml(target,c);
1122 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
1123 if(F.pikchr) F.pikchr.addSrcView();
1124 };
1125 return this._postPreview(this.fileContent(), updateView);
1126 };
1127
1128 /**
1129
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1319,10 +1319,11 @@
13191319
self = this;
13201320
const updateView = function(c,mimetype){
13211321
D.clearElement(target);
13221322
if('string'===typeof c) D.parseHtml(target,c);
13231323
if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
1324
+ if(F.pikchr) F.pikchr.addSrcView();
13241325
};
13251326
return this._postPreview(this.wikiContent(), updateView);
13261327
};
13271328
13281329
/**
13291330
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1319,10 +1319,11 @@
1319 self = this;
1320 const updateView = function(c,mimetype){
1321 D.clearElement(target);
1322 if('string'===typeof c) D.parseHtml(target,c);
1323 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
 
1324 };
1325 return this._postPreview(this.wikiContent(), updateView);
1326 };
1327
1328 /**
1329
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1319,10 +1319,11 @@
1319 self = this;
1320 const updateView = function(c,mimetype){
1321 D.clearElement(target);
1322 if('string'===typeof c) D.parseHtml(target,c);
1323 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
1324 if(F.pikchr) F.pikchr.addSrcView();
1325 };
1326 return this._postPreview(this.wikiContent(), updateView);
1327 };
1328
1329 /**
1330
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -109,10 +109,15 @@
109109
Returns this object.
110110
111111
The 2nd argument is intended to be a plain options object, but it
112112
is currently unused, as it's not yet clear what we can/should
113113
make configurable.
114
+
115
+ Each element will only be processed once by this routine, even if
116
+ it is passed to this function multiple times. Each processed
117
+ element gets a "data" attribute set to it to indicate that it was
118
+ already dealt with.
114119
*/
115120
P.addSrcView = function f(svg,opt){
116121
if(!svg) svg = 'svg.pikchr';
117122
if('string' === typeof svg){
118123
document.querySelectorAll(svg).forEach(
@@ -121,10 +126,14 @@
121126
return this;
122127
}else if(svg.forEach){
123128
svg.forEach((e)=>f.call(this, e, opt));
124129
return this;
125130
}
131
+ if(svg.dataset.pikchrProcessed){
132
+ return this;
133
+ }
134
+ svg.dataset.pikchrProcessed = 1;
126135
const src = svg.querySelector('pikchr\\:src');
127136
if(!src){
128137
console.warn("No pikchr:src node found in",svg);
129138
return this;
130139
}
131140
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -109,10 +109,15 @@
109 Returns this object.
110
111 The 2nd argument is intended to be a plain options object, but it
112 is currently unused, as it's not yet clear what we can/should
113 make configurable.
 
 
 
 
 
114 */
115 P.addSrcView = function f(svg,opt){
116 if(!svg) svg = 'svg.pikchr';
117 if('string' === typeof svg){
118 document.querySelectorAll(svg).forEach(
@@ -121,10 +126,14 @@
121 return this;
122 }else if(svg.forEach){
123 svg.forEach((e)=>f.call(this, e, opt));
124 return this;
125 }
 
 
 
 
126 const src = svg.querySelector('pikchr\\:src');
127 if(!src){
128 console.warn("No pikchr:src node found in",svg);
129 return this;
130 }
131
--- src/fossil.pikchr.js
+++ src/fossil.pikchr.js
@@ -109,10 +109,15 @@
109 Returns this object.
110
111 The 2nd argument is intended to be a plain options object, but it
112 is currently unused, as it's not yet clear what we can/should
113 make configurable.
114
115 Each element will only be processed once by this routine, even if
116 it is passed to this function multiple times. Each processed
117 element gets a "data" attribute set to it to indicate that it was
118 already dealt with.
119 */
120 P.addSrcView = function f(svg,opt){
121 if(!svg) svg = 'svg.pikchr';
122 if('string' === typeof svg){
123 document.querySelectorAll(svg).forEach(
@@ -121,10 +126,14 @@
126 return this;
127 }else if(svg.forEach){
128 svg.forEach((e)=>f.call(this, e, opt));
129 return this;
130 }
131 if(svg.dataset.pikchrProcessed){
132 return this;
133 }
134 svg.dataset.pikchrProcessed = 1;
135 const src = svg.querySelector('pikchr\\:src');
136 if(!src){
137 console.warn("No pikchr:src node found in",svg);
138 return this;
139 }
140
+3 -2
--- src/wiki.c
+++ src/wiki.c
@@ -581,10 +581,11 @@
581581
wiki_render_by_mimetype(&wiki, zMimetype);
582582
blob_reset(&wiki);
583583
}
584584
attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
585585
manifest_destroy(pWiki);
586
+ document_emit_js(/*for optional pikchr support*/);
586587
style_footer();
587588
}
588589
589590
/*
590591
** Write a wiki artifact into the repository
@@ -1281,14 +1282,14 @@
12811282
"sandbox page will fail.</p>");
12821283
CX("<h2>Wiki Name Rules</h2>");
12831284
well_formed_wiki_name_rules();
12841285
CX("</div>"/*#wikiedit-tab-save*/);
12851286
}
1286
-
12871287
if(!builtin_bundle_all_fossil_js_apis()){
12881288
builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1289
- "storage", "popupwidget", 0);
1289
+ "storage", "popupwidget", "copybutton",
1290
+ "pikchr", 0);
12901291
}
12911292
builtin_request_js("sbsdiff.js");
12921293
builtin_request_js("fossil.page.wikiedit.js");
12931294
builtin_fulfill_js_requests();
12941295
/* Dynamically populate the editor... */
12951296
--- src/wiki.c
+++ src/wiki.c
@@ -581,10 +581,11 @@
581 wiki_render_by_mimetype(&wiki, zMimetype);
582 blob_reset(&wiki);
583 }
584 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
585 manifest_destroy(pWiki);
 
586 style_footer();
587 }
588
589 /*
590 ** Write a wiki artifact into the repository
@@ -1281,14 +1282,14 @@
1281 "sandbox page will fail.</p>");
1282 CX("<h2>Wiki Name Rules</h2>");
1283 well_formed_wiki_name_rules();
1284 CX("</div>"/*#wikiedit-tab-save*/);
1285 }
1286
1287 if(!builtin_bundle_all_fossil_js_apis()){
1288 builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1289 "storage", "popupwidget", 0);
 
1290 }
1291 builtin_request_js("sbsdiff.js");
1292 builtin_request_js("fossil.page.wikiedit.js");
1293 builtin_fulfill_js_requests();
1294 /* Dynamically populate the editor... */
1295
--- src/wiki.c
+++ src/wiki.c
@@ -581,10 +581,11 @@
581 wiki_render_by_mimetype(&wiki, zMimetype);
582 blob_reset(&wiki);
583 }
584 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
585 manifest_destroy(pWiki);
586 document_emit_js(/*for optional pikchr support*/);
587 style_footer();
588 }
589
590 /*
591 ** Write a wiki artifact into the repository
@@ -1281,14 +1282,14 @@
1282 "sandbox page will fail.</p>");
1283 CX("<h2>Wiki Name Rules</h2>");
1284 well_formed_wiki_name_rules();
1285 CX("</div>"/*#wikiedit-tab-save*/);
1286 }
 
1287 if(!builtin_bundle_all_fossil_js_apis()){
1288 builtin_emit_fossil_js_apis("fetch", "dom", "tabs", "confirmer",
1289 "storage", "popupwidget", "copybutton",
1290 "pikchr", 0);
1291 }
1292 builtin_request_js("sbsdiff.js");
1293 builtin_request_js("fossil.page.wikiedit.js");
1294 builtin_fulfill_js_requests();
1295 /* Dynamically populate the editor... */
1296

Keyboard Shortcuts

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