Fossil SCM

New/unsaved pages can now be discarded.

stephan 2020-07-30 19:48 ajax-wiki-editor
Commit 2ccdf326cde1b533b00d7954f2358da56097bb1095bf294a004a6c532d8b5a5a
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -263,36 +263,52 @@
263263
}
264264
};
265265
266266
const WikiList = {
267267
e: {},
268
- /** Update OPTION elements to reflect whether the page has
268
+ /** Updates OPTION elements to reflect whether the page has
269269
local changes or is new/unsaved. */
270270
refreshStashMarks: function(){
271
- this.e.select.querySelectorAll(
272
- 'option'
273
- ).forEach(function(o){
274
- const stashed = $stash.getWinfo({name:o.value});
271
+ const sel = this.e.select;
272
+ Object.keys(sel.options).forEach(function(key){
273
+ const opt = sel.options[key];
274
+ const stashed = $stash.getWinfo({name:opt.value});
275275
if(stashed){
276276
const isNew = 'sandbox'===stashed.type ? false : !stashed.version;
277
- D.addClass(o, isNew ? 'stashed-new' :'stashed');
277
+ D.addClass(opt, isNew ? 'stashed-new' :'stashed');
278278
}else{
279
- D.removeClass(o, 'stashed', 'stashed-new');
279
+ D.removeClass(opt, 'stashed', 'stashed-new');
280280
}
281281
});
282282
},
283
+ /** Removes the given wiki page entry from the page selection
284
+ list, if it's in the list. */
285
+ removeEntry: function(name){
286
+ const sel = this.e.select;
287
+ const ndx = sel.selectedIndex;
288
+ sel.value = name;
289
+ if(sel.selectedIndex>-1){
290
+ sel.options.remove(sel.selectedIndex);
291
+ }
292
+ sel.selectedIndex = ndx;
293
+ },
294
+ /**
295
+ Installs a wiki page selection list into the given parent DOM
296
+ element and loads the page list from the server.
297
+ */
283298
init: function(parentElem){
284299
const sel = D.select(), btn = D.button("Reload page list");
285300
this.e.select = sel;
286301
D.addClass(parentElem, 'wikiedit-page-list-wrapper');
287302
D.clearElement(parentElem);
288303
D.append(
289
- parentElem, btn,
304
+ parentElem,
290305
D.append(D.span(), "Select a page to edit:"),
291306
sel,
292
- D.append(D.span(), "* = local edits exist"),
293
- D.append(D.span(), "+ = new/unsaved page")
307
+ D.append(D.span(), "[*] = page has local edits"),
308
+ D.append(D.span(), "[+] = page is new/unsaved"),
309
+ btn
294310
);
295311
D.attr(sel, 'size', 10);
296312
D.option(D.disable(D.clearElement(sel)), "Loading...");
297313
const self = this;
298314
btn.addEventListener(
@@ -339,10 +355,11 @@
339355
F.page.addEventListener(
340356
'wiki-stash-updated',
341357
()=>this.refreshStashMarks(),
342358
false
343359
);
360
+ delete this.init;
344361
}
345362
};
346363
347364
/**
348365
Keep track of how many in-flight AJAX requests there are so we
@@ -469,15 +486,27 @@
469486
onconfirm: function(e){
470487
const w = P.winfo;
471488
if(!w){
472489
F.error("No page loaded.");
473490
return;
474
- }else if(!w.version){
475
- F.error("Cannot reload a new/unsaved page.");
491
+ }
492
+ if(!w.version/* new/unsaved page */ && P.wikiContent()){
493
+ F.error("This new/unsaved page has content.",
494
+ "To really discard this page,",
495
+ "first clear its content",
496
+ "then use the Discard button.");
476497
return;
477498
}
478
- P.unstashContent().loadPage();
499
+ P.unstashContent()
500
+ if(w.version){
501
+ P.loadPage();
502
+ }else{
503
+ delete P.winfo;
504
+ WikiList.removeEntry(w.name);
505
+ P.updatePageTitle();
506
+ F.message("Discarded new page ["+w.name+"].");
507
+ }
479508
},
480509
ticks: 3
481510
});
482511
P.e.taEditor.addEventListener(
483512
'change', ()=>P.stashContentChange(), false
@@ -560,26 +589,30 @@
560589
if(!P.winfo && !quiet) F.error("No wiki page is loaded.");
561590
return !!P.winfo;
562591
};
563592
564593
/**
565
- Update the page title and header based on the state
566
- of this.winfo. A no-op if this.winfo is not set.
594
+ Update the page title and header based on the state of
595
+ this.winfo. A no-op if this.winfo is not set. Returns this.
567596
*/
568597
P.updatePageTitle = function f(){
569
- if(!affirmPageLoaded(true)) return;
570598
if(!f.titleElement){
571599
f.titleElement = document.head.querySelector('title');
572600
f.pageTitleHeader = document.querySelector('div.header .title');
573601
}
574602
var title = ['Wiki Editor:'];
575
- if(!P.winfo.version) title.push('[+]');
576
- else if($stash.getWinfo(P.winfo)) title.push('[*]')
577
- title.push(P.winfo.name);
603
+ if(P.winfo){
604
+ if(!P.winfo.version) title.push('[+]');
605
+ else if($stash.getWinfo(P.winfo)) title.push('[*]')
606
+ title.push(P.winfo.name);
607
+ }else{
608
+ title.push('(no page loaded)');
609
+ }
578610
title = title.join(' ');
579611
f.titleElement.innerText = title;
580612
f.pageTitleHeader.innerText = title;
613
+ return this;
581614
};
582615
583616
/**
584617
Getter (if called with no args) or setter (if passed an arg) for
585618
the current file content.
@@ -674,20 +707,20 @@
674707
name = arg.name;
675708
}
676709
const onload = (r)=>this.dispatchEvent('wiki-page-loaded', r);
677710
const stashWinfo = this.getStashedWinfo({name: name});
678711
if(stashWinfo){ // fake a response from the stash...
712
+ F.message("Fetched from the local-edit storage:",
713
+ stashWinfo.name);
679714
onload({
680715
name: stashWinfo.name,
681716
mimetype: stashWinfo.mimetype,
682717
type: stashWinfo.type,
683718
version: stashWinfo.version,
684719
parent: stashWinfo.parent,
685720
content: $stash.stashedContent(stashWinfo)
686721
});
687
- F.message("Fetched from the local-edit storage:",
688
- stashWinfo.name);
689722
return this;
690723
}
691724
F.message(
692725
"Loading content..."
693726
).fetch('wikiajax/fetch',{
@@ -694,12 +727,12 @@
694727
urlParams: {
695728
page: name
696729
},
697730
responseType: 'json',
698731
onload:(r)=>{
699
- onload(r);
700732
F.message('Loaded page ['+r.name+'].');
733
+ onload(r);
701734
}
702735
});
703736
return this;
704737
};
705738
706739
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -263,36 +263,52 @@
263 }
264 };
265
266 const WikiList = {
267 e: {},
268 /** Update OPTION elements to reflect whether the page has
269 local changes or is new/unsaved. */
270 refreshStashMarks: function(){
271 this.e.select.querySelectorAll(
272 'option'
273 ).forEach(function(o){
274 const stashed = $stash.getWinfo({name:o.value});
275 if(stashed){
276 const isNew = 'sandbox'===stashed.type ? false : !stashed.version;
277 D.addClass(o, isNew ? 'stashed-new' :'stashed');
278 }else{
279 D.removeClass(o, 'stashed', 'stashed-new');
280 }
281 });
282 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283 init: function(parentElem){
284 const sel = D.select(), btn = D.button("Reload page list");
285 this.e.select = sel;
286 D.addClass(parentElem, 'wikiedit-page-list-wrapper');
287 D.clearElement(parentElem);
288 D.append(
289 parentElem, btn,
290 D.append(D.span(), "Select a page to edit:"),
291 sel,
292 D.append(D.span(), "* = local edits exist"),
293 D.append(D.span(), "+ = new/unsaved page")
 
294 );
295 D.attr(sel, 'size', 10);
296 D.option(D.disable(D.clearElement(sel)), "Loading...");
297 const self = this;
298 btn.addEventListener(
@@ -339,10 +355,11 @@
339 F.page.addEventListener(
340 'wiki-stash-updated',
341 ()=>this.refreshStashMarks(),
342 false
343 );
 
344 }
345 };
346
347 /**
348 Keep track of how many in-flight AJAX requests there are so we
@@ -469,15 +486,27 @@
469 onconfirm: function(e){
470 const w = P.winfo;
471 if(!w){
472 F.error("No page loaded.");
473 return;
474 }else if(!w.version){
475 F.error("Cannot reload a new/unsaved page.");
 
 
 
 
476 return;
477 }
478 P.unstashContent().loadPage();
 
 
 
 
 
 
 
 
479 },
480 ticks: 3
481 });
482 P.e.taEditor.addEventListener(
483 'change', ()=>P.stashContentChange(), false
@@ -560,26 +589,30 @@
560 if(!P.winfo && !quiet) F.error("No wiki page is loaded.");
561 return !!P.winfo;
562 };
563
564 /**
565 Update the page title and header based on the state
566 of this.winfo. A no-op if this.winfo is not set.
567 */
568 P.updatePageTitle = function f(){
569 if(!affirmPageLoaded(true)) return;
570 if(!f.titleElement){
571 f.titleElement = document.head.querySelector('title');
572 f.pageTitleHeader = document.querySelector('div.header .title');
573 }
574 var title = ['Wiki Editor:'];
575 if(!P.winfo.version) title.push('[+]');
576 else if($stash.getWinfo(P.winfo)) title.push('[*]')
577 title.push(P.winfo.name);
 
 
 
 
578 title = title.join(' ');
579 f.titleElement.innerText = title;
580 f.pageTitleHeader.innerText = title;
 
581 };
582
583 /**
584 Getter (if called with no args) or setter (if passed an arg) for
585 the current file content.
@@ -674,20 +707,20 @@
674 name = arg.name;
675 }
676 const onload = (r)=>this.dispatchEvent('wiki-page-loaded', r);
677 const stashWinfo = this.getStashedWinfo({name: name});
678 if(stashWinfo){ // fake a response from the stash...
 
 
679 onload({
680 name: stashWinfo.name,
681 mimetype: stashWinfo.mimetype,
682 type: stashWinfo.type,
683 version: stashWinfo.version,
684 parent: stashWinfo.parent,
685 content: $stash.stashedContent(stashWinfo)
686 });
687 F.message("Fetched from the local-edit storage:",
688 stashWinfo.name);
689 return this;
690 }
691 F.message(
692 "Loading content..."
693 ).fetch('wikiajax/fetch',{
@@ -694,12 +727,12 @@
694 urlParams: {
695 page: name
696 },
697 responseType: 'json',
698 onload:(r)=>{
699 onload(r);
700 F.message('Loaded page ['+r.name+'].');
 
701 }
702 });
703 return this;
704 };
705
706
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -263,36 +263,52 @@
263 }
264 };
265
266 const WikiList = {
267 e: {},
268 /** Updates OPTION elements to reflect whether the page has
269 local changes or is new/unsaved. */
270 refreshStashMarks: function(){
271 const sel = this.e.select;
272 Object.keys(sel.options).forEach(function(key){
273 const opt = sel.options[key];
274 const stashed = $stash.getWinfo({name:opt.value});
275 if(stashed){
276 const isNew = 'sandbox'===stashed.type ? false : !stashed.version;
277 D.addClass(opt, isNew ? 'stashed-new' :'stashed');
278 }else{
279 D.removeClass(opt, 'stashed', 'stashed-new');
280 }
281 });
282 },
283 /** Removes the given wiki page entry from the page selection
284 list, if it's in the list. */
285 removeEntry: function(name){
286 const sel = this.e.select;
287 const ndx = sel.selectedIndex;
288 sel.value = name;
289 if(sel.selectedIndex>-1){
290 sel.options.remove(sel.selectedIndex);
291 }
292 sel.selectedIndex = ndx;
293 },
294 /**
295 Installs a wiki page selection list into the given parent DOM
296 element and loads the page list from the server.
297 */
298 init: function(parentElem){
299 const sel = D.select(), btn = D.button("Reload page list");
300 this.e.select = sel;
301 D.addClass(parentElem, 'wikiedit-page-list-wrapper');
302 D.clearElement(parentElem);
303 D.append(
304 parentElem,
305 D.append(D.span(), "Select a page to edit:"),
306 sel,
307 D.append(D.span(), "[*] = page has local edits"),
308 D.append(D.span(), "[+] = page is new/unsaved"),
309 btn
310 );
311 D.attr(sel, 'size', 10);
312 D.option(D.disable(D.clearElement(sel)), "Loading...");
313 const self = this;
314 btn.addEventListener(
@@ -339,10 +355,11 @@
355 F.page.addEventListener(
356 'wiki-stash-updated',
357 ()=>this.refreshStashMarks(),
358 false
359 );
360 delete this.init;
361 }
362 };
363
364 /**
365 Keep track of how many in-flight AJAX requests there are so we
@@ -469,15 +486,27 @@
486 onconfirm: function(e){
487 const w = P.winfo;
488 if(!w){
489 F.error("No page loaded.");
490 return;
491 }
492 if(!w.version/* new/unsaved page */ && P.wikiContent()){
493 F.error("This new/unsaved page has content.",
494 "To really discard this page,",
495 "first clear its content",
496 "then use the Discard button.");
497 return;
498 }
499 P.unstashContent()
500 if(w.version){
501 P.loadPage();
502 }else{
503 delete P.winfo;
504 WikiList.removeEntry(w.name);
505 P.updatePageTitle();
506 F.message("Discarded new page ["+w.name+"].");
507 }
508 },
509 ticks: 3
510 });
511 P.e.taEditor.addEventListener(
512 'change', ()=>P.stashContentChange(), false
@@ -560,26 +589,30 @@
589 if(!P.winfo && !quiet) F.error("No wiki page is loaded.");
590 return !!P.winfo;
591 };
592
593 /**
594 Update the page title and header based on the state of
595 this.winfo. A no-op if this.winfo is not set. Returns this.
596 */
597 P.updatePageTitle = function f(){
 
598 if(!f.titleElement){
599 f.titleElement = document.head.querySelector('title');
600 f.pageTitleHeader = document.querySelector('div.header .title');
601 }
602 var title = ['Wiki Editor:'];
603 if(P.winfo){
604 if(!P.winfo.version) title.push('[+]');
605 else if($stash.getWinfo(P.winfo)) title.push('[*]')
606 title.push(P.winfo.name);
607 }else{
608 title.push('(no page loaded)');
609 }
610 title = title.join(' ');
611 f.titleElement.innerText = title;
612 f.pageTitleHeader.innerText = title;
613 return this;
614 };
615
616 /**
617 Getter (if called with no args) or setter (if passed an arg) for
618 the current file content.
@@ -674,20 +707,20 @@
707 name = arg.name;
708 }
709 const onload = (r)=>this.dispatchEvent('wiki-page-loaded', r);
710 const stashWinfo = this.getStashedWinfo({name: name});
711 if(stashWinfo){ // fake a response from the stash...
712 F.message("Fetched from the local-edit storage:",
713 stashWinfo.name);
714 onload({
715 name: stashWinfo.name,
716 mimetype: stashWinfo.mimetype,
717 type: stashWinfo.type,
718 version: stashWinfo.version,
719 parent: stashWinfo.parent,
720 content: $stash.stashedContent(stashWinfo)
721 });
 
 
722 return this;
723 }
724 F.message(
725 "Loading content..."
726 ).fetch('wikiajax/fetch',{
@@ -694,12 +727,12 @@
727 urlParams: {
728 page: name
729 },
730 responseType: 'json',
731 onload:(r)=>{
 
732 F.message('Loaded page ['+r.name+'].');
733 onload(r);
734 }
735 });
736 return this;
737 };
738
739
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -1,14 +1,16 @@
11
body.wikieedit.waiting * {
22
/* Triggered during AJAX requests. */
33
cursor: wait;
44
}
5
+body.wikiedit textarea,
56
body.wikiedit textarea:focus,
7
+body.wikiedit input,
68
body.wikiedit input:focus{
79
/* The sudden appearance of a border (as in the Ardoise skin)
810
shifts the layout in unsightly ways */
9
- border: initial;
11
+ border: reset;
1012
}
1113
body.wikiedit div.wikiedit-preview {
1214
margin: 0;
1315
padding: 0;
1416
}
@@ -52,17 +54,17 @@
5254
}
5355
body.wikiedit .wikiedit-page-list-wrapper select option {
5456
margin: 0.5em 0;
5557
}
5658
body.wikiedit .wikiedit-page-list-wrapper select option.stashed::before {
57
- content: "* ";
59
+ content: "[*] ";
5860
}
5961
body.wikiedit .wikiedit-page-list-wrapper select option.stashed-new::before {
60
- content: "+ ";
62
+ content: "[+] ";
6163
}
6264
body.wikiedit textarea {
6365
max-width: calc(100% - 1em);
6466
}
6567
6668
body.wikiedit .tabs .tab-panel {
6769
overflow: auto;
6870
}
6971
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -1,14 +1,16 @@
1 body.wikieedit.waiting * {
2 /* Triggered during AJAX requests. */
3 cursor: wait;
4 }
 
