-
Notifications
You must be signed in to change notification settings - Fork 7
Change Detection
The project page can be used for editing.
It is normal to ask a user if they want to save edits before leaving an editor.
However, users should only be prompted to save when changes have been made or the project is new.
This requires a method to record or detect when changes have been made.
Two methods are:
-
Set a "dirty bit", e.g.
isChanged = true;
every time the user makes a change. This is very simple to implement, but it requires extra code proportional to the number of things that can be changed. It is easy to omit code to record changes, and hard to test for complete correctness. -
Record the state of the project when the editor is entered and compare it to the current state when the user tries to leave the editor. This has the problem of taking more space (but projects are small in absolute terms) and requiring some sophistication to detect changes given the the project has a graph structure with many objects and fields.
We should try method 2. We already store graphs in a simplified representation (JSON), and since this is everything that we store, it is exactly the right place to check for any changes that will be significant.
Here is what a simple project looks like as JSON (after some reformatting to reduce the number of lines):
{ "projectName": "test",
"projectDescription": "",
"blocks": {
"bs": [
{ "typeName": "SamplePlayer",
"id": 1,
"typeId": 1,
"name": "S1",
"givenName": "SamplePlayer",
"collapse": true,
"audioObj": {},
"inNode": [],
"outNode": [["S1", 2, "0", 0]],
"color": "#e5777d",
"inDisabled": true,
"osc": false,
"inDisableds": [true, true, true, true, true, true, true, true, true, true],
"random": false,
"loop": false,
"speed": 1,
"reversed": false,
"playings": [false, false, false, false, false, false, false, false, false, false],
"files": [null, null, null, null, null, null, null, null, null, null],
"masterVolume": 100
},
{
"typeName": "Speaker",
"id": 2,
"typeId": 1,
"name": "S1",
"givenName": "Speaker",
"collapse": true,
"audioObj": {},
"inNode": [["S1", 1, "0"]],
"outNode": [],
"color": "#f0fec7",
"renderRate": 100,
"suspended": false,
"meterL": 60,
"meterR": 60
}
],
"nowOut": [],
"cns": {}
}
}
When the project page is opened, save the JSON string as originalProject
. If the user saves the project, update orginalProject
to hold the JSON that is saved. So currentProject
is exactly whatever is currently saved in the database.
When the user is about to exit the editor, create a new JSON string currentProject
(which would be the string to save if the user wants to save it). Then compare originalProject
to currentProject
. I worry that the order of fields and objects (which is pretty arbitrary) might change: Normally, it is more reliable to compare actual structures than to compare string representations of structures because strings might contain arbitrary ID numbers or list sets of things in arbitrary order. However, I think we can get away with simple string compares. At least we can try comparing strings, and if we find that there are "false positives" due meaningless string differences, we can then implement a more robust "project compare" function that gets it right.