0 Votes

Changes for page Todolist Macro

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

From version 22.1
edited by Ryan C
on 2025/04/24 11:12
Change comment: Todo List item added
To version 29.1
edited by Ryan C
on 2025/04/30 07:54
Change comment: Migrated property [executionIsolated] from class [XWiki.WikiMacroClass]

Summary

Details

Page properties
Content
... ... @@ -4,5 +4,6 @@
4 4  a 3nd thing|0
5 5  adding this thing|0
6 6  adding this thing|0
7 +refreshed they are still there not even having to save page|0
7 7  
8 8  {{/todolist}}
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,292 +1,333 @@
1 1  requirejs.config({
2 2   baseUrl: '${xwiki.getDocument("TodoLists.TodoListMacro").getURL("download")}/',
3 3   paths: {
4 - 'jquery': 'https://code.jquery.com/jquery-3.6.0.min' // Updated jQuery version
4 + 'jquery-1.10.2': 'https://code.jquery.com/jquery-1.10.2.min'
5 5   },
6 6   shim: {
7 7   'ember-data': {
8 - deps: ['ember', 'jquery']
8 + deps: ['ember']
9 9   },
10 10   'ember': {
11 - deps: ['jquery']
11 + deps: ['jquery-1.10.2']
12 12   }
13 13   }
14 14  });
15 15  
16 -require(['jquery', 'handlebars-v1.2.1', 'ember-data', 'ember'], function($) {
17 - // Create app
18 - window.Todos = Ember.Application.create({
19 - rootElement: '#todoappdiv'
16 +// Load jQuery 1.10.2 specifically for Ember, using noConflict mode
17 +require(['jquery-1.10.2'], function(jQuery) {
18 + // Store the original jQuery and $ if they exist
19 + var originalJQuery = window.jQuery;
20 + var original$ = window.$;
21 +
22 + // Create a new jQuery instance in noConflict mode
23 + var emberJQuery = jQuery.noConflict(true);
24 +
25 + // Now load Ember with our specific jQuery
26 + require(['handlebars-v1.2.1', 'ember-data', 'ember'], function() {
27 + // Make emberJQuery available to Ember
28 + window.jQuery = emberJQuery;
29 + window.$ = emberJQuery;
30 +
31 + // Initialize Ember app
32 + initializeEmberApp(emberJQuery);
33 +
34 + // Restore original jQuery and $ when done
35 + window.jQuery = originalJQuery;
36 + window.$ = original$;
20 20   });
38 +
39 + function initializeEmberApp(jQuery) {
40 + // Create app with specific jQuery instance
41 + window.Todos = Ember.Application.create({
42 + rootElement: '#todoappdiv',
43 + jQuery: jQuery
44 + });
21 21  
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) };
46 + // Define the todolist store that will write to the TodoListsService
47 + Todos.ApplicationAdapter = DS.Adapter.extend({
48 + serialize: function(record, options) {
49 + var serialized = record.record.toJSON();
50 + if (options && options.includeId) {
51 + serialized.id = record.id;
52 + }
53 + return serialized;
54 + },
28 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);
56 + createRecord: function(store, type, record) {
57 + console.log("createRecord");
58 + var serialized = this.serialize(record, { includeId: true });
59 + var query = { create: "1", content: JSON.stringify(serialized) };
60 +
61 + return new Ember.RSVP.Promise(function(resolve, reject) {
62 + var url = "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
63 + XWiki.currentSpace + "." + XWiki.currentPage +
64 + "&xpage=plain&outputSyntax=plain";
65 + console.log("Creating record, URL:", url);
66 +
67 + jQuery.getJSON(url, query).then(function(data) {
68 + console.log("Create success:", data);
69 + Ember.run(function() {
70 + resolve(data);
71 + });
72 + }, function(jqXHR) {
73 + console.error("Create error:", jqXHR);
74 + Ember.run(function() {
75 + reject(jqXHR);
76 + });
38 38   });
39 - }, function(jqXHR) {
40 - Ember.run(function() {
41 - reject(jqXHR);
42 - });
43 43   });
44 - });
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 };
79 + },
64 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);
81 + deleteRecord: function(store, type, record) {
82 + console.log("deleteRecord");
83 + var recordArrays = store.recordArrayManager.recordArraysForRecord(record);
84 + if (recordArrays && recordArrays.list && recordArrays.list[0]) {
85 + return this.saveAll(recordArrays.list[0].content);
86 + }
87 + return Ember.RSVP.resolve();
88 + },
89 +
90 + find: function(store, type, id) {
91 + console.log("find");
92 + return Ember.RSVP.resolve();
93 + },
94 +
95 + findAll: function(store, type, sinceToken) {
96 + console.log("findAll");
97 + var query = { since: sinceToken };
98 +
99 + return new Ember.RSVP.Promise(function(resolve, reject) {
100 + var url = "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
101 + XWiki.currentSpace + "." + XWiki.currentPage +
102 + "&xpage=plain&outputSyntax=plain";
103 + console.log("Finding all records, URL:", url);
104 +
105 + jQuery.getJSON(url, query).then(function(data) {
106 + console.log("FindAll success:", data);
107 + Ember.run(function() {
108 + resolve(data);
109 + });
110 + }, function(jqXHR) {
111 + console.error("FindAll error:", jqXHR);
112 + Ember.run(function() {
113 + reject(jqXHR);
114 + });
74 74   });
75 - }, function(jqXHR) {
76 - Ember.run(function() {
77 - reject(jqXHR);
78 - });
79 79   });
80 - });
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) };
117 + },
94 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);
119 + updateRecord: function(store, type, record) {
120 + console.log("updateRecord");
121 + var recordArrays = store.recordArrayManager.recordArraysForRecord(record);
122 + if (recordArrays && recordArrays.list && recordArrays.list[0]) {
123 + return this.saveAll(recordArrays.list[0].content);
124 + }
125 + return Ember.RSVP.resolve();
126 + },
127 +
128 + saveAll: function(alldata) {
129 + console.log("saveAll");
130 + var query = { save: "1", content: JSON.stringify(alldata) };
131 +
132 + return new Ember.RSVP.Promise(function(resolve, reject) {
133 + var currentPage = XWiki.currentSpace + "." + XWiki.currentPage;
134 + var url = "${xwiki.getURL('TodoLists.TodoListsService')}?page=" +
135 + currentPage + "&xpage=plain&outputSyntax=plain";
136 + console.log("Saving all records, URL:", url, "Page:", currentPage);
137 +
138 + jQuery.getJSON(url, query).then(function(data) {
139 + console.log("SaveAll success:", data);
140 + Ember.run(function() {
141 + resolve(data);
142 + });
143 + }, function(jqXHR) {
144 + console.error("SaveAll error:", jqXHR);
145 + Ember.run(function() {
146 + reject(jqXHR);
147 + });
104 104   });
105 - }, function(jqXHR) {
106 - Ember.run(function() {
107 - reject(jqXHR);
108 - });
109 109   });
150 + }
151 + });
152 +
153 + // Routing
154 + Todos.Router.map(function() {
155 + this.resource('todos', { path: '' }, function() {
156 + this.route('active');
157 + this.route('completed');
110 110   });
111 - }
112 - });
159 + });
113 113  
114 - // Register the adapter
115 - Todos.ApplicationAdapter.reopen({
116 - namespace: 'api'
117 - });
161 + Todos.TodosRoute = Ember.Route.extend({
162 + model: function() {
163 + return this.store.find('todo');
164 + }
165 + });
118 118  
119 - // Routing
120 - Todos.Router.map(function() {
121 - this.resource('todos', { path: '' }, function() {
122 - this.route('active');
123 - this.route('completed');
167 + Todos.TodosIndexRoute = Ember.Route.extend({
168 + model: function() {
169 + return this.modelFor('todos');
170 + }
124 124   });
125 - });
126 126  
127 - Todos.TodosRoute = Ember.Route.extend({
128 - model: function() {
129 - return this.store.find('todo');
130 - }
131 - });
173 + Todos.TodosActiveRoute = Ember.Route.extend({
174 + model: function() {
175 + return this.store.filter('todo', function(todo) {
176 + return !todo.get('isCompleted');
177 + });
178 + },
179 + renderTemplate: function(controller) {
180 + this.render('todos/index', { controller: controller });
181 + }
182 + });
132 132  
133 - Todos.TodosIndexRoute = Ember.Route.extend({
134 - model: function() {
135 - return this.modelFor('todos');
136 - }
137 - });
184 + Todos.TodosCompletedRoute = Ember.Route.extend({
185 + model: function() {
186 + return this.store.filter('todo', function(todo) {
187 + return todo.get('isCompleted');
188 + });
189 + },
190 + renderTemplate: function(controller) {
191 + this.render('todos/index', { controller: controller });
192 + }
193 + });
138 138  
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 - });
195 + // Data model
196 + Todos.Todo = DS.Model.extend({
197 + title: DS.attr('string'),
198 + priority: DS.attr('string'),
199 + assignee: DS.attr('string'),
200 + isCompleted: DS.attr('boolean')
201 + });
149 149  
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 - });
203 + // Controller
204 + Todos.TodoController = Ember.ObjectController.extend({
205 + actions: {
206 + editTodo: function() {
207 + this.set('isEditing', true);
208 + },
209 + acceptChanges: function() {
210 + this.set('isEditing', false);
160 160  
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 - });
168 -
169 - // Controller
170 - Todos.TodoController = Ember.ObjectController.extend({
171 - actions: {
172 - editTodo: function() {
173 - this.set('isEditing', true);
212 + if (Ember.isEmpty(this.get('model.title'))) {
213 + this.send('removeTodo');
214 + } else {
215 + this.get('model').save();
216 + }
217 + },
218 + removeTodo: function() {
219 + var todo = this.get('model');
220 + todo.deleteRecord();
221 + todo.save();
222 + }
174 174   },
175 - acceptChanges: function() {
176 - this.set('isEditing', false);
177 177  
178 - if (Ember.isEmpty(this.get('model.title'))) {
179 - this.send('removeTodo');
225 + isEditing: false,
226 +
227 + isCompleted: function(key, value) {
228 + var model = this.get('model');
229 +
230 + if (value === undefined) {
231 + // Property being used as a getter
232 + return model.get('isCompleted');
180 180   } else {
181 - this.get('model').save();
234 + // Property being used as setter
235 + model.set('isCompleted', value);
236 + model.save();
237 + return value;
182 182   }
183 - },
184 - removeTodo: function() {
185 - var todo = this.get('model');
186 - todo.deleteRecord();
187 - todo.save();
188 - }
189 - },
239 + }.property('model.isCompleted')
240 + });
190 190  
191 - isEditing: false,
242 + Todos.TodosController = Ember.ArrayController.extend({
243 + actions: {
244 + createTodo: function() {
245 + // Get the todo title set by the "New Todo" text field
246 + var title = this.get('newTitle');
247 + if (!title || !title.trim()) { return; }
192 192  
193 - isCompleted: function(key, value) {
194 - var model = this.get('model');
249 + console.log("Creating new todo with title:", title);
195 195  
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 - });
251 + // Create the new Todo model
252 + var todo = this.store.createRecord('todo', {
253 + title: title,
254 + priority: "P3",
255 + assignee: "all",
256 + isCompleted: false
257 + });
207 207  
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; }
259 + // Clear the "New Todo" text field
260 + this.set('newTitle', '');
214 214  
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 - });
262 + // Save the new model
263 + todo.save().then(function(savedTodo) {
264 + console.log("Todo saved successfully:", savedTodo);
265 + // Force a refresh of the list after saving
266 + Ember.run.later(function() {
267 + console.log("Refreshing todo list");
268 + Todos.store.find('todo');
269 + }, 100);
270 + }, function(error) {
271 + console.error("Failed to save todo:", error);
272 + });
273 + },
274 +
275 + clearCompleted: function() {
276 + var completed = this.filter(function(todo) {
277 + return todo.get('isCompleted');
278 + });
279 +
280 + completed.forEach(function(todo) {
281 + todo.deleteRecord();
282 + todo.save();
283 + });
284 + }
285 + },
222 222  
223 - // Clear the "New Todo" text field
224 - this.set('newTitle', '');
287 + remaining: function() {
288 + return this.filter(function(todo) {
289 + return !todo.get('isCompleted');
290 + }).get('length');
291 + }.property('@each.isCompleted'),
225 225  
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 - },
293 + inflection: function() {
294 + var remaining = this.get('remaining');
295 + return remaining === 1 ? 'item' : 'items';
296 + }.property('remaining'),
234 234  
235 - clearCompleted: function() {
236 - var completed = this.filter(function(todo) {
298 + hasCompleted: function() {
299 + return this.get('completed') > 0;
300 + }.property('completed'),
301 +
302 + completed: function() {
303 + return this.filter(function(todo) {
237 237   return todo.get('isCompleted');
238 - });
239 -
240 - completed.forEach(function(todo) {
241 - todo.deleteRecord();
242 - todo.save();
243 - });
244 - }
245 - },
305 + }).get('length');
306 + }.property('@each.isCompleted'),
246 246  
247 - remaining: function() {
248 - return this.filter(function(todo) {
249 - return !todo.get('isCompleted');
250 - }).get('length');
251 - }.property('@each.isCompleted'),
308 + allAreDone: function(key, value) {
309 + if (value === undefined) {
310 + return this.get('length') > 0 && this.every(function(todo) {
311 + return todo.get('isCompleted');
312 + });
313 + } else {
314 + this.forEach(function(todo) {
315 + todo.set('isCompleted', value);
316 + todo.save();
317 + });
318 + return value;
319 + }
320 + }.property('@each.isCompleted')
321 + });
252 252  
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'),
261 -
262 - completed: function() {
263 - return this.filter(function(todo) {
264 - return todo.get('isCompleted');
265 - }).get('length');
266 - }.property('@each.isCompleted'),
267 -
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;
323 + // Editing
324 + Todos.EditTodoView = Ember.TextField.extend({
325 + didInsertElement: function() {
326 + this.$().focus();
279 279   }
280 - }.property('@each.isCompleted')
281 - });
328 + });
282 282  
283 - // Editing
284 - Todos.EditTodoView = Ember.TextField.extend({
285 - didInsertElement: function() {
286 - this.$().focus();
287 - }
288 - });
289 -
290 - Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
330 + Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
331 + }
291 291  });
292 292