0 Votes

Changes for page Todolist Macro

Last modified by Ryan C on 2025/04/30 07:54

From version 10.1
edited by Ryan C
on 2025/04/24 11:00
Change comment: There is no comment for this version
To version 14.1
edited by Ryan C
on 2025/04/24 11:07
Change comment: Todo List item added

Summary

Details

Page properties
Content
... ... @@ -3,5 +3,8 @@
3 3  {{todolist width="50%" center="1"}}
4 4  a thing|1
5 5  a second thing|0
6 +a 3nd thing|0
7 +a 3nd thing|1
8 +a 3nd thing|0
6 6  
7 7  {{/todolist}}
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,7 +1,7 @@
1 1  requirejs.config({
2 2   baseUrl: '${xwiki.getDocument("TodoLists.TodoListMacro").getURL("download")}/',
3 3   paths: {
4 - 'jquery': 'https://code.jquery.com/jquery-1.10.2.min'
4 + 'jquery': 'https://code.jquery.com/jquery-3.6.0.min' // Updated jQuery version
5 5   },
6 6   shim: {
7 7   'ember-data': {
... ... @@ -13,241 +13,280 @@
13 13   }
14 14  });
15 15  
16 -require(['jquery', 'handlebars-v1.2.1', 'ember-data', 'ember' ], function ($) {
16 +require(['jquery', 'handlebars-v1.2.1', 'ember-data', 'ember'], function($) {
17 + // Create app
18 + window.Todos = Ember.Application.create({
19 + rootElement: '#todoappdiv'
20 + });
17 17  
18 -// create app
19 -window.Todos = Ember.Application.create({
20 - rootElement: '#todoappdiv'
21 -});
22 -
23 -// define the todolist store that will write to the TodoListsService
24 -Todos.ApplicationAdapter = DS.Adapter.extend({
25 - createRecord: function(store, type, record) {
26 - console.log("createRecord");
27 - var query = { create: "1", content : JSON.stringify(record) };
28 - return new Ember.RSVP.Promise(function(resolve, reject) {
29 - jQuery.getJSON("${xwiki.getURL("TodoLists.TodoListsService")}?page=" + XWiki.currentSpace + "." + XWiki.currentPage + "&xpage=plain&outputSyntax=plain", query).then(function(data) {
30 - Ember.run(null, resolve, data);
31 - }, function(jqXHR) {
32 - jqXHR.then = null; // tame jQuery's ill mannered promises
33 - Ember.run(null, reject, jqXHR);
22 + // Define the todolist store that will write to the TodoListsService
23 + Todos.ApplicationAdapter = DS.Adapter.extend({
24 + createRecord: function(store, type, record) {
25 + console.log("createRecord");
26 + var data = this.serialize(record, { includeId: true });
27 + var query = { create: "1", content: JSON.stringify(data) };
28 +
29 + return new Ember.RSVP.Promise(function(resolve, reject) {
30 + jQuery.getJSON(
31 + "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
32 + XWiki.currentSpace + "." + XWiki.currentPage +
33 + "&xpage=plain&outputSyntax=plain",
34 + query
35 + ).then(function(data) {
36 + Ember.run(function() {
37 + resolve(data);
38 + });
39 + }, function(jqXHR) {
40 + Ember.run(function() {
41 + reject(jqXHR);
42 + });
43 + });
34 34   });
35 - });
36 - },
37 - deleteRecord: function(store, type, record) {
38 - console.log("deleteRecord");
39 - return this.saveAll(store.recordArrayManager.recordArraysForRecord(record).list[0].content);
40 - },
41 - find: function(store, type, id) {
42 - console.log("find");
43 - return;
44 - },
45 - findAll: function(store, type, sinceToken) {
46 - console.log("findAll");
47 - var query = { since: sinceToken };
48 - return new Ember.RSVP.Promise(function(resolve, reject) {
49 - jQuery.getJSON("${xwiki.getURL("TodoLists.TodoListsService")}?page=" + XWiki.currentSpace + "." + XWiki.currentPage + "&xpage=plain&outputSyntax=plain", query).then(function(data) {
50 - Ember.run(null, resolve, data);
51 - }, function(jqXHR) {
52 - jqXHR.then = null; // tame jQuery's ill mannered promises
53 - Ember.run(null, reject, jqXHR);
45 + },
46 +
47 + deleteRecord: function(store, type, record) {
48 + console.log("deleteRecord");
49 + var recordArrays = store.recordArrayManager.recordArraysForRecord(record);
50 + if (recordArrays && recordArrays.list && recordArrays.list[0]) {
51 + return this.saveAll(recordArrays.list[0].content);
52 + }
53 + return Ember.RSVP.resolve();
54 + },
55 +
56 + find: function(store, type, id) {
57 + console.log("find");
58 + return Ember.RSVP.resolve();
59 + },
60 +
61 + findAll: function(store, type, sinceToken) {
62 + console.log("findAll");
63 + var query = { since: sinceToken };
64 +
65 + return new Ember.RSVP.Promise(function(resolve, reject) {
66 + jQuery.getJSON(
67 + "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
68 + XWiki.currentSpace + "." + XWiki.currentPage +
69 + "&xpage=plain&outputSyntax=plain",
70 + query
71 + ).then(function(data) {
72 + Ember.run(function() {
73 + resolve(data);
74 + });
75 + }, function(jqXHR) {
76 + Ember.run(function() {
77 + reject(jqXHR);
78 + });
79 + });
54 54   });
55 - });
56 - },
57 - updateRecord: function(store, type, record) {
58 - return this.saveAll(store.recordArrayManager.recordArraysForRecord(record).list[0].content);
59 - },
60 - saveAll: function(alldata) {
61 - console.log("updateRecord");
62 - var query = { save: "1", content : JSON.stringify(alldata) };
63 - return new Ember.RSVP.Promise(function(resolve, reject) {
64 - jQuery.getJSON("${xwiki.getURL("TodoLists.TodoListsService")}?page=" + XWiki.currentSpace + "." + XWiki.currentPage + "&xpage=plain&outputSyntax=plain", query).then(function(data) {
65 - Ember.run(null, resolve, data);
66 - }, function(jqXHR) {
67 - jqXHR.then = null; // tame jQuery's ill mannered promises
68 - Ember.run(null, reject, jqXHR);
81 + },
82 +
83 + updateRecord: function(store, type, record) {
84 + var recordArrays = store.recordArrayManager.recordArraysForRecord(record);
85 + if (recordArrays && recordArrays.list && recordArrays.list[0]) {
86 + return this.saveAll(recordArrays.list[0].content);
87 + }
88 + return Ember.RSVP.resolve();
89 + },
90 +
91 + saveAll: function(alldata) {
92 + console.log("saveAll");
93 + var query = { save: "1", content: JSON.stringify(alldata) };
94 +
95 + return new Ember.RSVP.Promise(function(resolve, reject) {
96 + jQuery.getJSON(
97 + "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
98 + XWiki.currentSpace + "." + XWiki.currentPage +
99 + "&xpage=plain&outputSyntax=plain",
100 + query
101 + ).then(function(data) {
102 + Ember.run(function() {
103 + resolve(data);
104 + });
105 + }, function(jqXHR) {
106 + Ember.run(function() {
107 + reject(jqXHR);
108 + });
109 + });
69 69   });
70 - });
71 - }
72 -});
111 + }
112 + });
73 73  
74 -// use my own store
75 -Todos.store = DS.Store.create({
76 - adapter: 'ApplicationAdapter'
77 -});
114 + // Register the adapter
115 + Todos.ApplicationAdapter.reopen({
116 + namespace: 'api'
117 + });
78 78  
79 -// Todos.ApplicationAdapter = DS.FixtureAdapter.extend();
119 + // Routing
120 + Todos.Router.map(function() {
121 + this.resource('todos', { path: '' }, function() {
122 + this.route('active');
123 + this.route('completed');
124 + });
125 + });
80 80  
81 -// routing
82 -Todos.Router.map(function() {
83 - this.resource('todos', { path: '' }, function() {
84 - this.route('active');
85 - this.route('completed');
127 + Todos.TodosRoute = Ember.Route.extend({
128 + model: function() {
129 + return this.store.find('todo');
130 + }
86 86   });
87 -});
88 88  
89 -Todos.TodosRoute = Ember.Route.extend({
90 - model: function() {
91 - return this.store.find('todo');
92 - }
93 -});
133 + Todos.TodosIndexRoute = Ember.Route.extend({
134 + model: function() {
135 + return this.modelFor('todos');
136 + }
137 + });
94 94  
95 -Todos.TodosIndexRoute = Ember.Route.extend({
96 - model: function() {
97 - return this.modelFor('todos');
98 - }
99 -});
139 + Todos.TodosActiveRoute = Ember.Route.extend({
140 + model: function() {
141 + return this.store.filter('todo', function(todo) {
142 + return !todo.get('isCompleted');
143 + });
144 + },
145 + renderTemplate: function(controller) {
146 + this.render('todos/index', { controller: controller });
147 + }
148 + });
100 100  
101 -// ... additional lines truncated for brevity ...
102 -Todos.TodosActiveRoute = Ember.Route.extend({
103 - model: function(){
104 - return this.store.filter('todo', function(todo) {
105 - return !todo.get('isCompleted');
106 - });
107 - },
108 - renderTemplate: function(controller) {
109 - this.render('todos/index', {controller: controller});
110 - }
111 -});
150 + Todos.TodosCompletedRoute = Ember.Route.extend({
151 + model: function() {
152 + return this.store.filter('todo', function(todo) {
153 + return todo.get('isCompleted');
154 + });
155 + },
156 + renderTemplate: function(controller) {
157 + this.render('todos/index', { controller: controller });
158 + }
159 + });
112 112  
113 -Todos.TodosCompletedRoute = Ember.Route.extend({
114 - model: function(){
115 - return this.store.filter('todo', function (todo) {
116 - return todo.get('isCompleted');
117 - });
118 - },
119 - renderTemplate: function(controller){
120 - this.render('todos/index', {controller: controller});
121 - }
122 -});
161 + // Data model
162 + Todos.Todo = DS.Model.extend({
163 + title: DS.attr('string'),
164 + priority: DS.attr('string'),
165 + assignee: DS.attr('string'),
166 + isCompleted: DS.attr('boolean')
167 + });
123 123  
124 -// data model
125 -Todos.Todo = DS.Model.extend({
126 - title: DS.attr('string'),
127 - priority: DS.attr('string'),
128 - assignee: DS.attr('string'),
129 - isCompleted: DS.attr('boolean')
130 -});
169 + // Controller
170 + Todos.TodoController = Ember.ObjectController.extend({
171 + actions: {
172 + editTodo: function() {
173 + this.set('isEditing', true);
174 + },
175 + acceptChanges: function() {
176 + this.set('isEditing', false);
131 131  
132 -// ... additional lines truncated for brevity ...
133 -Todos.Todo.FIXTURES = [
134 - {
135 - id: 1,
136 - title: 'Learn Ember.js X',
137 - isCompleted: true
138 - },
139 - {
140 - id: 2,
141 - title: '...',
142 - isCompleted: false
143 - },
144 - {
145 - id: 3,
146 - title: 'Profit!',
147 - isCompleted: false
148 - }
149 -];
150 -
151 -// controler
152 -Todos.TodoController = Ember.ObjectController.extend({
153 - actions: {
154 - editTodo: function () {
155 - this.set('isEditing', true);
178 + if (Ember.isEmpty(this.get('model.title'))) {
179 + this.send('removeTodo');
180 + } else {
181 + this.get('model').save();
182 + }
183 + },
184 + removeTodo: function() {
185 + var todo = this.get('model');
186 + todo.deleteRecord();
187 + todo.save();
188 + }
156 156   },
157 - acceptChanges: function() {
158 - this.set('isEditing', false);
159 159  
160 - if (Ember.isEmpty(this.get('model.title'))) {
161 - this.send('removeTodo');
162 - } else {
163 - this.get('model').save();
164 - }
165 - },
166 - removeTodo: function() {
167 - var todo = this.get('model');
168 - todo.deleteRecord();
169 - todo.save();
170 - }
171 - },
191 + isEditing: false,
172 172  
173 - isEditing: false,
193 + isCompleted: function(key, value) {
194 + var model = this.get('model');
174 174  
175 - isCompleted: function(key, value){
176 - var model = this.get('model');
196 + if (value === undefined) {
197 + // Property being used as a getter
198 + return model.get('isCompleted');
199 + } else {
200 + // Property being used as setter
201 + model.set('isCompleted', value);
202 + model.save();
203 + return value;
204 + }
205 + }.property('model.isCompleted')
206 + });
177 177  
178 - if (value === undefined) {
179 - // property being used as a getter
180 - return model.get('isCompleted');
181 - } else {
182 - // property being used as setter
183 - model.set('isCompleted', value);
184 - model.save();
185 - return value;
186 - }
187 - }.property('model.isCompleted')
188 -});
208 + Todos.TodosController = Ember.ArrayController.extend({
209 + actions: {
210 + createTodo: function() {
211 + // Get the todo title set by the "New Todo" text field
212 + var title = this.get('newTitle');
213 + if (!title || !title.trim()) { return; }
189 189  
190 -Todos.TodosController = Ember.ArrayController.extend({
191 - actions: {
192 - createTodo: function () {
193 - // Get the todo title set by the "New Todo" text field
194 - var title = this.get('newTitle');
195 - if (!title.trim()) { return; }
215 + // Create the new Todo model
216 + var todo = this.store.createRecord('todo', {
217 + title: title,
218 + priority: "P3",
219 + assignee: "all",
220 + isCompleted: false
221 + });
196 196  
197 - // Create the new Todo model
198 - var todo = this.store.createRecord('todo', {
199 - title: title,
200 - priority: "P3",
201 - assignee: "all",
202 - isCompleted: false
203 - });
223 + // Clear the "New Todo" text field
224 + this.set('newTitle', '');
204 204  
205 - // Clear the "New Todo" text field
206 - this.set('newTitle', '');
207 -
208 - // Save the new model
209 - todo.save();
226 + // Save the new model
227 + todo.save().then(function() {
228 + // Force a refresh of the list after saving
229 + Ember.run.later(function() {
230 + Todos.store.find('todo');
231 + }, 100);
232 + });
233 + },
234 +
235 + clearCompleted: function() {
236 + var completed = this.filter(function(todo) {
237 + return todo.get('isCompleted');
238 + });
239 +
240 + completed.forEach(function(todo) {
241 + todo.deleteRecord();
242 + todo.save();
243 + });
244 + }
210 210   },
211 - clearCompleted: function () {
212 - var completed = this.filterProperty('isCompleted', true);
213 - completed.invoke('deleteRecord');
214 - completed.invoke('save');
215 - }
216 - },
217 217  
218 - remaining: function () {
219 - return this.filterProperty('isCompleted', false).get('length');
220 - }.property('@each.isCompleted'),
247 + remaining: function() {
248 + return this.filter(function(todo) {
249 + return !todo.get('isCompleted');
250 + }).get('length');
251 + }.property('@each.isCompleted'),
221 221  
222 - inflection: function () {
223 - var remaining = this.get('remaining');
224 - return remaining === 1 ? 'item' : 'items';
225 - }.property('remaining'),
226 - hasCompleted: function () {
227 - return this.get('completed') > 0;
228 - }.property('completed'),
253 + inflection: function() {
254 + var remaining = this.get('remaining');
255 + return remaining === 1 ? 'item' : 'items';
256 + }.property('remaining'),
257 +
258 + hasCompleted: function() {
259 + return this.get('completed') > 0;
260 + }.property('completed'),
229 229  
230 - completed: function () {
231 - return this.filterProperty('isCompleted', true).get('length');
232 - }.property('@each.isCompleted'),
262 + completed: function() {
263 + return this.filter(function(todo) {
264 + return todo.get('isCompleted');
265 + }).get('length');
266 + }.property('@each.isCompleted'),
233 233  
234 - allAreDone: function(key, value) {
235 - if (value === undefined) {
236 - return !!this.get('length') && this.everyProperty('isCompleted', true);
237 - } else {
238 - this.setEach('isCompleted', value);
239 - this.invoke('save');
240 - return value;
241 - }
242 -}.property('@each.isCompleted')
243 -});
268 + allAreDone: function(key, value) {
269 + if (value === undefined) {
270 + return this.get('length') > 0 && this.every(function(todo) {
271 + return todo.get('isCompleted');
272 + });
273 + } else {
274 + this.forEach(function(todo) {
275 + todo.set('isCompleted', value);
276 + todo.save();
277 + });
278 + return value;
279 + }
280 + }.property('@each.isCompleted')
281 + });
244 244  
245 -// editing
246 -Todos.EditTodoView = Ember.TextField.extend({
247 - didInsertElement: function() {
248 - this.$().focus();
249 - }
250 -});
283 + // Editing
284 + Todos.EditTodoView = Ember.TextField.extend({
285 + didInsertElement: function() {
286 + this.$().focus();
287 + }
288 + });
251 251  
252 -Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
290 + Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
253 253  });
292 +