Fossil SCM

Added fossil.confirmer JS API to offer a non-intrusive click confirmation mechanism. Re-activated the /filepage content reload button with a confirmation click required.

stephan 2020-05-06 03:02 fileedit-ajaxify
Commit e70ab3a368b78adfb76feb58e86e647cd92e3428ffc12fb0c47e2860bafed110
+8 -3
--- src/fileedit.c
+++ src/fileedit.c
@@ -1564,18 +1564,22 @@
15641564
CX("<div id='fileedit-tab-content' "
15651565
"data-tab-parent='fileedit-tabs' "
15661566
"data-tab-label='File Content'"
15671567
">");
15681568
CX("<div class='fileedit-options flex-container row'>");
1569
- if(0){
1569
+ if(1){
15701570
/* Discard/reload button. Leave this out until we have a
15711571
** nice way of offering confirmation, e.g. like the old
15721572
** jQuery.confirmer plugin which required a 2nd click of the
15731573
** button within X seconds to confirm. Right now it's simply
15741574
** to easy to tap by accident. */
1575
- CX("<button class='fileedit-content-reload'>Discard &amp; Reload"
1576
- "</button>");
1575
+ CX("<button class='fileedit-content-reload confirmer' "
1576
+ "title='Reload the file from the server, discarding "
1577
+ "any local edits. To help avoid accidental loss of "
1578
+ "edits, it requires confirmation (a second click) within "
1579
+ "a few seconds or it will not reload.'"
1580
+ ">Discard &amp; Reload</button>");
15771581
}
15781582
style_select_list_int("select-font-size",
15791583
"editor_font_size", "Editor Font Size",
15801584
NULL/*tooltip*/,
15811585
100,
@@ -1774,10 +1778,11 @@
17741778
CheckinMiniInfo_cleanup(&cimi);
17751779
style_emit_script_fossil_bootstrap(0);
17761780
style_emit_script_fetch(0);
17771781
style_emit_script_tabs(0);
17781782
style_emit_script_builtin("fossil.page.fileedit.js",0);
1783
+ style_emit_script_confirmer(0);
17791784
if(blob_size(&endScript)>0){
17801785
style_emit_script_tag(0,0);
17811786
CX("(function(){\n");
17821787
CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
17831788
&endScript);
17841789
--- src/fileedit.c
+++ src/fileedit.c
@@ -1564,18 +1564,22 @@
1564 CX("<div id='fileedit-tab-content' "
1565 "data-tab-parent='fileedit-tabs' "
1566 "data-tab-label='File Content'"
1567 ">");
1568 CX("<div class='fileedit-options flex-container row'>");
1569 if(0){
1570 /* Discard/reload button. Leave this out until we have a
1571 ** nice way of offering confirmation, e.g. like the old
1572 ** jQuery.confirmer plugin which required a 2nd click of the
1573 ** button within X seconds to confirm. Right now it's simply
1574 ** to easy to tap by accident. */
1575 CX("<button class='fileedit-content-reload'>Discard &amp; Reload"
1576 "</button>");
 
 
 
 
1577 }
1578 style_select_list_int("select-font-size",
1579 "editor_font_size", "Editor Font Size",
1580 NULL/*tooltip*/,
1581 100,
@@ -1774,10 +1778,11 @@
1774 CheckinMiniInfo_cleanup(&cimi);
1775 style_emit_script_fossil_bootstrap(0);
1776 style_emit_script_fetch(0);
1777 style_emit_script_tabs(0);
1778 style_emit_script_builtin("fossil.page.fileedit.js",0);
 
1779 if(blob_size(&endScript)>0){
1780 style_emit_script_tag(0,0);
1781 CX("(function(){\n");
1782 CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
1783 &endScript);
1784
--- src/fileedit.c
+++ src/fileedit.c
@@ -1564,18 +1564,22 @@
1564 CX("<div id='fileedit-tab-content' "
1565 "data-tab-parent='fileedit-tabs' "
1566 "data-tab-label='File Content'"
1567 ">");
1568 CX("<div class='fileedit-options flex-container row'>");
1569 if(1){
1570 /* Discard/reload button. Leave this out until we have a
1571 ** nice way of offering confirmation, e.g. like the old
1572 ** jQuery.confirmer plugin which required a 2nd click of the
1573 ** button within X seconds to confirm. Right now it's simply
1574 ** to easy to tap by accident. */
1575 CX("<button class='fileedit-content-reload confirmer' "
1576 "title='Reload the file from the server, discarding "
1577 "any local edits. To help avoid accidental loss of "
1578 "edits, it requires confirmation (a second click) within "
1579 "a few seconds or it will not reload.'"
1580 ">Discard &amp; Reload</button>");
1581 }
1582 style_select_list_int("select-font-size",
1583 "editor_font_size", "Editor Font Size",
1584 NULL/*tooltip*/,
1585 100,
@@ -1774,10 +1778,11 @@
1778 CheckinMiniInfo_cleanup(&cimi);
1779 style_emit_script_fossil_bootstrap(0);
1780 style_emit_script_fetch(0);
1781 style_emit_script_tabs(0);
1782 style_emit_script_builtin("fossil.page.fileedit.js",0);
1783 style_emit_script_confirmer(0);
1784 if(blob_size(&endScript)>0){
1785 style_emit_script_tag(0,0);
1786 CX("(function(){\n");
1787 CX("try{\n%b\n}catch(e){console.error('Exception:',e)}\n",
1788 &endScript);
1789
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,10 +3,12 @@
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
+ const F = global.fossil;
9
+
810
/**
911
Returns the current time in something approximating
1012
ISO-8601 format.
1113
*/
1214
const timestring = function f(){
@@ -25,11 +27,11 @@
2527
** removed from the object. Pass it a falsy value to clear the target
2628
** element.
2729
**
2830
** Returns this object.
2931
*/
30
- global.fossil.message = function f(msg){
32
+ F.message = function f(msg){
3133
const args = Array.prototype.slice.call(arguments,0);
3234
const tgt = f.targetElement;
3335
args.unshift(timestring(),'UTC:');
3436
if(tgt){
3537
tgt.classList.remove('error');
@@ -42,23 +44,23 @@
4244
return this;
4345
};
4446
/*
4547
** Set default message.targetElement to #fossil-status-bar, if found.
4648
*/
47
- global.fossil.message.targetElement =
49
+ F.message.targetElement =
4850
document.querySelector('#fossil-status-bar');
4951
/*
5052
** By default fossil.error() sends its first argument to
5153
** console.error(). If fossil.message.targetElement (yes,
5254
** fossil.message) is set, it adds the 'error' CSS class to
5355
** that element and sets its content as defined for message().
5456
**
5557
** Returns this object.
5658
*/
57
- global.fossil.error = function f(msg){
59
+ F.error = function f(msg){
5860
const args = Array.prototype.slice.call(arguments,0);
59
- const tgt = global.fossil.message.targetElement;
61
+ const tgt = F.message.targetElement;
6062
args.unshift(timestring(),'UTC:');
6163
if(tgt){
6264
tgt.classList.add('error');
6365
tgt.innerText = args.join(' ');
6466
}
@@ -78,11 +80,11 @@
7880
to that array and tgtArray is returned. The above object would be
7981
appended as ['a','=','1','&','b','=','2']. This form is used for
8082
building up parameter lists before join('')ing the array to create
8183
the result string.
8284
*/
83
- global.fossil.encodeUrlArgs = function(obj,tgtArray){
85
+ F.encodeUrlArgs = function(obj,tgtArray){
8486
if(!obj) return '';
8587
const a = (tgtArray instanceof Array) ? tgtArray : [];
8688
let k, i = 0;
8789
for( k in obj ){
8890
if(i++) a.push('&');
@@ -99,16 +101,45 @@
99101
leading slash). If urlParams is a string, it must be
100102
paramters encoded in the form "key=val&key2=val2...", WITHOUT
101103
a leading '?'. If it's an object, all of its properties get
102104
appended to the URL in that form.
103105
*/
104
- global.fossil.repoUrl = function(path,urlParams){
106
+ F.repoUrl = function(path,urlParams){
105107
if(!urlParams) return this.rootPath+path;
106108
const url=[this.rootPath,path];
107109
url.push('?');
108110
if('string'===typeof urlParams) url.push(urlParams);
109111
else if('object'===typeof urlParams){
110112
this.encodeUrlArgs(urlParams, url);
111113
}
112114
return url.join('');
113115
};
116
+
117
+ /**
118
+ Returns true if v appears to be a plain object.
119
+ */
120
+ F.isObject = function(v){
121
+ return v &&
122
+ (v instanceof Object) &&
123
+ ('[object Object]' === Object.prototype.toString.apply(v) );
124
+ };
125
+
126
+ /**
127
+ For each object argument, this function combines their properties,
128
+ using a last-one-wins policy, and returns a new object with the
129
+ combined properties. If passed a single object, it effectively
130
+ shallowly clones that object.
131
+ */
132
+ F.mergeLastWins = function(){
133
+ var k, o, i;
134
+ const n = arguments.length, rc={};
135
+ for(i = 0; i < n; ++i){
136
+ if(!F.isObject(o = arguments[i])) continue;
137
+ for( k in o ){
138
+ if(o.hasOwnProperty(k)) rc[k] = o[k];
139
+ }
140
+ }
141
+ return rc;
142
+ };
143
+
144
+
114145
})(window);
115146
116147
ADDED src/fossil.confirmer.js
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,10 +3,12 @@
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(){
@@ -25,11 +27,11 @@
25 ** removed from the object. Pass it a falsy value to clear the target
26 ** element.
27 **
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');
@@ -42,23 +44,23 @@
42 return this;
43 };
44 /*
45 ** Set default message.targetElement to #fossil-status-bar, if found.
46 */
47 global.fossil.message.targetElement =
48 document.querySelector('#fossil-status-bar');
49 /*
50 ** By default fossil.error() sends its first argument to
51 ** console.error(). If fossil.message.targetElement (yes,
52 ** fossil.message) is set, it adds the 'error' CSS class to
53 ** that element and sets its content as defined for message().
54 **
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 }
@@ -78,11 +80,11 @@
78 to that array and tgtArray is returned. The above object would be
79 appended as ['a','=','1','&','b','=','2']. This form is used for
80 building up parameter lists before join('')ing the array to create
81 the result string.
82 */
83 global.fossil.encodeUrlArgs = function(obj,tgtArray){
84 if(!obj) return '';
85 const a = (tgtArray instanceof Array) ? tgtArray : [];
86 let k, i = 0;
87 for( k in obj ){
88 if(i++) a.push('&');
@@ -99,16 +101,45 @@
99 leading slash). If urlParams is a string, it must be
100 paramters encoded in the form "key=val&key2=val2...", WITHOUT
101 a leading '?'. If it's an object, all of its properties get
102 appended to the URL in that form.
103 */
104 global.fossil.repoUrl = function(path,urlParams){
105 if(!urlParams) return this.rootPath+path;
106 const url=[this.rootPath,path];
107 url.push('?');
108 if('string'===typeof urlParams) url.push(urlParams);
109 else if('object'===typeof urlParams){
110 this.encodeUrlArgs(urlParams, url);
111 }
112 return url.join('');
113 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114 })(window);
115
116 DDED src/fossil.confirmer.js
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -3,10 +3,12 @@
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 F = global.fossil;
9
10 /**
11 Returns the current time in something approximating
12 ISO-8601 format.
13 */
14 const timestring = function f(){
@@ -25,11 +27,11 @@
27 ** removed from the object. Pass it a falsy value to clear the target
28 ** element.
29 **
30 ** Returns this object.
31 */
32 F.message = function f(msg){
33 const args = Array.prototype.slice.call(arguments,0);
34 const tgt = f.targetElement;
35 args.unshift(timestring(),'UTC:');
36 if(tgt){
37 tgt.classList.remove('error');
@@ -42,23 +44,23 @@
44 return this;
45 };
46 /*
47 ** Set default message.targetElement to #fossil-status-bar, if found.
48 */
49 F.message.targetElement =
50 document.querySelector('#fossil-status-bar');
51 /*
52 ** By default fossil.error() sends its first argument to
53 ** console.error(). If fossil.message.targetElement (yes,
54 ** fossil.message) is set, it adds the 'error' CSS class to
55 ** that element and sets its content as defined for message().
56 **
57 ** Returns this object.
58 */
59 F.error = function f(msg){
60 const args = Array.prototype.slice.call(arguments,0);
61 const tgt = F.message.targetElement;
62 args.unshift(timestring(),'UTC:');
63 if(tgt){
64 tgt.classList.add('error');
65 tgt.innerText = args.join(' ');
66 }
@@ -78,11 +80,11 @@
80 to that array and tgtArray is returned. The above object would be
81 appended as ['a','=','1','&','b','=','2']. This form is used for
82 building up parameter lists before join('')ing the array to create
83 the result string.
84 */
85 F.encodeUrlArgs = function(obj,tgtArray){
86 if(!obj) return '';
87 const a = (tgtArray instanceof Array) ? tgtArray : [];
88 let k, i = 0;
89 for( k in obj ){
90 if(i++) a.push('&');
@@ -99,16 +101,45 @@
101 leading slash). If urlParams is a string, it must be
102 paramters encoded in the form "key=val&key2=val2...", WITHOUT
103 a leading '?'. If it's an object, all of its properties get
104 appended to the URL in that form.
105 */
106 F.repoUrl = function(path,urlParams){
107 if(!urlParams) return this.rootPath+path;
108 const url=[this.rootPath,path];
109 url.push('?');
110 if('string'===typeof urlParams) url.push(urlParams);
111 else if('object'===typeof urlParams){
112 this.encodeUrlArgs(urlParams, url);
113 }
114 return url.join('');
115 };
116
117 /**
118 Returns true if v appears to be a plain object.
119 */
120 F.isObject = function(v){
121 return v &&
122 (v instanceof Object) &&
123 ('[object Object]' === Object.prototype.toString.apply(v) );
124 };
125
126 /**
127 For each object argument, this function combines their properties,
128 using a last-one-wins policy, and returns a new object with the
129 combined properties. If passed a single object, it effectively
130 shallowly clones that object.
131 */
132 F.mergeLastWins = function(){
133 var k, o, i;
134 const n = arguments.length, rc={};
135 for(i = 0; i < n; ++i){
136 if(!F.isObject(o = arguments[i])) continue;
137 for( k in o ){
138 if(o.hasOwnProperty(k)) rc[k] = o[k];
139 }
140 }
141 return rc;
142 };
143
144
145 })(window);
146
147 DDED src/fossil.confirmer.js
--- a/src/fossil.confirmer.js
+++ b/src/fossil.confirmer.js
@@ -0,0 +1 @@
1
+/
--- a/src/fossil.confirmer.js
+++ b/src/fossil.confirmer.js
@@ -0,0 +1 @@
 
--- a/src/fossil.confirmer.js
+++ b/src/fossil.confirmer.js
@@ -0,0 +1 @@
1 /
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -54,13 +54,14 @@
5454
);
5555
P.e.btnCommit.addEventListener(
5656
"click",(e)=>P.commit(), false
5757
);
5858
if(P.e.btnReload){
59
- P.e.btnReload.addEventListener(
60
- "click",(e)=>P.loadFile(), false
61
- );
59
+ F.confirmer(P.e.btnReload, {
60
+ confirmText: "Really reload, losing edits?",
61
+ onconfirm: (e)=>P.loadFile()
62
+ });
6263
}
6364
/**
6465
Cosmetic: jump through some hoops to enable/disable
6566
certain preview options depending on the current
6667
preview mode...
6768
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -54,13 +54,14 @@
54 );
55 P.e.btnCommit.addEventListener(
56 "click",(e)=>P.commit(), false
57 );
58 if(P.e.btnReload){
59 P.e.btnReload.addEventListener(
60 "click",(e)=>P.loadFile(), false
61 );
 
62 }
63 /**
64 Cosmetic: jump through some hoops to enable/disable
65 certain preview options depending on the current
66 preview mode...
67
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -54,13 +54,14 @@
54 );
55 P.e.btnCommit.addEventListener(
56 "click",(e)=>P.commit(), false
57 );
58 if(P.e.btnReload){
59 F.confirmer(P.e.btnReload, {
60 confirmText: "Really reload, losing edits?",
61 onconfirm: (e)=>P.loadFile()
62 });
63 }
64 /**
65 Cosmetic: jump through some hoops to enable/disable
66 certain preview options depending on the current
67 preview mode...
68
--- src/main.mk
+++ src/main.mk
@@ -219,10 +219,11 @@
219219
$(SRCDIR)/ci_edit.js \
220220
$(SRCDIR)/copybtn.js \
221221
$(SRCDIR)/diff.tcl \
222222
$(SRCDIR)/forum.js \
223223
$(SRCDIR)/fossil.bootstrap.js \
224
+ $(SRCDIR)/fossil.confirmer.js \
224225
$(SRCDIR)/fossil.dom.js \
225226
$(SRCDIR)/fossil.fetch.js \
226227
$(SRCDIR)/fossil.page.fileedit.js \
227228
$(SRCDIR)/fossil.tabs.js \
228229
$(SRCDIR)/graph.js \
229230
--- src/main.mk
+++ src/main.mk
@@ -219,10 +219,11 @@
219 $(SRCDIR)/ci_edit.js \
220 $(SRCDIR)/copybtn.js \
221 $(SRCDIR)/diff.tcl \
222 $(SRCDIR)/forum.js \
223 $(SRCDIR)/fossil.bootstrap.js \
 
224 $(SRCDIR)/fossil.dom.js \
225 $(SRCDIR)/fossil.fetch.js \
226 $(SRCDIR)/fossil.page.fileedit.js \
227 $(SRCDIR)/fossil.tabs.js \
228 $(SRCDIR)/graph.js \
229
--- src/main.mk
+++ src/main.mk
@@ -219,10 +219,11 @@
219 $(SRCDIR)/ci_edit.js \
220 $(SRCDIR)/copybtn.js \
221 $(SRCDIR)/diff.tcl \
222 $(SRCDIR)/forum.js \
223 $(SRCDIR)/fossil.bootstrap.js \
224 $(SRCDIR)/fossil.confirmer.js \
225 $(SRCDIR)/fossil.dom.js \
226 $(SRCDIR)/fossil.fetch.js \
227 $(SRCDIR)/fossil.page.fileedit.js \
228 $(SRCDIR)/fossil.tabs.js \
229 $(SRCDIR)/graph.js \
230
+17
--- src/style.c
+++ src/style.c
@@ -1574,5 +1574,22 @@
15741574
if(0==once++){
15751575
style_emit_script_dom(asInline);
15761576
style_emit_script_builtin("fossil.tabs.js",asInline);
15771577
}
15781578
}
1579
+
1580
+/*
1581
+** The first time this is called, it calls style_emit_script_dom(),
1582
+** passing it the given asInline value, and emits the JS code from the
1583
+** built-in file fossil.confirmer.js. Subsequent calls are no-ops.
1584
+**
1585
+** If passed a true value, it emits the contents directly
1586
+** to the page output, else it emits a script tag with a
1587
+** src=builtin/... to load the script.
1588
+*/
1589
+void style_emit_script_confirmer(int asInline){
1590
+ static int once = 0;
1591
+ if(0==once++){
1592
+ style_emit_script_dom(asInline);
1593
+ style_emit_script_builtin("fossil.confirmer.js",asInline);
1594
+ }
1595
+}
15791596
--- src/style.c
+++ src/style.c
@@ -1574,5 +1574,22 @@
1574 if(0==once++){
1575 style_emit_script_dom(asInline);
1576 style_emit_script_builtin("fossil.tabs.js",asInline);
1577 }
1578 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1579
--- src/style.c
+++ src/style.c
@@ -1574,5 +1574,22 @@
1574 if(0==once++){
1575 style_emit_script_dom(asInline);
1576 style_emit_script_builtin("fossil.tabs.js",asInline);
1577 }
1578 }
1579
1580 /*
1581 ** The first time this is called, it calls style_emit_script_dom(),
1582 ** passing it the given asInline value, and emits the JS code from the
1583 ** built-in file fossil.confirmer.js. Subsequent calls are no-ops.
1584 **
1585 ** If passed a true value, it emits the contents directly
1586 ** to the page output, else it emits a script tag with a
1587 ** src=builtin/... to load the script.
1588 */
1589 void style_emit_script_confirmer(int asInline){
1590 static int once = 0;
1591 if(0==once++){
1592 style_emit_script_dom(asInline);
1593 style_emit_script_builtin("fossil.confirmer.js",asInline);
1594 }
1595 }
1596
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -641,10 +641,11 @@
641641
$(SRCDIR)/ci_edit.js \
642642
$(SRCDIR)/copybtn.js \
643643
$(SRCDIR)/diff.tcl \
644644
$(SRCDIR)/forum.js \
645645
$(SRCDIR)/fossil.bootstrap.js \
646
+ $(SRCDIR)/fossil.confirmer.js \
646647
$(SRCDIR)/fossil.dom.js \
647648
$(SRCDIR)/fossil.fetch.js \
648649
$(SRCDIR)/fossil.page.fileedit.js \
649650
$(SRCDIR)/fossil.tabs.js \
650651
$(SRCDIR)/graph.js \
651652
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -641,10 +641,11 @@
641 $(SRCDIR)/ci_edit.js \
642 $(SRCDIR)/copybtn.js \
643 $(SRCDIR)/diff.tcl \
644 $(SRCDIR)/forum.js \
645 $(SRCDIR)/fossil.bootstrap.js \
 
646 $(SRCDIR)/fossil.dom.js \
647 $(SRCDIR)/fossil.fetch.js \
648 $(SRCDIR)/fossil.page.fileedit.js \
649 $(SRCDIR)/fossil.tabs.js \
650 $(SRCDIR)/graph.js \
651
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -641,10 +641,11 @@
641 $(SRCDIR)/ci_edit.js \
642 $(SRCDIR)/copybtn.js \
643 $(SRCDIR)/diff.tcl \
644 $(SRCDIR)/forum.js \
645 $(SRCDIR)/fossil.bootstrap.js \
646 $(SRCDIR)/fossil.confirmer.js \
647 $(SRCDIR)/fossil.dom.js \
648 $(SRCDIR)/fossil.fetch.js \
649 $(SRCDIR)/fossil.page.fileedit.js \
650 $(SRCDIR)/fossil.tabs.js \
651 $(SRCDIR)/graph.js \
652
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -548,10 +548,11 @@
548548
$(SRCDIR)\ci_edit.js \
549549
$(SRCDIR)\copybtn.js \
550550
$(SRCDIR)\diff.tcl \
551551
$(SRCDIR)\forum.js \
552552
$(SRCDIR)\fossil.bootstrap.js \
553
+ $(SRCDIR)\fossil.confirmer.js \
553554
$(SRCDIR)\fossil.dom.js \
554555
$(SRCDIR)\fossil.fetch.js \
555556
$(SRCDIR)\fossil.page.fileedit.js \
556557
$(SRCDIR)\fossil.tabs.js \
557558
$(SRCDIR)\graph.js \
558559
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -548,10 +548,11 @@
548 $(SRCDIR)\ci_edit.js \
549 $(SRCDIR)\copybtn.js \
550 $(SRCDIR)\diff.tcl \
551 $(SRCDIR)\forum.js \
552 $(SRCDIR)\fossil.bootstrap.js \
 
553 $(SRCDIR)\fossil.dom.js \
554 $(SRCDIR)\fossil.fetch.js \
555 $(SRCDIR)\fossil.page.fileedit.js \
556 $(SRCDIR)\fossil.tabs.js \
557 $(SRCDIR)\graph.js \
558
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -548,10 +548,11 @@
548 $(SRCDIR)\ci_edit.js \
549 $(SRCDIR)\copybtn.js \
550 $(SRCDIR)\diff.tcl \
551 $(SRCDIR)\forum.js \
552 $(SRCDIR)\fossil.bootstrap.js \
553 $(SRCDIR)\fossil.confirmer.js \
554 $(SRCDIR)\fossil.dom.js \
555 $(SRCDIR)\fossil.fetch.js \
556 $(SRCDIR)\fossil.page.fileedit.js \
557 $(SRCDIR)\fossil.tabs.js \
558 $(SRCDIR)\graph.js \
559

Keyboard Shortcuts

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