Fossil SCM

fossil-scm / src / fossil.pikchr.js
Blame History Raw 134 lines
1
(function(F/*window.fossil object*/){
2
"use strict";
3
const D = F.dom, P = F.pikchr = {};
4
5
/**
6
Initializes pikchr-rendered elements with the ability to
7
toggle between their SVG and source code.
8
9
The first argument may be any of:
10
11
- A single SVG.pikchr element.
12
13
- A collection (with a forEach method) of such elements.
14
15
- A CSS selector string for one or more such elements.
16
17
- An array of such strings.
18
19
Passing no value is equivalent to passing 'svg.pikchr'.
20
21
For each SVG in the resulting set, this function sets up event
22
handlers which allow the user to toggle the SVG between image and
23
source code modes. The image will switch modes in response to
24
cltr-click and, if its *parent* element has the "toggle" CSS
25
class, it will also switch modes in response to single-click.
26
27
If the parent element has the "source" CSS class, the image
28
starts off with its source code visible and the image hidden,
29
instead of the default of the other way around.
30
31
Returns this object.
32
33
Each element will only be processed once by this routine, even if
34
it is passed to this function multiple times. Each processed
35
element gets a "data" attribute set to it to indicate that it was
36
already dealt with.
37
38
This code expects the following structure around the SVGs, and
39
will not process any which don't match this:
40
41
<DIV.pikchr-wrapper>
42
<DIV.pikchr-svg><SVG.pikchr></SVG></DIV>
43
<DIV.pikchr-src>
44
<PRE>pikchr source code</PRE>
45
<SPAN class='hidden'><A>link to open pikchr in /pikchrshow</A></SPAN>
46
</DIV>
47
</DIV>
48
*/
49
P.addSrcView = function f(svg){
50
if(!f.hasOwnProperty('parentClick')){
51
f.parentClick = function(ev){
52
if(ev.altKey || ev.metaKey || ev.ctrlKey
53
/* Every combination of special key (alt, shift, ctrl,
54
meta) is handled differently everywhere. Shift is used
55
by the browser, Ctrl doesn't work on an iMac, and Alt is
56
intercepted by most Linux window managers to control
57
window movement! So... we just listen for *any* of them
58
(except Shift) and the user will need to find one which
59
works on their environment. */
60
|| this.classList.contains('toggle')){
61
this.classList.toggle('source');
62
ev.stopPropagation();
63
ev.preventDefault();
64
}
65
};
66
/**
67
Event handler for the "open in pikchrshow" links: store the
68
source code for the link's pikchr in
69
window.sessionStorage['pikchr-xfer'] then open
70
/pikchrshow?fromSession to trigger loading of that pikchr.
71
*/
72
f.clickPikchrShow = function(ev){
73
const pId = this.dataset['pikchrid'] /* ID of the associated pikchr source code element */;
74
if(!pId) return;
75
const ePikchr = this.parentNode.parentNode.querySelector('#'+pId);
76
if(!ePikchr) return;
77
ev.stopPropagation() /* keep pikchr source view from toggling */;
78
window.sessionStorage.setItem('pikchr-xfer', ePikchr.innerText);
79
/*
80
After returning from this function the link element will
81
open [/pikchrshow?fromSession], and pikchrshow will extract
82
the pikchr source code from sessionStorage['pikchr-xfer'].
83
84
Quirks of this ^^^ design:
85
86
We use only a single slot in sessionStorage. We could
87
alternately use a key like pikchr-$pId and pass that key on
88
to /pikchrshow via fromSession=pikchr-$pId, but that would
89
eventually lead to stale session entries if loading of
90
pikchrshow were interrupted at an untimely point. The
91
down-side of _not_ doing that is that some user (or
92
automation) options multiple "open in pikchrshow" links
93
rapidly enough, the will open the same pikchr (the one which
94
was stored in the session's slot most recently). The
95
current approach should be fine for normal human interaction
96
speeds, but if it proves to be a problem we can instead use
97
the above-described approach of storing each pikchr in its
98
own session slot and simply accept that there may be stale
99
entries at some point.
100
*/
101
};
102
};
103
if(!svg) svg = 'svg.pikchr';
104
if('string' === typeof svg){
105
document.querySelectorAll(svg).forEach((e)=>f.call(this, e));
106
return this;
107
}else if(svg.forEach){
108
svg.forEach((e)=>f.call(this, e));
109
return this;
110
}
111
if(svg.dataset.pikchrProcessed){
112
return this;
113
}
114
svg.dataset.pikchrProcessed = 1;
115
const parent = svg.parentNode.parentNode /* outermost DIV.pikchr-wrapper */;
116
const srcView = parent ? svg.parentNode.nextElementSibling /* DIV.pikchr-src */ : undefined;
117
if(srcView && srcView.classList.contains('pikchr-src')){
118
/* Without this element, there's nothing for us to do here. */
119
parent.addEventListener('click', f.parentClick, false);
120
const eSpan = window.sessionStorage
121
? srcView.querySelector('span') /* "open in..." link wrapper */
122
: undefined;
123
if(eSpan){
124
const openLink = eSpan.querySelector('a');
125
if(openLink){
126
openLink.addEventListener('click', f.clickPikchrShow, false);
127
eSpan.classList.remove('hidden');
128
}
129
}
130
}
131
return this;
132
};
133
})(window.fossil);
134

Keyboard Shortcuts

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