Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Rearranged the pikchrshow controls a bit to make better use of space and reduce flickering of the preview mode label/controls. Adapted CSS for pikchr error reporting structure changes. Code renaming for consistency/clarity. fossil.copyButton() click handler is now a no-op if the pseudo-button element has the 'disabled' CSS class and added style to grey such a button out. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
c304b4ffdf163aed2b7ab42084a87ce5 |
| User & Date: | stephan 2020-09-11 23:56:22.404 |
Context
|
2020-09-12
| ||
| 00:00 | Import the latest version of pikchr that supports the "file" object type. ... (check-in: b01fae602d user: drh tags: trunk) | |
|
2020-09-11
| ||
| 23:56 | Rearranged the pikchrshow controls a bit to make better use of space and reduce flickering of the preview mode label/controls. Adapted CSS for pikchr error reporting structure changes. Code renaming for consistency/clarity. fossil.copyButton() click handler is now a no-op if the pseudo-button element has the 'disabled' CSS class and added style to grey such a button out. ... (check-in: c304b4ffdf user: stephan tags: trunk) | |
| 22:30 | Minor code readability tweaks, nothing functional. ... (check-in: f73f1e36ad user: stephan tags: trunk) | |
Changes
Changes to src/default.css.
| ︙ | ︙ | |||
901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
d='M4,5h4v1h-4zm0,2h4v1h-4z'/%3E%3Cpath style='fill:rgb(64,64,64)' \
d='M5,3h5l3,3v7h-8z'/%3E%3Cpath style='fill:rgb(248,248,248)' \
d='M10,4.4v1.6h1.6zm-4,-0.6h3v3h-3zm0,3h6v5.4h-6z'/%3E%3Cpath style='fill:rgb(80,128,208)' \
d='M7,8h4v1h-4zm0,2h4v1h-4z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.copy-button-flipped {
/*Note: .16em is suitable for element grouping.*/
margin-left: .16em;
margin-right: 0;
}
.nobr {
| > > > | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 |
d='M4,5h4v1h-4zm0,2h4v1h-4z'/%3E%3Cpath style='fill:rgb(64,64,64)' \
d='M5,3h5l3,3v7h-8z'/%3E%3Cpath style='fill:rgb(248,248,248)' \
d='M10,4.4v1.6h1.6zm-4,-0.6h3v3h-3zm0,3h6v5.4h-6z'/%3E%3Cpath style='fill:rgb(80,128,208)' \
d='M7,8h4v1h-4zm0,2h4v1h-4z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.copy-button.disabled {
opacity: 0.4;
}
.copy-button-flipped {
/*Note: .16em is suitable for element grouping.*/
margin-left: .16em;
margin-right: 0;
}
.nobr {
|
| ︙ | ︙ |
Changes to src/fossil.copybutton.js.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
The copy button emits custom event 'text-copied' after it has
successfully copied text to the clipboard. The event's "detail"
member is an object with a "text" property holding the copied
text. Other properties may be added in the future. The event is
not fired if copying to the clipboard fails (e.g. is not
available in the current environment).
Returns the copy-initialized element.
Example:
const button = fossil.copyButton('#my-copy-button', {
copyFromId: 'some-other-element-id'
| > > > > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
The copy button emits custom event 'text-copied' after it has
successfully copied text to the clipboard. The event's "detail"
member is an object with a "text" property holding the copied
text. Other properties may be added in the future. The event is
not fired if copying to the clipboard fails (e.g. is not
available in the current environment).
As a special case, the copy button's click handler is suppressed
(becomes a no-op) for as long as the element has the CSS class
"disabled". This allows elements which cannot be disabled via
HTML attributes, e.g. a SPAN, to act as a copy button while still
providing a way to disable them.
Returns the copy-initialized element.
Example:
const button = fossil.copyButton('#my-copy-button', {
copyFromId: 'some-other-element-id'
|
| ︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
const extract = opt.extractText || (
undefined===srcElem.value ? ()=>srcElem.innerText : ()=>srcElem.value
);
D.copyStyle(e, opt.style);
e.addEventListener(
'click',
function(){
const txt = extract.call(opt);
if(txt && D.copyTextToClipboard(txt)){
e.dispatchEvent(new CustomEvent('text-copied',{
detail: {text: txt}
}));
}
},
| > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
const extract = opt.extractText || (
undefined===srcElem.value ? ()=>srcElem.innerText : ()=>srcElem.value
);
D.copyStyle(e, opt.style);
e.addEventListener(
'click',
function(){
if(e.classList.contains('disabled')) return;
const txt = extract.call(opt);
if(txt && D.copyTextToClipboard(txt)){
e.dispatchEvent(new CustomEvent('text-copied',{
detail: {text: txt}
}));
}
},
|
| ︙ | ︙ |
Changes to src/fossil.dom.js.
| ︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
*/
dom.removeClass = function(e,c){
const a = argsToArray(arguments);
a.unshift('remove');
return domAddRemoveClass.apply(this, a);
};
dom.hasClass = function(e,c){
return (e && e.classList) ? e.classList.contains(c) : false;
};
/**
Each argument after the first may be a single DOM element
or a container of them with a forEach() method. All such
| > > > > | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
*/
dom.removeClass = function(e,c){
const a = argsToArray(arguments);
a.unshift('remove');
return domAddRemoveClass.apply(this, a);
};
/**
Returns true if DOM element e contains CSS class c, else
false.
*/
dom.hasClass = function(e,c){
return (e && e.classList) ? e.classList.contains(c) : false;
};
/**
Each argument after the first may be a single DOM element
or a container of them with a forEach() method. All such
|
| ︙ | ︙ | |||
540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
e.style.opacity = opacity;
delete e.dataset.isBlinking;
if(afterFlashCallback) afterFlashCallback();
}, howLongMs);
return e;
};
dom.flashOnce.defaultTimeMs = 400;
/**
Attempts to copy the given text to the system clipboard. Returns
true if it succeeds, else false.
*/
dom.copyTextToClipboard = function(text){
if( window.clipboardData && window.clipboardData.setData ){
| > > > > > | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
e.style.opacity = opacity;
delete e.dataset.isBlinking;
if(afterFlashCallback) afterFlashCallback();
}, howLongMs);
return e;
};
dom.flashOnce.defaultTimeMs = 400;
/**
A DOM event handler which simply passes event.target
to dom.flashOnce().
*/
dom.flashOnce.eventHandler = (event)=>dom.flashOnce(event.target)
/**
Attempts to copy the given text to the system clipboard. Returns
true if it succeeds, else false.
*/
dom.copyTextToClipboard = function(text){
if( window.clipboardData && window.clipboardData.setData ){
|
| ︙ | ︙ |
Changes to src/fossil.page.pikchrshow.js.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
inputText: undefined /* value of the editor field at render-time */,
raw: undefined /* raw response text/HTML from server */
};
F.onPageLoad(function() {
document.body.classList.add('pikchrshow');
P.e = { /* various DOM elements we work with... */
previewTarget: E('#pikchrshow-output'),
| | > | | > > > | > > | | < < | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
inputText: undefined /* value of the editor field at render-time */,
raw: undefined /* raw response text/HTML from server */
};
F.onPageLoad(function() {
document.body.classList.add('pikchrshow');
P.e = { /* various DOM elements we work with... */
previewTarget: E('#pikchrshow-output'),
previewLegend: E('#pikchrshow-output-wrapper > legend'),
previewModeLabel: D.span(/*holds the text for the preview mode label*/),
previewCopyButton: D.addClass(D.span(), 'copy-button'),
btnSubmit: E('#pikchr-submit-preview'),
cbDarkMode: E('#flipcolors-wrapper > input[type=checkbox]'),
taContent: E('#content'),
taPreviewText: D.attr(D.textarea(), 'rows', 20, 'cols', 60,
'readonly', true),
uiControls: E('#pikchrshow-controls'),
previewModeToggle: D.button("Preview mode"),
selectMarkupAlignment: D.select()
};
////////////////////////////////////////////////////////////
// Setup the preview fieldset's LEGEND element...
D.append( P.e.previewLegend,
P.e.previewModeToggle,
P.e.previewModeLabel,
P.e.previewCopyButton );
////////////////////////////////////////////////////////////
// Setup markup alignment selection...
D.append(P.e.uiControls, P.e.selectMarkupAlignment);
D.disable(D.option(P.e.selectMarkupAlignment, '', 'Markup Alignment'));
['left', 'center'].forEach(function(val,ndx){
D.option(P.e.selectMarkupAlignment, ndx ? val : '', val);
});
////////////////////////////////////////////////////////////
// Setup clipboard-copy of markup/SVG...
F.copyButton(P.e.previewCopyButton, {copyFromElement: P.e.taPreviewText});
P.e.previewCopyButton.addEventListener('text-copied', D.flashOnce.eventHandler, false);
////////////////////////////////////////////////////////////
// Set up dark mode simulator...
P.e.cbDarkMode.addEventListener('change', function(ev){
if(ev.target.checked) D.addClass(P.e.previewTarget, 'dark-mode');
else D.removeClass(P.e.previewTarget, 'dark-mode');
}, false);
if(P.e.cbDarkMode.checked) D.addClass(P.e.previewTarget, 'dark-mode');
////////////////////////////////////////////////////////////
// Set up preview update and preview mode toggle...
P.e.btnSubmit.addEventListener('click', ()=>P.preview(), false);
P.e.previewModeToggle.addEventListener('click', function(){
/* Rotate through the 4 available preview modes */
P.previewMode = ++P.previewMode % 4;
P.renderPreview();
}, false);
P.e.selectMarkupAlignment.addEventListener('change', function(ev){
/* Update markdown/fossil wiki preview if it's active */
if(P.previewMode==1 || P.previewMode==2){
|
| ︙ | ︙ | |||
184 185 186 187 188 189 190 |
if(this.response.isError){
preTgt.innerHTML = this.response.raw;
D.addClass(preTgt, 'error');
this.e.previewModeLabel.innerText = "Error";
return;
}
D.removeClass(preTgt, 'error');
| > | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
if(this.response.isError){
preTgt.innerHTML = this.response.raw;
D.addClass(preTgt, 'error');
this.e.previewModeLabel.innerText = "Error";
return;
}
D.removeClass(preTgt, 'error');
D.removeClass(P.e.previewCopyButton, 'disabled');
D.enable(this.e.previewModeToggle);
let label;
switch(this.previewMode){
case 0:
label = "Rendered SVG";
preTgt.innerHTML = this.response.raw;
this.e.taPreviewText.value = this.response.raw.replace(f.rxNonce, '')/*for copy button*/;
break;
|
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
break;
case 3:
label = "Raw SVG";
this.e.taPreviewText.value = this.response.raw.replace(f.rxNonce, '');
D.append(D.clearElement(preTgt), this.e.taPreviewText);
break;
}
| | < | | > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
break;
case 3:
label = "Raw SVG";
this.e.taPreviewText.value = this.response.raw.replace(f.rxNonce, '');
D.append(D.clearElement(preTgt), this.e.taPreviewText);
break;
}
this.e.previewModeLabel.innerText = label;
};
/**
Fetches the preview from the server and updates the preview to
the rendered SVG content or error report.
*/
P.preview = function fp(){
if(!fp.hasOwnProperty('toDisable')){
fp.toDisable = [
/* input elements to disable during ajax operations */
this.e.btnSubmit, this.e.taContent,
this.e.selectMarkupAlignment,
this.e.cbAutoPreview, this.e.selectScript
/* this.e.previewModeToggle is handled separately */
];
fp.target = this.e.previewTarget;
fp.updateView = function(c,isError){
P.previewMode = 0;
P.response.raw = c;
P.response.isError = isError;
D.enable(fp.toDisable);
P.renderPreview();
};
}
D.disable(fp.toDisable, this.e.previewModeToggle);
D.addClass(this.e.previewCopyButton, 'disabled');
const content = this.e.taContent.value.trim();
this.response.raw = undefined;
this.response.inputText = content;
if(!content){
fp.updateView("No pikchr content!",true);
return this;
}
|
| ︙ | ︙ |
Changes to src/pikchrshow.c.
| ︙ | ︙ | |||
84 85 86 87 88 89 90 |
"{display: flex; flex-direction: column; align-items: stretch;}");
CX("#pikchrshow-form > * {margin: 0.25em 0}");
CX("#pikchrshow-output {flex: 5 1 auto; padding: 0}");
CX("#pikchrshow-output > pre, "
"#pikchrshow-output > pre > div, "
"#pikchrshow-output > pre > div > pre "
"{margin: 0; padding: 0}");
| | | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
"{display: flex; flex-direction: column; align-items: stretch;}");
CX("#pikchrshow-form > * {margin: 0.25em 0}");
CX("#pikchrshow-output {flex: 5 1 auto; padding: 0}");
CX("#pikchrshow-output > pre, "
"#pikchrshow-output > pre > div, "
"#pikchrshow-output > pre > div > pre "
"{margin: 0; padding: 0}");
CX("#pikchrshow-output.error > pre "
/* Server-side error report */
"{padding: 0.5em}");
CX("#pikchrshow-controls {" /* where the buttons live */
"display: flex; flex-direction: row; "
"align-items: center; flex-wrap: wrap;"
"}");
CX("#pikchrshow-controls > * {"
"display: inline; margin: 0 0.25em 0.5em 0;"
"}");
CX("#pikchrshow-controls > .input-with-label > * {"
"cursor: pointer;"
"}");
CX("#pikchrshow-output.dark-mode svg {"
/* Flip the colors to approximate a dark theme look */
"filter: invert(1) hue-rotate(180deg);"
"}");
CX("#sbs-wrapper > fieldset {"
"padding: 0.25em 0.5em; border-radius: 0.25em;"
"}");
CX("fieldset > legend > * {margin-right: 0.25em}");
CX(".dragover {border: 0.5em dotted rgba(0,255,0,0.6)}");
CX("</style>");
CX("<div>Input pikchr code and tap Preview to render it:</div>");
CX("<div id='sbs-wrapper'>");
CX("<div id='pikchrshow-form'>");
CX("<textarea id='content' name='content' rows='15'>%s</textarea>",
zContent/*safe-for-%s*/);
CX("<div id='pikchrshow-controls'>");
CX("<button id='pikchr-submit-preview'>Preview</button>");
style_labeled_checkbox("flipcolors-wrapper", "flipcolors",
"Dark mode?",
"1", flipColors, 0);
CX("</div>"/*#pikchrshow-controls*/);
CX("</div>"/*#pikchrshow-form*/);
CX("<fieldset id='pikchrshow-output-wrapper'>");
CX("<legend></legend>");
CX("<div id='pikchrshow-output'>");
if(*zContent){
int w = 0, h = 0;
char *zOut = pikchr(zContent, "pikchr", 0, &w, &h);
if( w>0 && h>0 ){
const char *zNonce = safe_html_nonce(1);
CX("%s<div style='max-width:%dpx;'>\n%s</div>%s",
|
| ︙ | ︙ |