Using two wikiedit windows on two repositories
(1) By Chris (crustyoz) on 2020-08-17 22:23:16 [source]
I have two repositories that are substantially the same. One contains English text files for translation to Spanish. The other contains the same English text files for translation to French.
In addition to the text files, there are three wiki pages in each:
- LMS Spanish
- Linux and MacOS
- MS Windows
and
- LMS French
- Linux and MacOS
- MS Windows
The contents of the last two wiki pages are identical across the repositories. The content of the first wiki page varies only in the title.
I created these pages first in the Spanish repository then opened the French repository in another Firefox browser tab and attempted to cut and paste from one to the other.
The newly created French wiki page was blank to start, as expected. I needed to have the Spanish wikiedit page in Editor mode to cut and paste the body, but when I selected the Spanish wiki page from the list of all wiki pages, the Editor mode window was empty.
It appears that the local storage data is shared between the two Firefox tabs. They are both on the same domain and the stored data does not differentiate between tabs. The last record stored represents the newly created and empty French wiki page and that is what was retrieved by the Spanish wikiedit page.
(2) By Stephan Beal (stephan) on 2020-08-18 00:31:52 in reply to 1 [link] [source]
It appears that the local storage data is shared between the two Firefox tabs. They are both on the same domain and the stored data does not differentiate between tabs.
That's correct and the desired behaviour. A JS app has no way to distinguish between tabs. If it did differentiate between tabs it would mean the data is lost the moment you leave the tab because that tab no longer exists. sessionStorage is supposedly different, tied to the tab, but i've admittedly not done more than basic tests with that.
Yours is a a use case i had not considered during development, but it gives me that idea that maybe we could, where it's available, offer a selection of which storage to use: localStorage (persistent), sessionStorage (semi-persistent), and no storage (local to the page). The storage API currently selects the longest-lived storage it can legally use, and doesn't expose other options (they're all hidden behind one API). That could probably be expanded to figure out which options are available and offer a selection of data sources. That would, at least hypothetically, allow you to use different tabs with sessionStorage to have separate state.
Does that address your point?
(3) By Chris (crustyoz) on 2020-08-18 11:30:43 in reply to 2 [link] [source]
You have recognised and explained the constraint, thanks.
Offering a variety of storage options is likely to confuse users so I would not recommend it.
I have an unrelated purchasing application that also uses local storage and could bump into the same issue for a rare and "sophisticated" user who opens a second purchasing tab, so I need to give more thought to the issue myself.
I don't see a way around the problem at this moment and might need to accept that the situation is truly rare.
(5) By sean (jungleboogie) on 2020-08-18 18:08:31 in reply to 3 [link] [source]
I don't see a way around the problem at this moment and might need to accept that the situation is truly rare.
It's a way around the problem, but not glamorous...two different firefox profiles.
If you're a firefox user, you can about:profiles
and create a second one for your second 'tab' in the Fossil repo.
(7) By Chris (crustyoz) on 2020-08-18 18:17:25 in reply to 5 [link] [source]
While it might work for me (as a Firefox user), it does not generalise to the public using any browser and unaware they might bump into this issue.
(8) By sean (jungleboogie) on 2020-08-18 18:29:04 in reply to 7 [link] [source]
Yes, that's right. I meant this as a 'solution' specific to your case, not for everyone.
I also agree that adding storage options into the wiki/fileedit wouldn't be a benefit to the general user.
(4) By John Rouillard (rouilj) on 2020-08-18 17:56:12 in reply to 2 [link] [source]
Hmm, looks like my reply to this disappeared.
I agree multiple storage backends would be confusing to the user and the ui.
However it looks like storage* backends are all key:value stores.
It also looks like the key is simply the wiki page name. So what is happening here is a key conflict. IIUC key:value store is unique to the host name, so this conflict doesn't happen for https://host1/fossil/WikiPage and https://host2/fossil/WikiPage as host1 and host 2 storage areas are different.
What happens if you augment the key with the current URL path? This way there would be different keys for WikiPage in different repos.
One would be stored with key:
.../repo1|WikiPage
and one with:
.../repo2|WikiPage
this should solve the issue right?
(6) By Stephan Beal (stephan) on 2020-08-18 18:16:48 in reply to 4 [link] [source]
However it looks like storage* backends are all key:value stores.
Correct.
It also looks like the key is simply the wiki page name.
Kinda. It's an internally mangled key, to avoid conflicts between different fossil pages, but it's based on the name.
So what is happening here is a key conflict.
There isn't, as far as the app is concerned, any conflict. They key refers to some opaque wiki page content and it uses whatever content is put into it. If the user, as in the OPs case, uses two tabs to do so, it's last-one-wins. There's no reliable way to detect when a browser's "duplicate tab" is used, so there's no reliable way for the app to recognize that another instance overwrite the record, other than, perhaps, time-stamping each record, recording that timestamp in app-local memory (neither sessionStorage nor localStorage), and comparing that on every operation. (Feel free to patch it for that - it wasn't designed with that in mind, so it might not be so straightforward.)
What happens if you augment the key with the current URL path? This way there would be different keys for WikiPage in different repos.
...
Oh, so very no...
i've just confirmed on my hoster that multiple repos from the same origin server will use the same localstorage. That is very, VERY, oh so veryvery bad.
My understanding of "origin" was "the repo root," not "the domain."
i will patch that immediately to use sessionStorage instead of localStorage by default. It's not as persistent, but it is as long as the same tab is opened, so it's not a total loss.
Holy moley... be back soon, and will announce this change in a new top-level post to help avoid that it gets overlooked.
this should solve the issue right?
Not entirely because the page name is not necessarily part of the URL. You can now visit /wikiedit
with no arguments and select a page to edit (that wasn't the case before).
(10) By John Rouillard (rouilj) on 2020-08-18 20:38:13 in reply to 6 [link] [source]
My understanding of "origin" was "the repo root," not "the domain."
Um yeah no. Think https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy. It's exactly the same rational to prevent data leaks.
Not entirely because the page name is not necessarily part of the URL. You can now visit /wikiedit with no arguments and select a page to edit (that wasn't the case before).
but you also said:
It also looks like the key is simply the wiki page name.
Kinda. It's an internally mangled key, to avoid conflicts between different fossil pages, but it's based on the name.
So as soon as you change to edit an actual page, there is a manged wiki page name based key that will be different for two wiki pages in the same fossil repo.
If you are still at the select page step of wikiedit, I don't expect it to use any localstorage.
(11) By Stephan Beal (stephan) on 2020-08-18 21:29:46 in reply to 10 [link] [source]
Um yeah no.
Yeah, huge facepalm on my part. i knew that deep down, i just somehow really bungled it for purposes of localStorage
and sessionStorage
.
So as soon as you change to edit an actual page, there is a manged wiki page name based key that will be different for two wiki pages in the same fossil repo.
It doesn't actually stash anything until the first "change" event is fired by the textarea (editor widget), at which point it stashes the edits using a key which is different per page, so yes, you'll have 2 entries. Simply selecting a file to edit does not stash anything, though - that's delayed until a "change" event.
The editor remembers up to the latest 10 (7?) edits. After that it starts discarding the least-recently-used. It also discards those immediately when a page is saved or when the "discard edits" buttons are used (either discarding that one page's state or all page-edit state, depending on which button).
If you are still at the select page step of wikiedit, I don't expect it to use any localstorage.
For wikiedit, that's correct. For fileedit we load the list of leaf checkins and those get cached so that we can map UUIDs to branch names in later sessions after a given UUID is no longer a leaf (a minor cosmetic issue, but avoids a small bit of confusion). So when visiting fileedit there's always at least one stashed entry for that page.
"Soon" we will have similar stashed edits for the forum, so that you can have replies to multiple threads going at a single time, as well as a single/in-progress new post, without threat of losing the edits.
BTW: the latest trunk now sandboxes that storage access on a per-repo basis (by project code, which is a long unique-per-repo hash), so wikiedit and fileedit will not see edit state from other repos, same origin or otherwise.
(9.1) By Stephan Beal (stephan) on 2020-08-18 18:56:07 edited from 9.0 in reply to 1 [link] [source]
It appears that the local storage data is shared between the two Firefox tabs. They are both on the same domain and the stored data does not differentiate between tabs. The last record stored represents the newly created and empty French wiki page and that is what was retrieved by the Spanish wikiedit page.
i should have, based on this description, recognized the problem sooner. It's not the tabs themselves but the scope of window.localStorage
that is the problem here (and it is very much a problem, unlike the tab-related scoping). See /forumpost/33dd754eaf for the gory details and solution.
(Edited for broken link.)