Fossil SCM

First step in the automation of connecting an editor widget to a preview-mode widget, as demo'd in [https://fossil-scm.org/forum/forumpost/d44564bad4|/forumpost/d44564bad4].

stephan 2020-05-06 17:33 fileedit-ajaxify
Commit 7ede6122e575be2b1f349f1edc7c800a9c52bfe1e024511ee92e437fac2643ee
+8 -1
--- src/fileedit.c
+++ src/fileedit.c
@@ -1602,11 +1602,18 @@
16021602
"data-tab-parent='fileedit-tabs' "
16031603
"data-tab-label='Preview'"
16041604
">");
16051605
16061606
CX("<div class='fileedit-options flex-container row'>");
1607
- CX("<button>Refresh</button>");
1607
+ CX("<button id='btn-preview-refresh' "
1608
+ "data-f-post-from='fileedit-content-editor' "
1609
+ /* ^^^ text source elem ID*/
1610
+ "data-f-post-via='_postPreview' "
1611
+ /* ^^^ fossil.page[methodName](content, callback) */
1612
+ "data-f-post-to='fileedit-tab-preview-wrapper' "
1613
+ /* ^^^ dest elem ID */
1614
+ ">Refresh</button>");
16081615
/* Default preview rendering mode selection... */
16091616
previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
16101617
style_select_list_int("select-preview-mode",
16111618
"preview_render_mode",
16121619
"Preview Mode",
16131620
--- src/fileedit.c
+++ src/fileedit.c
@@ -1602,11 +1602,18 @@
1602 "data-tab-parent='fileedit-tabs' "
1603 "data-tab-label='Preview'"
1604 ">");
1605
1606 CX("<div class='fileedit-options flex-container row'>");
1607 CX("<button>Refresh</button>");
 
 
 
 
 
 
 
