Fossil SCM

fossil.message() and friends now use local timestamps instead of UTC. Fixed a bug in wikiedit which caused a newly-created page to disappear from the page selection list after it was saved. Other minor cleanups in adjacent code.

stephan 2020-08-01 23:38 trunk
Commit 3dc4613d19edd0d94bc8b15b81c7987b7caf884dd3961ceabecb1c740d25f16a
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -17,10 +17,25 @@
1717
}
1818
const d = new Date();
1919
return d.toISOString().replace(f.rx1,'').split('T').join(' ');
2020
};
2121
22
+ /** Returns the local time string of Date object d, defaulting
23
+ to the current time. */
24
+ const localTimeString = function ff(d){
25
+ if(!ff.pad){
26
+ ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
27
+ }
28
+ d || (d = new Date());
29
+ return [
30
+ d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
31
+ '-',ff.pad(d.getDate()),
32
+ ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
33
+ ':',ff.pad(d.getSeconds())
34
+ ].join('');
35
+ };
36
+
2237
/*
2338
** By default fossil.message() sends its arguments console.debug(). If
2439
** fossil.message.targetElement is set, it is assumed to be a DOM
2540
** element, its innerText gets assigned to the concatenation of all
2641
** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +45,14 @@
3045
** Returns this object.
3146
*/
3247
F.message = function f(msg){
3348
const args = Array.prototype.slice.call(arguments,0);
3449
const tgt = f.targetElement;
35
- if(args.length) args.unshift(timestring(),'UTC:');
50
+ if(args.length) args.unshift(
51
+ localTimeString()+':'
52
+ //timestring(),'UTC:'
53
+ );
3654
if(tgt){
3755
tgt.classList.remove('error');
3856
tgt.innerText = args.join(' ');
3957
}
4058
else{
4159
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -17,10 +17,25 @@
17 }
18 const d = new Date();
19 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
20 };
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22 /*
23 ** By default fossil.message() sends its arguments console.debug(). If
24 ** fossil.message.targetElement is set, it is assumed to be a DOM
25 ** element, its innerText gets assigned to the concatenation of all
26 ** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +45,14 @@
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 if(args.length) args.unshift(timestring(),'UTC:');
 
 
 
36 if(tgt){
37 tgt.classList.remove('error');
38 tgt.innerText = args.join(' ');
39 }
40 else{
41
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -17,10 +17,25 @@
17 }
18 const d = new Date();
19 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
20 };
21
22 /** Returns the local time string of Date object d, defaulting
23 to the current time. */
24 const localTimeString = function ff(d){
25 if(!ff.pad){
26 ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
27 }
28 d || (d = new Date());
29 return [
30 d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
31 '-',ff.pad(d.getDate()),
32 ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
33 ':',ff.pad(d.getSeconds())
34 ].join('');
35 };
36
37 /*
38 ** By default fossil.message() sends its arguments console.debug(). If
39 ** fossil.message.targetElement is set, it is assumed to be a DOM
40 ** element, its innerText gets assigned to the concatenation of all
41 ** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +45,14 @@
45 ** Returns this object.
46 */
47 F.message = function f(msg){
48 const args = Array.prototype.slice.call(arguments,0);
49 const tgt = f.targetElement;
50 if(args.length) args.unshift(
51 localTimeString()+':'
52 //timestring(),'UTC:'
53 );
54 if(tgt){
55 tgt.classList.remove('error');
56 tgt.innerText = args.join(' ');
57 }
58 else{
59
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -518,20 +518,20 @@
518518
return;
519519
}
520520
D.enable(this.e.select);
521521
D.removeClass(this.e.btnClear, 'hidden');
522522
D.disable(D.option(this.e.select,0,"Select a local edit..."));
523
- const currentFinfo = theFinfo || P.finfo || {};
523
+ const currentFinfo = theFinfo || P.finfo || {filename:''};
524524
ilist.sort(f.compare).forEach(function(finfo,n){
525525
const key = stasher.indexKey(finfo),
526526
branch = finfo.branch
527527
|| P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
528528
/* Remember that we don't know the branch name for non-leaf versions
529529
which P.fileSelectWidget() has never seen/cached. */
530530
const opt = D.option(
531531
self.e.select, n+1/*value is (almost) irrelevant*/,
532
- [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
532
+ [F.hashDigits(finfo.checkin), ' [',branch||'?branch?','] ',
533533
f.timestring(new Date(finfo.stashTime)),' ',
534534
false ? finfo.filename : F.shortenFilename(finfo.filename)
535535
].join('')
536536
);
537537
opt._finfo = finfo;
538538
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -518,20 +518,20 @@
518 return;
519 }
520 D.enable(this.e.select);
521 D.removeClass(this.e.btnClear, 'hidden');
522 D.disable(D.option(this.e.select,0,"Select a local edit..."));
523 const currentFinfo = theFinfo || P.finfo || {};
524 ilist.sort(f.compare).forEach(function(finfo,n){
525 const key = stasher.indexKey(finfo),
526 branch = finfo.branch
527 || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
528 /* Remember that we don't know the branch name for non-leaf versions
529 which P.fileSelectWidget() has never seen/cached. */
530 const opt = D.option(
531 self.e.select, n+1/*value is (almost) irrelevant*/,
532 [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
533 f.timestring(new Date(finfo.stashTime)),' ',
534 false ? finfo.filename : F.shortenFilename(finfo.filename)
535 ].join('')
536 );
537 opt._finfo = finfo;
538
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -518,20 +518,20 @@
518 return;
519 }
520 D.enable(this.e.select);
521 D.removeClass(this.e.btnClear, 'hidden');
522 D.disable(D.option(this.e.select,0,"Select a local edit..."));
523 const currentFinfo = theFinfo || P.finfo || {filename:''};
524 ilist.sort(f.compare).forEach(function(finfo,n){
525 const key = stasher.indexKey(finfo),
526 branch = finfo.branch
527 || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
528 /* Remember that we don't know the branch name for non-leaf versions
529 which P.fileSelectWidget() has never seen/cached. */
530 const opt = D.option(
531 self.e.select, n+1/*value is (almost) irrelevant*/,
532 [F.hashDigits(finfo.checkin), ' [',branch||'?branch?','] ',
533 f.timestring(new Date(finfo.stashTime)),' ',
534 false ? finfo.filename : F.shortenFilename(finfo.filename)
535 ].join('')
536 );
537 opt._finfo = finfo;
538
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -302,10 +302,11 @@
302302
/*map of wiki page type to checkbox for list filtering purposes,
303303
except for "sandbox" type, which is assumed to be covered by
304304
the "normal" type filter. */},
305305
},
306306
cache: {
307
+ pageList: [],
307308
names: {
308309
/* Map of page names to "something." We don't map to their
309310
winfo bits because those regularly get swapped out via
310311
de/serialization. We need this map to support the add-new-page
311312
feature, to give us a way to check for dupes without asking
@@ -355,10 +356,12 @@
355356
if(sel.selectedIndex>-1){
356357
if(ndx === sel.selectedIndex) ndx = -1;
357358
sel.options.remove(sel.selectedIndex);
358359
}
359360
sel.selectedIndex = ndx;
361
+ delete this.cache.names[name];
362
+ this.cache.pageList = this.cache.pageList.filter((wi)=>name !== wi.name);
360363
},
361364
362365
/**
363366
Rebuilds the selection list. Necessary when it's loaded from
364367
the server or we locally create a new page.
@@ -468,16 +471,19 @@
468471
has a full artifact ID after "checkin/". */
469472
const winfo = {
470473
name: name, type: wtype, mimetype: 'text/x-fossil-wiki',
471474
version: null, parent: null
472475
};
476
+ this.cache.pageList.push(
477
+ winfo/*keeps entry from getting lost from the list on save*/
478
+ );
473479
$stash.updateWinfo(winfo, '');
474480
this._rebuildList();
475481
P.loadPage(winfo.name);
476482
return true;
477483
},
478
-
484
+
479485
/**
480486
Installs a wiki page selection list into the given parent DOM
481487
element and loads the page list from the server.
482488
*/
483489
init: function(parentElem){
@@ -624,17 +630,16 @@
624630
},
625631
/**
626632
Regenerates the edit selection list.
627633
*/
628634
updateList: function f(stasher,theWinfo){
629
- console.debug("updateList()",arguments);
630635
if(!f.compare){
631636
const cmpBase = (l,r)=>l<r ? -1 : (l===r ? 0 : 1);
632
- f.compare = (l,r)=>cmpBase(l.name, r.name);
637
+ f.compare = (l,r)=>cmpBase(l.name.toLowerCase(), r.name.toLowerCase());
633638
f.rxZ = /\.\d+Z$/ /* ms and 'Z' part of date string */;
634639
const pad=(x)=>(''+x).length>1 ? x : '0'+x;
635
- f.timestring = function ff(d){
640
+ f.timestring = function(d){
636641
return [
637642
d.getFullYear(),'-',pad(d.getMonth()+1/*sigh*/),'-',pad(d.getDate()),
638643
'@',pad(d.getHours()),':',pad(d.getMinutes())
639644
].join('');
640645
};
@@ -657,24 +662,26 @@
657662
we have if they use P.e.btnReload. Not yet sure how best to resolve that,
658663
so we'll leave the button hidden for the time being. */
659664
D.removeClass(this.e.btnClear, 'hidden');
660665
}
661666
D.disable(D.option(this.e.select,0,"Select a local edit..."));
662
- const currentFinfo = theWinfo || P.winfo || {};
667
+ const currentWinfo = theWinfo || P.winfo || {name:''};
663668
ilist.sort(f.compare).forEach(function(winfo,n){
664669
const key = stasher.indexKey(winfo),
665670
rev = winfo.version || '';
666671
const opt = D.option(
667672
self.e.select, n+1/*value is (almost) irrelevant*/,
668673
[winfo.name,
669
- rev ? ' ['+F.hashDigits(rev, 6)+']' : ' [new/local]',
670
- ' @ ',
674
+ ' [',
675
+ rev ? F.hashDigits(rev) : (
676
+ winfo.type==='sandbox' ? 'sandbox' : 'new/local'
677
+ ),'] ',
671678
f.timestring(new Date(winfo.stashTime))
672679
].join('')
673680
);
674681
opt._winfo = winfo;
675
- if(0===f.compare(currentFinfo, winfo)){
682
+ if(0===f.compare(currentWinfo, winfo)){
676683
D.attr(opt, 'selected', true);
677684
}
678685
});
679686
}
680687
}/*P.stashWidget*/;
@@ -1244,12 +1251,10 @@
12441251
const content = this.wikiContent();
12451252
if(!callee.onload){
12461253
callee.onload = function(w){
12471254
const oldWinfo = self.winfo;
12481255
self.unstashContent(oldWinfo);
1249
- self.winfo = w;
1250
- self.updatePageTitle();
12511256
self.dispatchEvent('wiki-page-loaded', w);
12521257
F.message("Saved page: ["+w.name+"].");
12531258
}
12541259
}
12551260
const fd = new FormData(), w = P.winfo;
12561261
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -302,10 +302,11 @@
302 /*map of wiki page type to checkbox for list filtering purposes,
303 except for "sandbox" type, which is assumed to be covered by
304 the "normal" type filter. */},
305 },
306 cache: {
 
307 names: {
308 /* Map of page names to "something." We don't map to their
309 winfo bits because those regularly get swapped out via
310 de/serialization. We need this map to support the add-new-page
311 feature, to give us a way to check for dupes without asking
@@ -355,10 +356,12 @@
355 if(sel.selectedIndex>-1){
356 if(ndx === sel.selectedIndex) ndx = -1;
357 sel.options.remove(sel.selectedIndex);
358 }
359 sel.selectedIndex = ndx;
 
 
360 },
361
362 /**
363 Rebuilds the selection list. Necessary when it's loaded from
364 the server or we locally create a new page.
@@ -468,16 +471,19 @@
468 has a full artifact ID after "checkin/". */
469 const winfo = {
470 name: name, type: wtype, mimetype: 'text/x-fossil-wiki',
471 version: null, parent: null
472 };
 
 
 
473 $stash.updateWinfo(winfo, '');
474 this._rebuildList();
475 P.loadPage(winfo.name);
476 return true;
477 },
478
479 /**
480 Installs a wiki page selection list into the given parent DOM
481 element and loads the page list from the server.
482 */
483 init: function(parentElem){
@@ -624,17 +630,16 @@
624 },
625 /**
626 Regenerates the edit selection list.
627 */
628 updateList: function f(stasher,theWinfo){
629 console.debug("updateList()",arguments);
630 if(!f.compare){
631 const cmpBase = (l,r)=>l<r ? -1 : (l===r ? 0 : 1);
632 f.compare = (l,r)=>cmpBase(l.name, r.name);
633 f.rxZ = /\.\d+Z$/ /* ms and 'Z' part of date string */;
634 const pad=(x)=>(''+x).length>1 ? x : '0'+x;
635 f.timestring = function ff(d){
636 return [
637 d.getFullYear(),'-',pad(d.getMonth()+1/*sigh*/),'-',pad(d.getDate()),
638 '@',pad(d.getHours()),':',pad(d.getMinutes())
639 ].join('');
640 };
@@ -657,24 +662,26 @@
657 we have if they use P.e.btnReload. Not yet sure how best to resolve that,
658 so we'll leave the button hidden for the time being. */
659 D.removeClass(this.e.btnClear, 'hidden');
660 }
661 D.disable(D.option(this.e.select,0,"Select a local edit..."));
662 const currentFinfo = theWinfo || P.winfo || {};
663 ilist.sort(f.compare).forEach(function(winfo,n){
664 const key = stasher.indexKey(winfo),
665 rev = winfo.version || '';
666 const opt = D.option(
667 self.e.select, n+1/*value is (almost) irrelevant*/,
668 [winfo.name,
669 rev ? ' ['+F.hashDigits(rev, 6)+']' : ' [new/local]',
670 ' @ ',
 
 
671 f.timestring(new Date(winfo.stashTime))
672 ].join('')
673 );
674 opt._winfo = winfo;
675 if(0===f.compare(currentFinfo, winfo)){
676 D.attr(opt, 'selected', true);
677 }
678 });
679 }
680 }/*P.stashWidget*/;
@@ -1244,12 +1251,10 @@
1244 const content = this.wikiContent();
1245 if(!callee.onload){
1246 callee.onload = function(w){
1247 const oldWinfo = self.winfo;
1248 self.unstashContent(oldWinfo);
1249 self.winfo = w;
1250 self.updatePageTitle();
1251 self.dispatchEvent('wiki-page-loaded', w);
1252 F.message("Saved page: ["+w.name+"].");
1253 }
1254 }
1255 const fd = new FormData(), w = P.winfo;
1256
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -302,10 +302,11 @@
302 /*map of wiki page type to checkbox for list filtering purposes,
303 except for "sandbox" type, which is assumed to be covered by
304 the "normal" type filter. */},
305 },
306 cache: {
307 pageList: [],
308 names: {
309 /* Map of page names to "something." We don't map to their
310 winfo bits because those regularly get swapped out via
311 de/serialization. We need this map to support the add-new-page
312 feature, to give us a way to check for dupes without asking
@@ -355,10 +356,12 @@
356 if(sel.selectedIndex>-1){
357 if(ndx === sel.selectedIndex) ndx = -1;
358 sel.options.remove(sel.selectedIndex);
359 }
360 sel.selectedIndex = ndx;
361 delete this.cache.names[name];
362 this.cache.pageList = this.cache.pageList.filter((wi)=>name !== wi.name);
363 },
364
365 /**
366 Rebuilds the selection list. Necessary when it's loaded from
367 the server or we locally create a new page.
@@ -468,16 +471,19 @@
471 has a full artifact ID after "checkin/". */
472 const winfo = {
473 name: name, type: wtype, mimetype: 'text/x-fossil-wiki',
474 version: null, parent: null
475 };
476 this.cache.pageList.push(
477 winfo/*keeps entry from getting lost from the list on save*/
478 );
479 $stash.updateWinfo(winfo, '');
480 this._rebuildList();
481 P.loadPage(winfo.name);
482 return true;
483 },
484
485 /**
486 Installs a wiki page selection list into the given parent DOM
487 element and loads the page list from the server.
488 */
489 init: function(parentElem){
@@ -624,17 +630,16 @@
630 },
631 /**
632 Regenerates the edit selection list.
633 */
634 updateList: function f(stasher,theWinfo){
 
635 if(!f.compare){
636 const cmpBase = (l,r)=>l<r ? -1 : (l===r ? 0 : 1);
637 f.compare = (l,r)=>cmpBase(l.name.toLowerCase(), r.name.toLowerCase());
638 f.rxZ = /\.\d+Z$/ /* ms and 'Z' part of date string */;
639 const pad=(x)=>(''+x).length>1 ? x : '0'+x;
640 f.timestring = function(d){
641 return [
642 d.getFullYear(),'-',pad(d.getMonth()+1/*sigh*/),'-',pad(d.getDate()),
643 '@',pad(d.getHours()),':',pad(d.getMinutes())
644 ].join('');
645 };
@@ -657,24 +662,26 @@
662 we have if they use P.e.btnReload. Not yet sure how best to resolve that,
663 so we'll leave the button hidden for the time being. */
664 D.removeClass(this.e.btnClear, 'hidden');
665 }
666 D.disable(D.option(this.e.select,0,"Select a local edit..."));
667 const currentWinfo = theWinfo || P.winfo || {name:''};
668 ilist.sort(f.compare).forEach(function(winfo,n){
669 const key = stasher.indexKey(winfo),
670 rev = winfo.version || '';
671 const opt = D.option(
672 self.e.select, n+1/*value is (almost) irrelevant*/,
673 [winfo.name,
674 ' [',
675 rev ? F.hashDigits(rev) : (
676 winfo.type==='sandbox' ? 'sandbox' : 'new/local'
677 ),'] ',
678 f.timestring(new Date(winfo.stashTime))
679 ].join('')
680 );
681 opt._winfo = winfo;
682 if(0===f.compare(currentWinfo, winfo)){
683 D.attr(opt, 'selected', true);
684 }
685 });
686 }
687 }/*P.stashWidget*/;
@@ -1244,12 +1251,10 @@
1251 const content = this.wikiContent();
1252 if(!callee.onload){
1253 callee.onload = function(w){
1254 const oldWinfo = self.winfo;
1255 self.unstashContent(oldWinfo);
 
 
1256 self.dispatchEvent('wiki-page-loaded', w);
1257 F.message("Saved page: ["+w.name+"].");
1258 }
1259 }
1260 const fd = new FormData(), w = P.winfo;
1261
+7 -12
--- src/wiki.c
+++ src/wiki.c
@@ -807,24 +807,23 @@
807807
** Responds with JSON. On error, an object in the form documented by
808808
** ajax_route_error(). On success, an object in the form documented
809809
** for wiki_ajax_emit_page_object().
810810
**
811811
** The wikiajax API disallows saving of a sandbox pseudo-page, and
812
-** will respond with an error if asked to save one.
813
-**
814
-** Reminder: the original implementation implements sandbox-page
815
-** saving using:
812
+** will respond with an error if asked to save one. Should we want to
813
+** enable it, it's implemented like this for any saved page for which
814
+** is_sandbox(zPageName) is true:
816815
**
817816
** db_set("sandbox",zBody,0);
818817
** db_set("sandbox-mimetype",zMimetype,0);
819818
**
820819
*/
821820
static void wiki_ajax_route_save(void){
822821
const char *zPageName = P("page");
823822
const char *zMimetype = P("mimetype");
824823
const char *zContent = P("content");
825
- const int isNew = atoi(PD("isnew","0"))==1;
824
+ const int isNew = ajax_p_bool("isnew");
826825
Blob content = empty_blob;
827826
int parentRid = 0;
828827
int rollback = 0;
829828
830829
if(!wiki_ajax_can_write(zPageName, &parentRid)){
@@ -831,15 +830,13 @@
831830
return;
832831
}else if(is_sandbox(zPageName)){
833832
ajax_route_error(403,"Saving a sandbox page is prohibited.");
834833
return;
835834
}
836
-
837
- /* These isNew checks are just me being pedantic. The hope is
838
- to avoid accidental addition of new pages which differ only
839
- by the case of their name. We could just as easily derive
840
- isNew based on whether or not the page already exists. */
835
+ /* These isNew checks are just me being pedantic. We could just as
836
+ easily derive isNew based on whether or not the page already
837
+ exists. */
841838
if(isNew){
842839
if(parentRid>0){
843840
ajax_route_error(403,"Requested a new page, "
844841
"but it already exists with RID %d: %s",
845842
parentRid, zPageName);
@@ -848,11 +845,10 @@
848845
}else if(parentRid==0){
849846
ajax_route_error(403,"Creating new page [%s] requires passing "
850847
"isnew=1.", zPageName);
851848
return;
852849
}
853
-
854850
blob_init(&content, zContent ? zContent : "", -1);
855851
db_begin_transaction();
856852
wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0);
857853
rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1;
858854
db_end_transaction(rollback);
@@ -1000,11 +996,10 @@
1000996
}
1001997
db_finalize(&q);
1002998
db_end_transaction(0);
1003999
CX("]");
10041000
}
1005
-
10061001
10071002
/*
10081003
** WEBPAGE: wikiajax
10091004
**
10101005
** An internal dispatcher for wiki AJAX operations. Not for direct
10111006
--- src/wiki.c
+++ src/wiki.c
@@ -807,24 +807,23 @@
807 ** Responds with JSON. On error, an object in the form documented by
808 ** ajax_route_error(). On success, an object in the form documented
809 ** for wiki_ajax_emit_page_object().
810 **
811 ** The wikiajax API disallows saving of a sandbox pseudo-page, and
812 ** will respond with an error if asked to save one.
813 **
814 ** Reminder: the original implementation implements sandbox-page
815 ** saving using:
816 **
817 ** db_set("sandbox",zBody,0);
818 ** db_set("sandbox-mimetype",zMimetype,0);
819 **
820 */
821 static void wiki_ajax_route_save(void){
822 const char *zPageName = P("page");
823 const char *zMimetype = P("mimetype");
824 const char *zContent = P("content");
825 const int isNew = atoi(PD("isnew","0"))==1;
826 Blob content = empty_blob;
827 int parentRid = 0;
828 int rollback = 0;
829
830 if(!wiki_ajax_can_write(zPageName, &parentRid)){
@@ -831,15 +830,13 @@
831 return;
832 }else if(is_sandbox(zPageName)){
833 ajax_route_error(403,"Saving a sandbox page is prohibited.");
834 return;
835 }
836
837 /* These isNew checks are just me being pedantic. The hope is
838 to avoid accidental addition of new pages which differ only
839 by the case of their name. We could just as easily derive
840 isNew based on whether or not the page already exists. */
841 if(isNew){
842 if(parentRid>0){
843 ajax_route_error(403,"Requested a new page, "
844 "but it already exists with RID %d: %s",
845 parentRid, zPageName);
@@ -848,11 +845,10 @@
848 }else if(parentRid==0){
849 ajax_route_error(403,"Creating new page [%s] requires passing "
850 "isnew=1.", zPageName);
851 return;
852 }
853
854 blob_init(&content, zContent ? zContent : "", -1);
855 db_begin_transaction();
856 wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0);
857 rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1;
858 db_end_transaction(rollback);
@@ -1000,11 +996,10 @@
1000 }
1001 db_finalize(&q);
1002 db_end_transaction(0);
1003 CX("]");
1004 }
1005
1006
1007 /*
1008 ** WEBPAGE: wikiajax
1009 **
1010 ** An internal dispatcher for wiki AJAX operations. Not for direct
1011
--- src/wiki.c
+++ src/wiki.c
@@ -807,24 +807,23 @@
807 ** Responds with JSON. On error, an object in the form documented by
808 ** ajax_route_error(). On success, an object in the form documented
809 ** for wiki_ajax_emit_page_object().
810 **
811 ** The wikiajax API disallows saving of a sandbox pseudo-page, and
812 ** will respond with an error if asked to save one. Should we want to
813 ** enable it, it's implemented like this for any saved page for which
814 ** is_sandbox(zPageName) is true:
 
815 **
816 ** db_set("sandbox",zBody,0);
817 ** db_set("sandbox-mimetype",zMimetype,0);
818 **
819 */
820 static void wiki_ajax_route_save(void){
821 const char *zPageName = P("page");
822 const char *zMimetype = P("mimetype");
823 const char *zContent = P("content");
824 const int isNew = ajax_p_bool("isnew");
825 Blob content = empty_blob;
826 int parentRid = 0;
827 int rollback = 0;
828
829 if(!wiki_ajax_can_write(zPageName, &parentRid)){
@@ -831,15 +830,13 @@
830 return;
831 }else if(is_sandbox(zPageName)){
832 ajax_route_error(403,"Saving a sandbox page is prohibited.");
833 return;
834 }
835 /* These isNew checks are just me being pedantic. We could just as
836 easily derive isNew based on whether or not the page already
837 exists. */
 
 
838 if(isNew){
839 if(parentRid>0){
840 ajax_route_error(403,"Requested a new page, "
841 "but it already exists with RID %d: %s",
842 parentRid, zPageName);
@@ -848,11 +845,10 @@
845 }else if(parentRid==0){
846 ajax_route_error(403,"Creating new page [%s] requires passing "
847 "isnew=1.", zPageName);
848 return;
849 }
 
850 blob_init(&content, zContent ? zContent : "", -1);
851 db_begin_transaction();
852 wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0);
853 rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1;
854 db_end_transaction(rollback);
@@ -1000,11 +996,10 @@
996 }
997 db_finalize(&q);
998 db_end_transaction(0);
999 CX("]");
1000 }
 
1001
1002 /*
1003 ** WEBPAGE: wikiajax
1004 **
1005 ** An internal dispatcher for wiki AJAX operations. Not for direct
1006

Keyboard Shortcuts

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