not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
8.3 KiB

  1. [Go back to tutorial home](tutorial.md)
  2. # Step 4: handle journal and datastore
  3. *(Estimated time: 30mn)*
  4. In the previous step, we've started to see how to use the unique Sugar UI. Let's see now another major feature of Sugar, the Journal, and how to handle it from our activity.
  5. ### What is the Journal?
  6. Launch the Paint activity from the Sugarizer home view.
  7. ![](images/tutorial_step4_1.png)
  8. Draw something.
  9. ![](images/tutorial_step4_2.png)
  10. Then stop the activity by clicking on the Stop button to the right.
  11. Relaunch it. You will retrieve the same drawing. That what the Journal is for: take care of your work without need to save it. Stop the activity again and go to the home view. Now just let the mouse on the Paint icon without clicking on it. A popup will appear after one second.
  12. ![](images/tutorial_step4_3.png)
  13. Click on the **Start new** item.
  14. This time a new drawing is created. Draw something else and click on the Paint icon to access the activity menu. Change the text to "*My second drawing*".
  15. ![](images/tutorial_step4_4.png)
  16. Stop the activity to go back to the Sugarizer home view. Then click on the Journal icon under the XO buddy icon.
  17. ![](images/tutorial_step4_5.png)
  18. It will display the Journal view. You will see here all your past work: the initial drawing and the second drawing that you've renamed. Just click on one of these lines to relaunch the activity in the exact state where you leave it. That's why the Journal is so useful.
  19. ![](images/tutorial_step4_6.png)
  20. Note that in the Journal you will see also your new Pawn activity. Let's see how we could handle context saving in this activity like Paint activity.
  21. ### Identify the context
  22. The "context" for our Pawn activity is the current n umber of pawns on the board. So a user could expect to retrieve the same number of pawns when he reopens the activity.
  23. Let's try to implement it.
  24. First we will slightly refactor (i.e. improve) our `activity/activity.js` file. Here is the current implementation:
  25. // Handle click on add
  26. document.getElementById("add-button").addEventListener('click', function (event) {
  27. var pawn = document.createElement("div");
  28. pawn.className = "pawn";
  29. document.getElementById("pawns").appendChild(pawn);
  30. icon.colorize(pawn, currentenv.user.colorvalue);
  31. document.getElementById("user").innerHTML = "<h1>"+currentenv.user.name+" played !</h1>";
  32. });
  33. We will refactor it to store pawns in an array `pawns` and to add a new method `drawPawn` to draw all icons at one time. So instead of adding a new `div` element on each button click, we just add a new element in the `pawns` array and we call the `drawPawn` icon to redraw the board. Here is the resulting code:
  34. // Draw pawns
  35. var pawns = [];
  36. var drawPawns = function() {
  37. document.getElementById("pawns").innerHTML = '';
  38. for (var i = 0 ; i < pawns.length ; i++) {
  39. var pawn = document.createElement("div");
  40. pawn.className = "pawn";
  41. document.getElementById("pawns").appendChild(pawn);
  42. icon.colorize(pawn, pawns[i]);
  43. }
  44. }
  45. // Handle click on add
  46. document.getElementById("add-button").addEventListener('click', function (event) {
  47. pawns.push(currentenv.user.colorvalue);
  48. drawPawns();
  49. document.getElementById("user").innerHTML = "<h1>"+currentenv.user.name+" played !</h1>";
  50. });
  51. The array `pawns` contain all pawns. It's the context for our activity.
  52. ### Store context in the datastore
  53. To store the context, we have to handle the **datastore**. The datastore is the place where Sugar store the Journal. During the activity setup, Sugar-Web automatically initialize the datastore for the activity. The `activity.getDatastoreObject()` method allow you to retrieve the datastore object allocated for the current activity.
  54. The `setDataAsText` method on this object is a way store a text string inside this object to retrieve it later.
  55. The `save` method store the object when it has been updated.
  56. So below is the source code to store the context in the datastore.
  57. First, convert the **pawns** array as JSON string and store it in the current object.
  58. var jsonData = JSON.stringify(pawns);
  59. activity.getDatastoreObject().setDataAsText(jsonData);
  60. Then save the updated object.
  61. activity.getDatastoreObject().save(function (error) {
  62. if (error === null) {
  63. console.log("write done.");
  64. } else {
  65. console.log("write failed.");
  66. }
  67. });
  68. This whole code should be called at the end of the activity. To do that we have to catch the click on the Stop button of the activity. So here is the complete source code we will add in the `activity/activity.js` file, just below the `add-button` event listener:
  69. // Save in Journal on Stop
  70. document.getElementById("stop-button").addEventListener('click', function (event) {
  71. console.log("writing...");
  72. var jsonData = JSON.stringify(pawns);
  73. activity.getDatastoreObject().setDataAsText(jsonData);
  74. activity.getDatastoreObject().save(function (error) {
  75. if (error === null) {
  76. console.log("write done.");
  77. } else {
  78. console.log("write failed.");
  79. }
  80. });
  81. });
  82. It's the first step: the board is now safely save in the datastore.
  83. Let's know how we could retrieve it.
  84. ### Detect the need to load the context
  85. Our Pawn activity works well when it's called from the **Start new** menu, i.e. with a new instance. Because in that case we don't have to reload the context.
  86. So the first question to ask is: how to detect that we need to load the context?
  87. Once again, the Sugar-Web environment could help us. When an activity is launched from an existing context, environment contains an `objectId` property with the identifier for the datastore object. When an activity is launch with a new instance, this property is null.
  88. So we will update our request on environment in `activity/activity.js` to test this variable:
  89. env.getEnvironment(function(err, environment) {
  90. currentenv = environment;
  91. document.getElementById("user").innerHTML = "<h1>"+"Hello"+" "+environment.user.name+" !</h1>";
  92. // Load from datastore
  93. if (!environment.objectId) {
  94. console.log("New instance");
  95. } else {
  96. console.log("Existing instance");
  97. }
  98. });
  99. Let's display the JavaScript console on your browser and test it. Launch the Pawn activity from the **Start new** menu or from List view of activities. Here is the result:
  100. ![](images/tutorial_step4_7.png)
  101. Now open the Pawn activity from the Journal or by clicking on the Pawn icon on the Home view. Here is the result:
  102. ![](images/tutorial_step4_8.png)
  103. Of course, the context is not loaded for the moment in the activity but at least we've got a way to detect when it should be loaded and when it shouldn’t be loaded.
  104. ### Load context from the datastore
  105. When our activity is launched with a new instance - the first branch from the previous `if` instruction, there is nothing to do. In that case, the `pawns` will be initialize with an empty array as today.
  106. When our activity is launched with an existing instance - the `else` branch, we have to load the context to init our `pawns` array.
  107. In the same way that the `setAsText`/`save` methods, the datastore object provide a `loadAsText` method to retrieve the string stored in an object. So the code we will have to write to retrieve our context is:
  108. activity.getDatastoreObject().loadAsText(function(error, metadata, data) {
  109. if (error==null && data!=null) {
  110. pawns = JSON.parse(data);
  111. }
  112. });
  113. We load the string - in the data parameter -, we parse it to an object and we set it in our `pawns` array. That's all for the initialization but we need also to draw it, so here is the full source code to write in `activity/activity.js`:
  114. // Load from datastore
  115. if (!environment.objectId) {
  116. console.log("New instance");
  117. } else {
  118. activity.getDatastoreObject().loadAsText(function(error, metadata, data) {
  119. if (error==null && data!=null) {
  120. pawns = JSON.parse(data);
  121. drawPawns();
  122. }
  123. });
  124. }
  125. Let's try if it works.
  126. Launch the Pawn activity from the **Start new** menu. Here is the result:
  127. ![](images/tutorial_step4_9.png)
  128. The activity display a blank board as expected.
  129. Click few times on the Plus button to add some pawns and stop the activity. Now re-open the activity by clicking on the Pawn icon on the Home view. Here is the result:
  130. ![](images/tutorial_step4_10.png)
  131. Yes! It's what we expected too: the activity reopens with the right number of pawns.
  132. The Journal is now fully supported by the Pawn activity.
  133. [Go to next step](tutorial_step5.md)