5 body.wikiedit textarea:focus,
 
6 body.wikiedit input:focus{
7 /* The sudden appearance of a border (as in the Ardoise skin)
8 shifts the layout in unsightly ways */
9 border: initial;
10 }
11 body.wikiedit div.wikiedit-preview {
12 margin: 0;
13 padding: 0;
14 }
@@ -52,17 +54,17 @@
52 }
53 body.wikiedit .wikiedit-page-list-wrapper select option {
54 margin: 0.5em 0;
55 }
56 body.wikiedit .wikiedit-page-list-wrapper select option.stashed::before {
57 content: "* ";
58 }
59 body.wikiedit .wikiedit-page-list-wrapper select option.stashed-new::before {
60 content: "+ ";
61 }
62 body.wikiedit textarea {
63 max-width: calc(100% - 1em);
64 }
65
66 body.wikiedit .tabs .tab-panel {
67 overflow: auto;
68 }
69
--- src/style.wikiedit.css
+++ src/style.wikiedit.css
@@ -1,14 +1,16 @@
1 body.wikieedit.waiting * {
2 /* Triggered during AJAX requests. */
3 cursor: wait;
4 }
5 body.wikiedit textarea,
6 body.wikiedit textarea:focus,
7 body.wikiedit input,
8 body.wikiedit input:focus{
9 /* The sudden appearance of a border (as in the Ardoise skin)
10 shifts the layout in unsightly ways */
11 border: reset;
12 }
13 body.wikiedit div.wikiedit-preview {
14 margin: 0;
15 padding: 0;
16 }
@@ -52,17 +54,17 @@
54 }
55 body.wikiedit .wikiedit-page-list-wrapper select option {
56 margin: 0.5em 0;
57 }
58 body.wikiedit .wikiedit-page-list-wrapper select option.stashed::before {
59 content: "[*] ";
60 }
61 body.wikiedit .wikiedit-page-list-wrapper select option.stashed-new::before {
62 content: "[+] ";
63 }
64 body.wikiedit textarea {
65 max-width: calc(100% - 1em);
66 }
67
68 body.wikiedit .tabs .tab-panel {
69 overflow: auto;
70 }
71
-2
--- src/wiki.c
+++ src/wiki.c
@@ -1103,12 +1103,10 @@
11031103
"data-tab-parent='wikiedit-tabs' "
11041104
"data-tab-label='TODOs'"
11051105
">");
11061106
CX("TODOs, in no particular order:<ul>");
11071107
CX("<li>Saving, obviously.</li>");
1108
- CX("<li>Figure out how to integrate new/unusaved files into "
1109
- "the UI</li>");
11101108
/*CX("<li></li>");*/
11111109
CX("</ul>");
11121110
CX("</div>");
11131111
}
11141112
11151113
--- src/wiki.c
+++ src/wiki.c
@@ -1103,12 +1103,10 @@
1103 "data-tab-parent='wikiedit-tabs' "
1104 "data-tab-label='TODOs'"
1105 ">");
1106 CX("TODOs, in no particular order:<ul>");
1107 CX("<li>Saving, obviously.</li>");
1108 CX("<li>Figure out how to integrate new/unusaved files into "
1109 "the UI</li>");
1110 /*CX("<li></li>");*/
1111 CX("</ul>");
1112 CX("</div>");
1113 }
1114
1115
--- src/wiki.c
+++ src/wiki.c
@@ -1103,12 +1103,10 @@
1103 "data-tab-parent='wikiedit-tabs' "
1104 "data-tab-label='TODOs'"
1105 ">");
1106 CX("TODOs, in no particular order:<ul>");
1107 CX("<li>Saving, obviously.</li>");
 
 
1108 /*CX("<li></li>");*/
1109 CX("</ul>");
1110 CX("</div>");
1111 }
1112
1113

Keyboard Shortcuts

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