1608 /* Default preview rendering mode selection... */
1609 previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
1610 style_select_list_int("select-preview-mode",
1611 "preview_render_mode",
1612 "Preview Mode",
1613
--- src/fileedit.c
+++ src/fileedit.c
@@ -1602,11 +1602,18 @@
1602 "data-tab-parent='fileedit-tabs' "
1603 "data-tab-label='Preview'"
1604 ">");
1605
1606 CX("<div class='fileedit-options flex-container row'>");
1607 CX("<button id='btn-preview-refresh' "
1608 "data-f-post-from='fileedit-content-editor' "
1609 /* ^^^ text source elem ID*/
1610 "data-f-post-via='_postPreview' "
1611 /* ^^^ fossil.page[methodName](content, callback) */
1612 "data-f-post-to='fileedit-tab-preview-wrapper' "
1613 /* ^^^ dest elem ID */
1614 ">Refresh</button>");
1615 /* Default preview rendering mode selection... */
1616 previewRenderMode = fileedit_render_mode_for_mimetype(zFileMime);
1617 style_select_list_int("select-preview-mode",
1618 "preview_render_mode",
1619 "Preview Mode",
1620
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -141,8 +141,117 @@
141141
if(o.hasOwnProperty(k)) rc[k] = o[k];
142142
}
143143
}
144144
return rc;
145145
};
146
+
147
+ /**
148
+ Sets up pseudo-automatic content preview handling between a
149
+ source element (typically a TEXTAREA) and a target rendering
150
+ element (typically a DIV). The selector argument must be one of:
151
+
152
+ - A single DOM element
153
+ - A collection of DOM elements with a forEach method.
154
+ - A CSS selector
155
+
156
+ Each element in the collection must have the following data
157
+ attributes:
158
+
159
+ - data-f-post-from: the DOM element id of the text source
160
+ element. It must support .value to get the content.
161
+
162
+ - data-f-post-to: the DOM element id of the target "previewer"
163
+ element.
164
+
165
+ - data-f-post-via: the name of a method (see below).
166
+
167
+ - OPTIONAL data-f-post-as-text: a numeric value. Explained below.
168
+
169
+ Each element gets a click handler added to it which does the
170
+ following:
171
+
172
+ 1) Reads the content from its data-f-post-from element.
173
+
174
+ 2) Passes the content to
175
+ methodNamespace[f-data-post-via](content,callback). f-data-post-via
176
+ is responsible for submitting the preview HTTP request, including
177
+ any parameters the request might require. When the response
178
+ arrives, it must pass the content of the response to its 2nd
179
+ argument, an auto-generated callback installed by this mechanism
180
+ which...
181
+
182
+ 3) Assigns the response text to the data-f-post-to element. If
183
+ data-f-post-as-text is '0' (the default) then the content
184
+ is assigned to the target element's innerHTML property, else
185
+ it is assigned to the element's textContent property.
186
+
187
+
188
+ The methodNamespace (2nd argument) defaults to fossil.page, and
189
+ data-f-post-via must be a single method name, not a
190
+ property-access-style string. e.g. "myPreview" is legal but
191
+ "foo.myPreview" is not (unless, of course, the method is actually
192
+ named "foo.myPreview" (which is legal but would be
193
+ unconventional)).
194
+
195
+ An example...
196
+
197
+ First an input button:
198
+
199
+ <button id='test-preview-connector'
200
+ data-f-post-from='fileedit-content-editor' // elem ID
201
+ data-f-post-via='myPreview' // method name
202
+ data-f-post-to='fileedit-tab-preview-wrapper' // elem ID
203
+ >Preview update</button>
204
+
205
+ And a sample data-f-post-via method:
206
+
207
+ fossil.page.myPreview = function(content,callback){
208
+ const fd = new FormData();
209
+ fd.append('foo', ...);
210
+ fossil.fetch('preview_forumpost',{
211
+ payload: fd,
212
+ onload: callback,
213
+ onerror: (e)=>{ // only if app-specific handling is needed
214
+ fossil.fetch.onerror(e); // default impl
215
+ ... any app-specific error reporting ...
216
+ }
217
+ });
218
+ };
219
+
220
+ Then connect the parts with:
221
+
222
+ fossil.connectPagePreviewers('#test-preview-connector');
223
+
224
+ Note that the data-f-post-from, data-f-post-via, and
225
+ data-f-post-to selector are not resolved until the button is
226
+ actually clicked, so they need not exist in the DOM at the
227
+ instant when the connection is set up, so long as they can be
228
+ resolved when the preview-refreshing element is clicked.
229
+ */
230
+ F.connectPagePreviewers = function f(selector,methodNamespace){
231
+ if('string'===typeof selector){
232
+ selector = document.querySelectorAll(selector);
233
+ }else if(!selector.forEach){
234
+ selector = [selector];
235
+ }
236
+ if(!methodNamespace){
237
+ methodNamespace = F.page;
238
+ }
239
+ selector.forEach(function(e){
240
+ e.addEventListener(
241
+ 'click', function(r){
242
+ const eTo = document.querySelector('#'+e.dataset.fPostTo),
243
+ eFrom = document.querySelector('#'+e.dataset.fPostFrom),
244
+ asText = +(e.dataset.fPostAsText || 0);
245
+ eTo.textContent = "Fetching preview...";
246
+ methodNamespace[e.dataset.fPostVia](
247
+ eFrom.value,
248
+ (r)=>eTo[asText ? 'textContent' : 'innerHTML'] = r||''
249
+ );
250
+ }, false
251
+ );
252
+ });
253
+ return this;
254
+ };
146255
147256
148257
})(window);
149258
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -141,8 +141,117 @@
141 if(o.hasOwnProperty(k)) rc[k] = o[k];
142 }
143 }
144 return rc;
145 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
147
148 })(window);
149
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -141,8 +141,117 @@
141 if(o.hasOwnProperty(k)) rc[k] = o[k];
142 }
143 }
144 return rc;
145 };
146
147 /**
148 Sets up pseudo-automatic content preview handling between a
149 source element (typically a TEXTAREA) and a target rendering
150 element (typically a DIV). The selector argument must be one of:
151
152 - A single DOM element
153 - A collection of DOM elements with a forEach method.
154 - A CSS selector
155
156 Each element in the collection must have the following data
157 attributes:
158
159 - data-f-post-from: the DOM element id of the text source
160 element. It must support .value to get the content.
161
162 - data-f-post-to: the DOM element id of the target "previewer"
163 element.
164
165 - data-f-post-via: the name of a method (see below).
166
167 - OPTIONAL data-f-post-as-text: a numeric value. Explained below.
168
169 Each element gets a click handler added to it which does the
170 following:
171
172 1) Reads the content from its data-f-post-from element.
173
174 2) Passes the content to
175 methodNamespace[f-data-post-via](content,callback). f-data-post-via
176 is responsible for submitting the preview HTTP request, including
177 any parameters the request might require. When the response
178 arrives, it must pass the content of the response to its 2nd
179 argument, an auto-generated callback installed by this mechanism
180 which...
181
182 3) Assigns the response text to the data-f-post-to element. If
183 data-f-post-as-text is '0' (the default) then the content
184 is assigned to the target element's innerHTML property, else
185 it is assigned to the element's textContent property.
186
187
188 The methodNamespace (2nd argument) defaults to fossil.page, and
189 data-f-post-via must be a single method name, not a
190 property-access-style string. e.g. "myPreview" is legal but
191 "foo.myPreview" is not (unless, of course, the method is actually
192 named "foo.myPreview" (which is legal but would be
193 unconventional)).
194
195 An example...
196
197 First an input button:
198
199 <button id='test-preview-connector'
200 data-f-post-from='fileedit-content-editor' // elem ID
201 data-f-post-via='myPreview' // method name
202 data-f-post-to='fileedit-tab-preview-wrapper' // elem ID
203 >Preview update</button>
204
205 And a sample data-f-post-via method:
206
207 fossil.page.myPreview = function(content,callback){
208 const fd = new FormData();
209 fd.append('foo', ...);
210 fossil.fetch('preview_forumpost',{
211 payload: fd,
212 onload: callback,
213 onerror: (e)=>{ // only if app-specific handling is needed
214 fossil.fetch.onerror(e); // default impl
215 ... any app-specific error reporting ...
216 }
217 });
218 };
219
220 Then connect the parts with:
221
222 fossil.connectPagePreviewers('#test-preview-connector');
223
224 Note that the data-f-post-from, data-f-post-via, and
225 data-f-post-to selector are not resolved until the button is
226 actually clicked, so they need not exist in the DOM at the
227 instant when the connection is set up, so long as they can be
228 resolved when the preview-refreshing element is clicked.
229 */
230 F.connectPagePreviewers = function f(selector,methodNamespace){
231 if('string'===typeof selector){
232 selector = document.querySelectorAll(selector);
233 }else if(!selector.forEach){
234 selector = [selector];
235 }
236 if(!methodNamespace){
237 methodNamespace = F.page;
238 }
239 selector.forEach(function(e){
240 e.addEventListener(
241 'click', function(r){
242 const eTo = document.querySelector('#'+e.dataset.fPostTo),
243 eFrom = document.querySelector('#'+e.dataset.fPostFrom),
244 asText = +(e.dataset.fPostAsText || 0);
245 eTo.textContent = "Fetching preview...";
246 methodNamespace[e.dataset.fPostVia](
247 eFrom.value,
248 (r)=>eTo[asText ? 'textContent' : 'innerHTML'] = r||''
249 );
250 }, false
251 );
252 });
253 return this;
254 };
255
256
257 })(window);
258
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -3,13 +3,13 @@
33
/**
44
Code for the /filepage app. Requires that the fossil JS
55
bootstrapping is complete and fossil.fetch() has been installed.
66
*/
77
const E = (s)=>document.querySelector(s),
8
- D = F.dom;
8
+ D = F.dom,
9
+ P = F.page;
910
window.addEventListener("load", function() {
10
- const P = F.page;
1111
P.tabs = new fossil.TabManager('#fileedit-tabs');
1212
P.e = {
1313
taEditor: E('#fileedit-content-editor'),
1414
taComment: E('#fileedit-comment'),
1515
ajaxContentTarget: E('#ajax-target'),
@@ -37,14 +37,14 @@
3737
//e.stopPropagation();
3838
return P;
3939
};
4040
4141
//P.tabs.getButtonForTab(P.e.tabs.preview)
42
- P.e.tabs.preview.querySelector(
43
- 'button'
44
- ).addEventListener(
45
- "click",(e)=>P.preview(), false
42
+ F.connectPagePreviewers(
43
+ P.e.tabs.preview.querySelector(
44
+ 'button'
45
+ )
4646
);
4747
4848
const diffButtons = E('#fileedit-tab-diff-buttons');
4949
diffButtons.querySelector('button.sbs').addEventListener(
5050
"click",(e)=>P.diff(true), false
@@ -102,19 +102,20 @@
102102
selectFontSize.dispatchEvent(
103103
// Force UI update
104104
new Event('change',{target:selectFontSize})
105105
);
106106
}
107
- }, false);
107
+
108
+ }, false)/*onload event handler*/;
108109
109110
/**
110111
updateVersion() updates the filename and version in various UI
111112
elements...
112113
113114
Returns this object.
114115
*/
115
- F.page.updateVersion = function(file,rev){
116
+ P.updateVersion = function(file,rev){
116117
this.finfo = {file,r:rev};
117118
const E = (s)=>document.querySelector(s),
118119
euc = encodeURIComponent,
119120
rShort = rev.substr(0,16);
120121
E('#r-label').innerText=rev;
@@ -140,11 +141,11 @@
140141
loadFile() loads (file,checkinVersion) and updates the relevant
141142
UI elements to reflect the loaded state.
142143
143144
Returns this object, noting that the load is async.
144145
*/
145
- F.page.loadFile = function(file,rev){
146
+ P.loadFile = function(file,rev){
146147
if(0===arguments.length){
147148
if(!this.finfo) return this;
148149
file = this.finfo.file;
149150
rev = this.finfo.r;
150151
}
@@ -169,20 +170,19 @@
169170
this page's input fields, and updates the UI with with the
170171
preview.
171172
172173
Returns this object, noting that the operation is async.
173174
*/
174
- F.page.preview = function(switchToTab){
175
+ P.preview = function(switchToTab){
175176
if(!this.finfo){
176177
F.error("No content is loaded.");
177178
return this;
178179
}
179
- const content = this.e.taEditor.value,
180
- target = this.e.tabs.preview.querySelector(
181
- '#fileedit-tab-preview-wrapper'
182
- ),
183
- self = this;
180
+ const target = this.e.tabs.preview.querySelector(
181
+ '#fileedit-tab-preview-wrapper'
182
+ );
183
+ const self = this;
184184
const updateView = function(c){
185185
D.clearElement(target);
186186
if('string'===typeof c){
187187
target.innerHTML = c;
188188
}
@@ -190,34 +190,47 @@
190190
if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
191191
};
192192
if(!content){
193193
updateView('');
194194
return this;
195
+ }
196
+ this._postPreview(this.e.taEditor.value, updateView);
197
+ return this;
198
+ };
199
+
200
+ /**
201
+ Callback for use with F.connectPagePreviewers()
202
+ */
203
+ P._postPreview = function(content,callback){
204
+ if(!content){
205
+ callback(content);
206
+ return;
195207
}
196208
const fd = new FormData();
197209
fd.append('render_mode',E('select[name=preview_render_mode]').value);
198210
fd.append('file',this.finfo.file);
199211
fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
200212
fd.append('iframe_height', E('[name=preview_html_ems]').value);
201
- fd.append('content',content);
202
- target.innerText = "Fetching preview...";
203
- F.message(
204
- "Fetching preview..."
205
- ).fetch('fileedit_preview',{
213
+ fd.append('content',content || '');
214
+ fossil.fetch('fileedit_preview',{
206215
payload: fd,
207
- onload: updateView
216
+ onload: callback,
217
+ onerror: (e)=>{
218
+ fossil.fetch.onerror(e);
219
+ callback("Error fetching preview: "+e);
220
+ }
208221
});
209
- return this;
210222
};
211223
224
+
212225
/**
213226
Fetches the content diff based on the contents and settings of this
214227
page's input fields, and updates the UI with the diff view.
215228
216229
Returns this object, noting that the operation is async.
217230
*/
218
- F.page.diff = function(sbs){
231
+ P.diff = function(sbs){
219232
if(!this.finfo){
220233
F.error("No content is loaded.");
221234
return this;
222235
}
223236
const content = this.e.taEditor.value,
@@ -252,11 +265,11 @@
252265
Performs an async commit based on the form contents and updates
253266
the UI.
254267
255268
Returns this object.
256269
*/
257
- F.page.commit = function f(){
270
+ P.commit = function f(){
258271
if(!this.finfo){
259272
F.error("No content is loaded.");
260273
return this;
261274
}
262275
const self = this;
@@ -282,11 +295,11 @@
282295
];
283296
if(!c.dryRun){
284297
msg.push('Re-activating dry-run mode.');
285298
self.e.taComment.value = '';
286299
cbDryRun.checked = true;
287
- F.page.updateVersion(filename, c.uuid);
300
+ P.updateVersion(filename, c.uuid);
288301
}
289302
F.message.apply(fossil, msg);
290303
self.tabs.switchToTab(self.e.tabs.commit);
291304
};
292305
}
@@ -328,6 +341,7 @@
328341
onload: f.updateView
329342
});
330343
return this;
331344
};
332345
346
+
333347
})(window.fossil);
334348
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -3,13 +3,13 @@
3 /**
4 Code for the /filepage app. Requires that the fossil JS
5 bootstrapping is complete and fossil.fetch() has been installed.
6 */
7 const E = (s)=>document.querySelector(s),
8 D = F.dom;
 
9 window.addEventListener("load", function() {
10 const P = F.page;
11 P.tabs = new fossil.TabManager('#fileedit-tabs');
12 P.e = {
13 taEditor: E('#fileedit-content-editor'),
14 taComment: E('#fileedit-comment'),
15 ajaxContentTarget: E('#ajax-target'),
@@ -37,14 +37,14 @@
37 //e.stopPropagation();
38 return P;
39 };
40
41 //P.tabs.getButtonForTab(P.e.tabs.preview)
42 P.e.tabs.preview.querySelector(
43 'button'
44 ).addEventListener(
45 "click",(e)=>P.preview(), false
46 );
47
48 const diffButtons = E('#fileedit-tab-diff-buttons');
49 diffButtons.querySelector('button.sbs').addEventListener(
50 "click",(e)=>P.diff(true), false
@@ -102,19 +102,20 @@
102 selectFontSize.dispatchEvent(
103 // Force UI update
104 new Event('change',{target:selectFontSize})
105 );
106 }
107 }, false);
 
108
109 /**
110 updateVersion() updates the filename and version in various UI
111 elements...
112
113 Returns this object.
114 */
115 F.page.updateVersion = function(file,rev){
116 this.finfo = {file,r:rev};
117 const E = (s)=>document.querySelector(s),
118 euc = encodeURIComponent,
119 rShort = rev.substr(0,16);
120 E('#r-label').innerText=rev;
@@ -140,11 +141,11 @@
140 loadFile() loads (file,checkinVersion) and updates the relevant
141 UI elements to reflect the loaded state.
142
143 Returns this object, noting that the load is async.
144 */
145 F.page.loadFile = function(file,rev){
146 if(0===arguments.length){
147 if(!this.finfo) return this;
148 file = this.finfo.file;
149 rev = this.finfo.r;
150 }
@@ -169,20 +170,19 @@
169 this page's input fields, and updates the UI with with the
170 preview.
171
172 Returns this object, noting that the operation is async.
173 */
174 F.page.preview = function(switchToTab){
175 if(!this.finfo){
176 F.error("No content is loaded.");
177 return this;
178 }
179 const content = this.e.taEditor.value,
180 target = this.e.tabs.preview.querySelector(
181 '#fileedit-tab-preview-wrapper'
182 ),
183 self = this;
184 const updateView = function(c){
185 D.clearElement(target);
186 if('string'===typeof c){
187 target.innerHTML = c;
188 }
@@ -190,34 +190,47 @@
190 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
191 };
192 if(!content){
193 updateView('');
194 return this;
 
 
 
 
 
 
 
 
 
 
 
 
195 }
196 const fd = new FormData();
197 fd.append('render_mode',E('select[name=preview_render_mode]').value);
198 fd.append('file',this.finfo.file);
199 fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
200 fd.append('iframe_height', E('[name=preview_html_ems]').value);
201 fd.append('content',content);
202 target.innerText = "Fetching preview...";
203 F.message(
204 "Fetching preview..."
205 ).fetch('fileedit_preview',{
206 payload: fd,
207 onload: updateView
 
 
 
 
208 });
209 return this;
210 };
211
 
212 /**
213 Fetches the content diff based on the contents and settings of this
214 page's input fields, and updates the UI with the diff view.
215
216 Returns this object, noting that the operation is async.
217 */
218 F.page.diff = function(sbs){
219 if(!this.finfo){
220 F.error("No content is loaded.");
221 return this;
222 }
223 const content = this.e.taEditor.value,
@@ -252,11 +265,11 @@
252 Performs an async commit based on the form contents and updates
253 the UI.
254
255 Returns this object.
256 */
257 F.page.commit = function f(){
258 if(!this.finfo){
259 F.error("No content is loaded.");
260 return this;
261 }
262 const self = this;
@@ -282,11 +295,11 @@
282 ];
283 if(!c.dryRun){
284 msg.push('Re-activating dry-run mode.');
285 self.e.taComment.value = '';
286 cbDryRun.checked = true;
287 F.page.updateVersion(filename, c.uuid);
288 }
289 F.message.apply(fossil, msg);
290 self.tabs.switchToTab(self.e.tabs.commit);
291 };
292 }
@@ -328,6 +341,7 @@
328 onload: f.updateView
329 });
330 return this;
331 };
332
 
333 })(window.fossil);
334
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -3,13 +3,13 @@
3 /**
4 Code for the /filepage app. Requires that the fossil JS
5 bootstrapping is complete and fossil.fetch() has been installed.
6 */
7 const E = (s)=>document.querySelector(s),
8 D = F.dom,
9 P = F.page;
10 window.addEventListener("load", function() {
 
11 P.tabs = new fossil.TabManager('#fileedit-tabs');
12 P.e = {
13 taEditor: E('#fileedit-content-editor'),
14 taComment: E('#fileedit-comment'),
15 ajaxContentTarget: E('#ajax-target'),
@@ -37,14 +37,14 @@
37 //e.stopPropagation();
38 return P;
39 };
40
41 //P.tabs.getButtonForTab(P.e.tabs.preview)
42 F.connectPagePreviewers(
43 P.e.tabs.preview.querySelector(
44 'button'
45 )
46 );
47
48 const diffButtons = E('#fileedit-tab-diff-buttons');
49 diffButtons.querySelector('button.sbs').addEventListener(
50 "click",(e)=>P.diff(true), false
@@ -102,19 +102,20 @@
102 selectFontSize.dispatchEvent(
103 // Force UI update
104 new Event('change',{target:selectFontSize})
105 );
106 }
107
108 }, false)/*onload event handler*/;
109
110 /**
111 updateVersion() updates the filename and version in various UI
112 elements...
113
114 Returns this object.
115 */
116 P.updateVersion = function(file,rev){
117 this.finfo = {file,r:rev};
118 const E = (s)=>document.querySelector(s),
119 euc = encodeURIComponent,
120 rShort = rev.substr(0,16);
121 E('#r-label').innerText=rev;
@@ -140,11 +141,11 @@
141 loadFile() loads (file,checkinVersion) and updates the relevant
142 UI elements to reflect the loaded state.
143
144 Returns this object, noting that the load is async.
145 */
146 P.loadFile = function(file,rev){
147 if(0===arguments.length){
148 if(!this.finfo) return this;
149 file = this.finfo.file;
150 rev = this.finfo.r;
151 }
@@ -169,20 +170,19 @@
170 this page's input fields, and updates the UI with with the
171 preview.
172
173 Returns this object, noting that the operation is async.
174 */
175 P.preview = function(switchToTab){
176 if(!this.finfo){
177 F.error("No content is loaded.");
178 return this;
179 }
180 const target = this.e.tabs.preview.querySelector(
181 '#fileedit-tab-preview-wrapper'
182 );
183 const self = this;
 
184 const updateView = function(c){
185 D.clearElement(target);
186 if('string'===typeof c){
187 target.innerHTML = c;
188 }
@@ -190,34 +190,47 @@
190 if(switchToTab) self.tabs.switchToTab(self.e.tabs.preview);
191 };
192 if(!content){
193 updateView('');
194 return this;
195 }
196 this._postPreview(this.e.taEditor.value, updateView);
197 return this;
198 };
199
200 /**
201 Callback for use with F.connectPagePreviewers()
202 */
203 P._postPreview = function(content,callback){
204 if(!content){
205 callback(content);
206 return;
207 }
208 const fd = new FormData();
209 fd.append('render_mode',E('select[name=preview_render_mode]').value);
210 fd.append('file',this.finfo.file);
211 fd.append('ln',E('[name=preview_ln]').checked ? 1 : 0);
212 fd.append('iframe_height', E('[name=preview_html_ems]').value);
213 fd.append('content',content || '');
214 fossil.fetch('fileedit_preview',{
 
 
 
215 payload: fd,
216 onload: callback,
217 onerror: (e)=>{
218 fossil.fetch.onerror(e);
219 callback("Error fetching preview: "+e);
220 }
221 });
 
222 };
223
224
225 /**
226 Fetches the content diff based on the contents and settings of this
227 page's input fields, and updates the UI with the diff view.
228
229 Returns this object, noting that the operation is async.
230 */
231 P.diff = function(sbs){
232 if(!this.finfo){
233 F.error("No content is loaded.");
234 return this;
235 }
236 const content = this.e.taEditor.value,
@@ -252,11 +265,11 @@
265 Performs an async commit based on the form contents and updates
266 the UI.
267
268 Returns this object.
269 */
270 P.commit = function f(){
271 if(!this.finfo){
272 F.error("No content is loaded.");
273 return this;
274 }
275 const self = this;
@@ -282,11 +295,11 @@
295 ];
296 if(!c.dryRun){
297 msg.push('Re-activating dry-run mode.');
298 self.e.taComment.value = '';
299 cbDryRun.checked = true;
300 P.updateVersion(filename, c.uuid);
301 }
302 F.message.apply(fossil, msg);
303 self.tabs.switchToTab(self.e.tabs.commit);
304 };
305 }
@@ -328,6 +341,7 @@
341 onload: f.updateView
342 });
343 return this;
344 };
345
346
347 })(window.fossil);
348

Keyboard Shortcuts

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