Fossil SCM

Include the branch name, if known, in stashed fileinfo objects, and use a longer hash prefix for storing checkin-to-branch mappings (noting that the record does not notice if a checkin is later moved to another branch). (We only know the branch names of leaf checkins we've loaded, but now cache them in persistent storage if possible.) Renamed an internal cache key for consistency.

stephan 2020-05-16 05:42 fileedit-ajaxify
Commit 8573443f32b446bf1674e4d927f77d2c2bf79eb3b8dd356335b47d4e94345a7c
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -112,11 +112,11 @@
112112
and that would be horribly inefficient (meaning "battery-consuming"
113113
on mobile devices).
114114
*/
115115
const $stash = {
116116
keys: {
117
- index: F.page.name+':index'
117
+ index: F.page.name+'/index'
118118
},
119119
/**
120120
index: {
121121
"CHECKIN_HASH:FILENAME": {file info w/o content}
122122
...
@@ -138,11 +138,30 @@
138138
by prepending P.name to suffix. */
139139
contentKey: function(suffix){return P.name+'/'+suffix},
140140
/** Returns the index object, fetching it from the stash or creating
141141
it anew on the first call. */
142142
getIndex: function(){
143
- if(!this.index) this.index = F.storage.getJSON(this.keys.index,{});
143
+ if(!this.index){
144
+ this.index = F.storage.getJSON(
145
+ this.keys.index, undefined
146
+ );
147
+ if(!this.index){
148
+ /*check for and remove/replace older name. This whole block
149
+ can be removed once the test phase is done (don't want to
150
+ invalidate the testers' edits on the test server). When
151
+ doing so, be sure to replace undefined in the above
152
+ getJSON() call with {}. */
153
+ const oldName = F.page.name+':index';
154
+ this.index = F.storage.getJSON(oldName,undefined);
155
+ if(this.index){
156
+ F.storage.remove(oldName);
157
+ this.storeIndex();
158
+ }else{
159
+ this.index = {};
160
+ }
161
+ }
162
+ }
144163
return this.index;
145164
},
146165
_fireStashEvent: function(){
147166
if(this._disableNextEvent) delete this._disableNextEvent;
148167
else F.page.dispatchEvent('fileedit-stash-updated', this);
@@ -173,10 +192,11 @@
173192
filename: finfo.filename,
174193
mimetype: finfo.mimetype
175194
});
176195
record.isExe = !!finfo.isExe;
177196
record.stashTime = new Date().getTime();
197
+ if(!record.branch) record.branch=finfo.branch;
178198
this.storeIndex();
179199
if(arguments.length>1){
180200
F.storage.set(this.contentKey(key), content);
181201
}
182202
this._fireStashEvent();
@@ -256,10 +276,11 @@
256276
},
257277
finfo: {},
258278
cache: {
259279
checkins: undefined,
260280
files:{},
281
+ branchKey: 'fileedit/uuid-branches',
261282
branchNames: {}
262283
},
263284
/**
264285
Fetches the list of leaf checkins from the server and updates
265286
the UI with that list.
@@ -281,15 +302,16 @@
281302
self.cache.checkins = list;
282303
D.clearElement(D.enable(self.e.selectCi));
283304
let loadThisOne;
284305
list.forEach(function(o,n){
285306
if(!n) loadThisOne = o;
286
- self.cache.branchNames[F.hashDigits(o.checkin)] = o.branch;
307
+ self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
287308
D.option(self.e.selectCi, o.checkin,
288309
o.timestamp+' ['+o.branch+']: '
289310
+F.hashDigits(o.checkin));
290311
});
312
+ F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
291313
self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
292314
}
293315
});
294316
},
295317
/**
@@ -347,18 +369,19 @@
347369
If this object has ever loaded the given checkin version via
348370
loadLeaves(), this returns the branch name associated with that
349371
version, else returns undefined;
350372
*/
351373
checkinBranchName: function(uuid){
352
- return this.cache.branchNames[F.hashDigits(uuid)];
374
+ return this.cache.branchNames[F.hashDigits(uuid,true)];
353375
},
354376
355377
/**
356378
Initializes the checkin/file selector widget. Must only be
357379
called once.
358380
*/
359381
init: function(){
382
+ this.cache.branchNames = F.storage.getJSON(this.cache.branchKey, {});
360383
const selCi = this.e.selectCi = D.select(),
361384
selFiles = this.e.selectFiles
362385
= D.addClass(D.select(), 'file-list'),
363386
btnLoad = this.e.btnLoadFile =
364387
D.addClass(D.button("Load file"), "flex-shrink"),
@@ -488,17 +511,20 @@
488511
D.removeClass(this.e.btnClear, 'hidden');
489512
D.disable(D.option(this.e.select,0,"Select a local edit..."));
490513
const currentFinfo = theFinfo || P.finfo || {};
491514
ilist.sort(f.compare).forEach(function(finfo,n){
492515
const key = stasher.indexKey(finfo),
493
- branch = P.fileSelectWidget.checkinBranchName(finfo.checkin);
516
+ branch = finfo.branch
517
+ || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
518
+ /* Remember that we don't know the branch name for non-leaf versions
519
+ which P.fileSelectWidget() has never seen/cached. */
494520
const opt = D.option(
495521
self.e.select, n+1/*value is (almost) irrelevant*/,
496
- [F.hashDigits(finfo.checkin, 6), branch,
497
- f.timestring(new Date(finfo.stashTime)),
522
+ [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
523
+ f.timestring(new Date(finfo.stashTime)),' ',
498524
false ? finfo.filename : F.shortenFilename(finfo.filename)
499
- ].join(' ')
525
+ ].join('')
500526
);
501527
opt._finfo = finfo;
502528
if(0===f.compare(currentFinfo, finfo)){
503529
D.attr(opt, 'selected', true);
504530
}
@@ -1139,10 +1165,11 @@
11391165
*/
11401166
P.stashContentChange = function(onlyFinfo){
11411167
if(affirmHasFile(true)){
11421168
const fi = this.finfo;
11431169
fi.isExe = this.e.cbIsExe.checked;
1170
+ if(!fi.branch) fi.branch = this.fileSelectWidget.checkinBranchName(fi.checkin);
11441171
if(onlyFinfo && $stash.hasStashedContent(fi)){
11451172
$stash.updateFile(fi);
11461173
}else{
11471174
$stash.updateFile(fi, P.fileContent());
11481175
}
11491176
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -112,11 +112,11 @@
112 and that would be horribly inefficient (meaning "battery-consuming"
113 on mobile devices).
114 */
115 const $stash = {
116 keys: {
117 index: F.page.name+':index'
118 },
119 /**
120 index: {
121 "CHECKIN_HASH:FILENAME": {file info w/o content}
122 ...
@@ -138,11 +138,30 @@
138 by prepending P.name to suffix. */
139 contentKey: function(suffix){return P.name+'/'+suffix},
140 /** Returns the index object, fetching it from the stash or creating
141 it anew on the first call. */
142 getIndex: function(){
143 if(!this.index) this.index = F.storage.getJSON(this.keys.index,{});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144 return this.index;
145 },
146 _fireStashEvent: function(){
147 if(this._disableNextEvent) delete this._disableNextEvent;
148 else F.page.dispatchEvent('fileedit-stash-updated', this);
@@ -173,10 +192,11 @@
173 filename: finfo.filename,
174 mimetype: finfo.mimetype
175 });
176 record.isExe = !!finfo.isExe;
177 record.stashTime = new Date().getTime();
 
178 this.storeIndex();
179 if(arguments.length>1){
180 F.storage.set(this.contentKey(key), content);
181 }
182 this._fireStashEvent();
@@ -256,10 +276,11 @@
256 },
257 finfo: {},
258 cache: {
259 checkins: undefined,
260 files:{},
 
261 branchNames: {}
262 },
263 /**
264 Fetches the list of leaf checkins from the server and updates
265 the UI with that list.
@@ -281,15 +302,16 @@
281 self.cache.checkins = list;
282 D.clearElement(D.enable(self.e.selectCi));
283 let loadThisOne;
284 list.forEach(function(o,n){
285 if(!n) loadThisOne = o;
286 self.cache.branchNames[F.hashDigits(o.checkin)] = o.branch;
287 D.option(self.e.selectCi, o.checkin,
288 o.timestamp+' ['+o.branch+']: '
289 +F.hashDigits(o.checkin));
290 });
 
291 self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
292 }
293 });
294 },
295 /**
@@ -347,18 +369,19 @@
347 If this object has ever loaded the given checkin version via
348 loadLeaves(), this returns the branch name associated with that
349 version, else returns undefined;
350 */
351 checkinBranchName: function(uuid){
352 return this.cache.branchNames[F.hashDigits(uuid)];
353 },
354
355 /**
356 Initializes the checkin/file selector widget. Must only be
357 called once.
358 */
359 init: function(){
 
360 const selCi = this.e.selectCi = D.select(),
361 selFiles = this.e.selectFiles
362 = D.addClass(D.select(), 'file-list'),
363 btnLoad = this.e.btnLoadFile =
364 D.addClass(D.button("Load file"), "flex-shrink"),
@@ -488,17 +511,20 @@
488 D.removeClass(this.e.btnClear, 'hidden');
489 D.disable(D.option(this.e.select,0,"Select a local edit..."));
490 const currentFinfo = theFinfo || P.finfo || {};
491 ilist.sort(f.compare).forEach(function(finfo,n){
492 const key = stasher.indexKey(finfo),
493 branch = P.fileSelectWidget.checkinBranchName(finfo.checkin);
 
 
 
494 const opt = D.option(
495 self.e.select, n+1/*value is (almost) irrelevant*/,
496 [F.hashDigits(finfo.checkin, 6), branch,
497 f.timestring(new Date(finfo.stashTime)),
498 false ? finfo.filename : F.shortenFilename(finfo.filename)
499 ].join(' ')
500 );
501 opt._finfo = finfo;
502 if(0===f.compare(currentFinfo, finfo)){
503 D.attr(opt, 'selected', true);
504 }
@@ -1139,10 +1165,11 @@
1139 */
1140 P.stashContentChange = function(onlyFinfo){
1141 if(affirmHasFile(true)){
1142 const fi = this.finfo;
1143 fi.isExe = this.e.cbIsExe.checked;
 
1144 if(onlyFinfo && $stash.hasStashedContent(fi)){
1145 $stash.updateFile(fi);
1146 }else{
1147 $stash.updateFile(fi, P.fileContent());
1148 }
1149
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -112,11 +112,11 @@
112 and that would be horribly inefficient (meaning "battery-consuming"
113 on mobile devices).
114 */
115 const $stash = {
116 keys: {
117 index: F.page.name+'/index'
118 },
119 /**
120 index: {
121 "CHECKIN_HASH:FILENAME": {file info w/o content}
122 ...
@@ -138,11 +138,30 @@
138 by prepending P.name to suffix. */
139 contentKey: function(suffix){return P.name+'/'+suffix},
140 /** Returns the index object, fetching it from the stash or creating
141 it anew on the first call. */
142 getIndex: function(){
143 if(!this.index){
144 this.index = F.storage.getJSON(
145 this.keys.index, undefined
146 );
147 if(!this.index){
148 /*check for and remove/replace older name. This whole block
149 can be removed once the test phase is done (don't want to
150 invalidate the testers' edits on the test server). When
151 doing so, be sure to replace undefined in the above
152 getJSON() call with {}. */
153 const oldName = F.page.name+':index';
154 this.index = F.storage.getJSON(oldName,undefined);
155 if(this.index){
156 F.storage.remove(oldName);
157 this.storeIndex();
158 }else{
159 this.index = {};
160 }
161 }
162 }
163 return this.index;
164 },
165 _fireStashEvent: function(){
166 if(this._disableNextEvent) delete this._disableNextEvent;
167 else F.page.dispatchEvent('fileedit-stash-updated', this);
@@ -173,10 +192,11 @@
192 filename: finfo.filename,
193 mimetype: finfo.mimetype
194 });
195 record.isExe = !!finfo.isExe;
196 record.stashTime = new Date().getTime();
197 if(!record.branch) record.branch=finfo.branch;
198 this.storeIndex();
199 if(arguments.length>1){
200 F.storage.set(this.contentKey(key), content);
201 }
202 this._fireStashEvent();
@@ -256,10 +276,11 @@
276 },
277 finfo: {},
278 cache: {
279 checkins: undefined,
280 files:{},
281 branchKey: 'fileedit/uuid-branches',
282 branchNames: {}
283 },
284 /**
285 Fetches the list of leaf checkins from the server and updates
286 the UI with that list.
@@ -281,15 +302,16 @@
302 self.cache.checkins = list;
303 D.clearElement(D.enable(self.e.selectCi));
304 let loadThisOne;
305 list.forEach(function(o,n){
306 if(!n) loadThisOne = o;
307 self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
308 D.option(self.e.selectCi, o.checkin,
309 o.timestamp+' ['+o.branch+']: '
310 +F.hashDigits(o.checkin));
311 });
312 F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
313 self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
314 }
315 });
316 },
317 /**
@@ -347,18 +369,19 @@
369 If this object has ever loaded the given checkin version via
370 loadLeaves(), this returns the branch name associated with that
371 version, else returns undefined;
372 */
373 checkinBranchName: function(uuid){
374 return this.cache.branchNames[F.hashDigits(uuid,true)];
375 },
376
377 /**
378 Initializes the checkin/file selector widget. Must only be
379 called once.
380 */
381 init: function(){
382 this.cache.branchNames = F.storage.getJSON(this.cache.branchKey, {});
383 const selCi = this.e.selectCi = D.select(),
384 selFiles = this.e.selectFiles
385 = D.addClass(D.select(), 'file-list'),
386 btnLoad = this.e.btnLoadFile =
387 D.addClass(D.button("Load file"), "flex-shrink"),
@@ -488,17 +511,20 @@
511 D.removeClass(this.e.btnClear, 'hidden');
512 D.disable(D.option(this.e.select,0,"Select a local edit..."));
513 const currentFinfo = theFinfo || P.finfo || {};
514 ilist.sort(f.compare).forEach(function(finfo,n){
515 const key = stasher.indexKey(finfo),
516 branch = finfo.branch
517 || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
518 /* Remember that we don't know the branch name for non-leaf versions
519 which P.fileSelectWidget() has never seen/cached. */
520 const opt = D.option(
521 self.e.select, n+1/*value is (almost) irrelevant*/,
522 [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
523 f.timestring(new Date(finfo.stashTime)),' ',
524 false ? finfo.filename : F.shortenFilename(finfo.filename)
525 ].join('')
526 );
527 opt._finfo = finfo;
528 if(0===f.compare(currentFinfo, finfo)){
529 D.attr(opt, 'selected', true);
530 }
@@ -1139,10 +1165,11 @@
1165 */
1166 P.stashContentChange = function(onlyFinfo){
1167 if(affirmHasFile(true)){
1168 const fi = this.finfo;
1169 fi.isExe = this.e.cbIsExe.checked;
1170 if(!fi.branch) fi.branch = this.fileSelectWidget.checkinBranchName(fi.checkin);
1171 if(onlyFinfo && $stash.hasStashedContent(fi)){
1172 $stash.updateFile(fi);
1173 }else{
1174 $stash.updateFile(fi, P.fileContent());
1175 }
1176
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -66,14 +66,20 @@
6666
catch(e){return dflt}
6767
},
6868
/** Returns true if the storage contains the given key,
6969
else false. */
7070
contains: (k)=>$storageHolder.hasOwnProperty(k),
71
- /** Removes the given key from the storage. */
72
- remove: (k)=>$storage.removeItem(k),
73
- /** Clears ALL keys from the storage. */
74
- clear: ()=>$storage.clear(),
71
+ /** Removes the given key from the storage. Returns this. */
72
+ remove: function(k){
73
+ $storage.removeItem(k);
74
+ return this;
75
+ },
76
+ /** Clears ALL keys from the storage. Returns this. */
77
+ clear: function(){
78
+ $storage.clear();
79
+ return this;
80
+ },
7581
/** Returns an array of all keys currently in the storage. */
7682
keys: ()=>Object.keys($storageHolder),
7783
/** Returns true if this storage is transient (only available
7884
until the page is reloaded), indicating that fileStorage
7985
and sessionStorage are unavailable. */
8086
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -66,14 +66,20 @@
66 catch(e){return dflt}
67 },
68 /** Returns true if the storage contains the given key,
69 else false. */
70 contains: (k)=>$storageHolder.hasOwnProperty(k),
71 /** Removes the given key from the storage. */
72 remove: (k)=>$storage.removeItem(k),
73 /** Clears ALL keys from the storage. */
74 clear: ()=>$storage.clear(),
 
 
 
 
 
 
75 /** Returns an array of all keys currently in the storage. */
76 keys: ()=>Object.keys($storageHolder),
77 /** Returns true if this storage is transient (only available
78 until the page is reloaded), indicating that fileStorage
79 and sessionStorage are unavailable. */
80
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -66,14 +66,20 @@
66 catch(e){return dflt}
67 },
68 /** Returns true if the storage contains the given key,
69 else false. */
70 contains: (k)=>$storageHolder.hasOwnProperty(k),
71 /** Removes the given key from the storage. Returns this. */
72 remove: function(k){
73 $storage.removeItem(k);
74 return this;
75 },
76 /** Clears ALL keys from the storage. Returns this. */
77 clear: function(){
78 $storage.clear();
79 return this;
80 },
81 /** Returns an array of all keys currently in the storage. */
82 keys: ()=>Object.keys($storageHolder),
83 /** Returns true if this storage is transient (only available
84 until the page is reloaded), indicating that fileStorage
85 and sessionStorage are unavailable. */
86

Keyboard Shortcuts

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