Merge lp:~urbanape/bindwood/migrate-old-user into lp:bindwood

Proposed by Chad Miller
Status: Merged
Approved by: Guillermo Gonzalez
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~urbanape/bindwood/migrate-old-user
Merge into: lp:bindwood
Diff against target: 1159 lines (+504/-206)
9 files modified
chrome.manifest (+1/-0)
content/bindwood.jsm (+457/-197)
content/browserOverlay.xul (+2/-7)
content/couch.jsm (+10/-0)
content/first-time.html (+10/-0)
content/migrate-old-bookmarks.html (+10/-0)
content/oauth.jsm (+2/-0)
content/subsequent-client-first-time-sync.html (+10/-0)
install.rdf (+2/-2)
To merge this branch: bzr merge lp:~urbanape/bindwood/migrate-old-user
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Tim Cole (community) Approve
Review via email: mp+18406@code.launchpad.net

Commit message

Provide a migration path for existing users of Bindwood to update their records.

Provide a ... progress indicator in the pop-up windows explaining what's going on.

Change the revision number, since this is a big change.

To post a comment you must log in.
Revision history for this message
Tim Cole (tcole) :
review: Approve
Revision history for this message
Guillermo Gonzalez (verterok) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'chrome.manifest'
2--- chrome.manifest 2009-07-14 14:09:22 +0000
3+++ chrome.manifest 2010-02-01 20:31:10 +0000
4@@ -1,3 +1,4 @@
5 content bindwood content/
6+resource bindwood content/
7 locale bindwood en locale/en/
8 overlay chrome://browser/content/browser.xul chrome://bindwood/content/browserOverlay.xul
9
10=== renamed file 'content/bindwood.js' => 'content/bindwood.jsm'
11--- content/bindwood.js 2010-01-22 17:29:33 +0000
12+++ content/bindwood.jsm 2010-02-01 20:31:10 +0000
13@@ -16,38 +16,53 @@
14 /* Lots and lots of debugging information */
15
16 Components.utils.import("resource://gre/modules/utils.js");
17+Components.utils.import("resource://bindwood/couch.jsm");
18+
19+var EXPORTED_SYMBOLS = ["Bindwood"];
20+
21+var Cc = Components.classes;
22+var Ci = Components.interfaces;
23+
24+var bookmarksService = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]
25+ .getService(Ci.nsINavBookmarksService);
26+var livemarkService = Cc["@mozilla.org/browser/livemark-service;2"]
27+ .getService(Ci.nsILivemarkService);
28+var uuidService = Cc["@mozilla.org/uuid-generator;1"]
29+ .getService(Ci.nsIUUIDGenerator);
30+var annotationService = Cc["@mozilla.org/browser/annotation-service;1"]
31+ .getService(Ci.nsIAnnotationService);
32+var consoleService = Cc["@mozilla.org/consoleservice;1"]
33+ .getService(Ci.nsIConsoleService);
34+var historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
35+ .getService(Ci.nsINavHistoryService);
36+var ioService = Cc["@mozilla.org/network/io-service;1"]
37+ .getService(Ci.nsIIOService);
38+var envService = Cc["@mozilla.org/process/environment;1"]
39+ .getService(Ci.nsIEnvironment);
40+var directoryService = Cc["@mozilla.org/file/directory_service;1"]
41+ .getService(Ci.nsIProperties);
42+var windowService = Cc["@mozilla.org/embedcomp/window-watcher;1"]
43+ .getService(Ci.nsIWindowWatcher);
44+// Technically, a branch, rather than the actual service, but
45+// consistency wins, I think
46+var prefsService = Cc["@mozilla.org/preferences-service;1"]
47+ .getService(Ci.nsIPrefService).getBranch("bindwood.");
48
49 var Bindwood = {
50- bookmarksService: Cc["@mozilla.org/browser/nav-bookmarks-service;1"]
51- .getService(Ci.nsINavBookmarksService),
52- livemarkService: Cc["@mozilla.org/browser/livemark-service;2"]
53- .getService(Ci.nsILivemarkService),
54- uuidService: Cc["@mozilla.org/uuid-generator;1"]
55- .getService(Ci.nsIUUIDGenerator),
56- annotationService: Cc["@mozilla.org/browser/annotation-service;1"]
57- .getService(Ci.nsIAnnotationService),
58- consoleService: Cc["@mozilla.org/consoleservice;1"]
59- .getService(Ci.nsIConsoleService),
60- historyService: Cc["@mozilla.org/browser/nav-history-service;1"]
61- .getService(Ci.nsINavHistoryService),
62- ioService: Cc["@mozilla.org/network/io-service;1"]
63- .getService(Ci.nsIIOService),
64- envService: Cc["@mozilla.org/process/environment;1"]
65- .getService(Ci.nsIEnvironment),
66- directoryService: Cc["@mozilla.org/file/directory_service;1"]
67- .getService(Ci.nsIProperties),
68- windowService: Cc["@mozilla.org/appshell/window-mediator;1"]
69- .getService(Ci.nsIWindowMediator),
70- // Technically, a branch, rather than the actual service, but
71- // consistency wins, I think
72- prefsService: Cc["@mozilla.org/preferences-service;1"]
73- .getService(Ci.nsIPrefService).getBranch("bindwood."),
74+
75+ pull_changes_timer: Cc["@mozilla.org/timer;1"]
76+ .createInstance(Ci.nsITimer),
77+ status_timer: Cc["@mozilla.org/timer;1"]
78+ .createInstance(Ci.nsITimer),
79+
80+ SCHEMA_VERSION: 1,
81
82 TYPE_BOOKMARK: "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark",
83 TYPE_FOLDER: "http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder",
84 TYPE_FEED: "http://www.freedesktop.org/wiki/Specifications/desktopcouch/feed",
85 TYPE_SEPARATOR: "http://www.freedesktop.org/wiki/Specifications/desktopcouch/separator",
86
87+ running: false,
88 push: 'ENABLED', // Start off enabled
89 annotationKey: "bindwood/uuid",
90 uuidItemIdMap: {},
91@@ -58,15 +73,21 @@
92 // Debugging/Console Behavior
93 writeMessage: function(aMessage) {
94 // convenience method for logging. Way better than alert()s.
95- if (Bindwood.prefsService.getBoolPref("debug")) {
96- Bindwood.consoleService.logStringMessage(
97+ var debug;
98+ try {
99+ debug = prefsService.getBoolPref('debug');
100+ } catch(e) {
101+ debug = false;
102+ }
103+ if (debug) {
104+ consoleService.logStringMessage(
105 "Bindwood: " + aMessage);
106 }
107 },
108
109 writeError: function(aMessage, e) {
110 // This should fire whether we're in DEBUG or not
111- Bindwood.consoleService.logStringMessage(
112+ consoleService.logStringMessage(
113 "Bindwood: " + aMessage +
114 " message: '" + e.message +
115 "', reason: '" + e.reason +
116@@ -116,15 +137,20 @@
117 // http://forums.mozillazine.org/viewtopic.php?f=19&t=657911&start=0
118 // It ensures that we're only running that code on the first window.
119
120- Bindwood.currentProfile = Bindwood.extractProfileName(
121- Bindwood.directoryService.get('ProfD', Ci.nsIFile).path);
122-
123- if(Bindwood.windowService.getEnumerator("").getNext() == window) {
124- Bindwood.getCouchEnvironment(Bindwood.setUpEnvironment);
125+ if (!Bindwood.running) {
126+ Bindwood.writeMessage("Getting started in init.");
127+ Bindwood.currentProfile = Bindwood.extractProfileName(
128+ directoryService.get('ProfD', Ci.nsIFile).path);
129+
130+ Bindwood.writeMessage("Got our profile: " + Bindwood.currentProfile);
131+
132+ Bindwood.running = true;
133+ bookmarksService.addObserver(Bindwood.Observer, false);
134+ Bindwood.getCouchEnvironment();
135 }
136 },
137
138- getCouchEnvironment: function(continueFunction) {
139+ getCouchEnvironment: function() {
140 // find the desktop Couch port number by making a D-Bus call
141 // we call D-Bus by shelling out to a bash script which calls
142 // it for us, and writes the port number into a temp file
143@@ -152,7 +178,7 @@
144
145 // create an nsIProcess2 to execute this bash script
146 var process = Cc["@mozilla.org/process/util;1"]
147- .createInstance(Ci.nsIProcess2);
148+ .createInstance(Ci.nsIProcess2 || Ci.nsIProcess);
149 process.init(nsifile);
150
151 // Run the process, passing the tmpfile path
152@@ -199,10 +225,12 @@
153 }
154
155 if (shouldProceed && environment) {
156- continueFunction(environment);
157+ Bindwood.writeMessage("Got our environment, proceeding.");
158+ Bindwood.setUpEnvironment(environment);
159 } else {
160 // Unregister our observer for bookmark events; we're done
161- Bindwood.bookmarksService.removeObserver(Bindwood.Observer);
162+ Bindwood.writeMessage("No environment. Unregistering observer.");
163+ bookmarksService.removeObserver(Bindwood.Observer);
164 }
165 }
166 });
167@@ -233,10 +261,11 @@
168 };
169
170 var db_name = 'bookmarks';
171- if (Bindwood.envService.exists('BINDWOOD_DB')) {
172- db_name = Bindwood.envService.get('BINDWOOD_DB');
173+ if (envService.exists('BINDWOOD_DB')) {
174+ db_name = envService.get('BINDWOOD_DB');
175 }
176
177+ Bindwood.writeMessage("Got our db name: " + db_name);
178 Bindwood.couch = new CouchDB(db_name);
179
180 try {
181@@ -251,7 +280,7 @@
182 getLastSequence: function() {
183 var seq;
184 try {
185- seq = Bindwood.prefsService.getIntPref('last_seq');
186+ seq = prefsService.getIntPref('last_seq');
187 } catch(e) {
188 seq = 0;
189 }
190@@ -259,14 +288,14 @@
191 },
192
193 setLastSequence: function(seq) {
194- Bindwood.prefsService.setIntPref('last_seq', seq);
195+ prefsService.setIntPref('last_seq', seq);
196 return seq;
197 },
198
199 getLatestModified: function() {
200 var mod;
201 try {
202- mod = Number(Bindwood.prefsService.getCharPref('latest_modified'));
203+ mod = Number(prefsService.getCharPref('latest_modified'));
204 } catch(e) {
205 mod = 0;
206 }
207@@ -274,7 +303,7 @@
208 },
209
210 setLatestModified: function(mod) {
211- Bindwood.prefsService.setCharPref(
212+ prefsService.setCharPref(
213 'latest_modified', Number(mod).toString());
214 return mod;
215 },
216@@ -293,60 +322,63 @@
217 Bindwood.writeMessage("Ensuring our scratch folder exists");
218 Bindwood.scratch_folder = Bindwood.ensureLocalScratchFolder();
219
220+ var profile_exists = Bindwood.profileExists();
221+ Bindwood.writeMessage("Determined whether profile already exists: " + profile_exists);
222+
223 var HAVE_LAST_SEQ = Bindwood.last_seq ? 1 : 0; // 0 or 1
224- var HAVE_PROFILE_ROOT = Bindwood.profileExists(); // 0 or 2
225+ var HAVE_PROFILE_ROOT = profile_exists ? 2 : 0; // 0 or 2
226+
227+ var additional = []; // for case 0 and 3, nothing else needs to be done
228
229 switch(HAVE_LAST_SEQ | HAVE_PROFILE_ROOT) {
230 case 0:
231 // Neither the profile root exists, nor do we have a last_seq. Ergo, we are a first
232 // time user. Proceed normally.
233
234- // Bindwood.display_first_sync_page();
235+ Bindwood.statusWindow = windowService.openWindow(null, "chrome://bindwood/content/first-time.html",
236+ "firstTime", "chrome,centerscreen,outerwidth=640,outerheight=480", null);
237+ Bindwood.status_timer.initWithCallback(
238+ { notify: function(timer) {
239+ var div = Bindwood.statusWindow.document.getElementById('status');
240+ var dots = div.innerHTML;
241+ div.innerHTML = dots + ".";
242+ } }, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
243 break;
244 case 1:
245 // We have a last_seq, but the profile root does not exist. Ergo, we are an old user
246 // and must migrate to the new way of doing things.
247
248- /* Migration strategy:
249-
250- Pull all records from Couch, and for each:
251-
252- - get the uuid off the bookmark.
253-
254- - look up itemId by uuid
255-
256- - annotate the itemId with the document's _id
257-
258- - delete the uuid field off the record
259-
260- */
261-
262- // Bindwood.display_migration_sync_page();
263+ Bindwood.statusWindow = windowService.openWindow(null, "chrome://bindwood/content/migrate-old-bookmarks.html",
264+ "migrate", "chrome,centerscreen,outerwidth=640,outerheight=480", null);
265+ Bindwood.status_timer.initWithCallback(
266+ { notify: function(timer) {
267+ var div = Bindwood.statusWindow.document.getElementById('status');
268+ var dots = div.innerHTML;
269+ div.innerHTML = dots + ".";
270+ } }, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
271+ var additional = Bindwood.migrateOlderBookmarkRecords();
272+
273 break;
274 case 2:
275 // We have no last_seq, but the profile root exists. Ergo, we are starting up a
276 // subsequent client. We must make our local bookmarks look like remote, and ensure
277 // that any unaccounted for local bookmarks are sent to CouchDB.
278
279- // Bindwood.display_subsequent_client_sync_page();
280- // Show a helpful page explaining what's happening, so the user doesn't feel
281- // something is broken.
282-
283- // Bindwood.move_local_records_to_scratch();
284- // Move all local records (folders, bookmarks, &c) to a temporary folder
285-
286- // Bindwood.situate_remote_records();
287- // Pull all remote records, putting them in place according to pullRecords()
288-
289- // Bindwood.situate_local_records();
290- // Iterate through our tmp tree, moving back bookmarks that aren't present.
291-
292- // Bindwood.remove_tmp_folder();
293- // Anything left in the tmp folder has already been accounted for.
294+ Bindwood.statusWindow = windowService.openWindow(null, "chrome://bindwood/content/subsequent-client-first-time-sync.html",
295+ "subsequentClient", "chrome,centerscreen,outerwidth=640,outerheight=480", null);
296+ Bindwood.status_timer.initWithCallback(
297+ { notify: function(timer) {
298+ var div = Bindwood.statusWindow.document.getElementById('status');
299+ var dots = div.innerHTML;
300+ div.innerHTML = dots + ".";
301+ } }, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
302+ var additional = Bindwood.handleSubsequentClientFirstTimeSync();
303+
304 break;
305 case 3: // Should this just be default?
306 // We have a last_seq, and the profile root exists. Ergo, we are a normally operating
307 // client. Proceed normally.
308+
309 break;
310 default:
311 break;
312@@ -358,7 +390,24 @@
313 Bindwood.noteStartTime('Pushing records');
314 Bindwood.pushLatestRecords();
315 Bindwood.noteEndTime('Pushing records');
316- Bindwood.pullChanges();
317+
318+ for (var i = 0; i < additional.length; i++) {
319+ try {
320+ var response = Bindwood.couch.save(additional[i]);
321+ // We can avoid having to process this revision when we pull it later
322+ Bindwood.seen_revisions[response.rev] = true;
323+ } catch(e) {
324+ Bindwood.writeError(
325+ "Problem saving record to CouchDB; record is " +
326+ JSON.stringify(additional[i]) + ": ", e);
327+ }
328+ }
329+
330+ try {
331+ Bindwood.pullChanges();
332+ } catch(e) {
333+ Bindwood.writeError("Problem pulling changes!", e);
334+ }
335 },
336
337 ensureDatabase: function() {
338@@ -380,13 +429,13 @@
339 _id: "_design/bookmarks",
340 views: {
341 profile: {
342- map: "function(doc) { var scheme = doc.uri.split(':',1)[0]; var uri; if (scheme == 'http' || scheme == 'https') {uri = doc.uri.split('/')[2];if (uri.length < 30) { uri += '/' + doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';}} else {uri = scheme + ' URL';}if ((!doc.deleted) && (doc.application_annotations.Firefox.profile)) {emit(doc.application_annotations.Firefox.profile, [doc.title, uri]);}}"
343+ map: "function(doc) { var scheme = doc.uri.split(':',1)[0]; var uri; if (scheme == 'http' || scheme == 'https') {uri = doc.uri.split('/')[2];if (uri.length < 30) { uri += '/' + doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';}} else {uri = scheme + ' URL';}if ((!(doc.application_annotations && doc.application_annotations['Ubuntu One'] && doc.application_annotations['Ubuntu One'].private_application_annotations && doc.application_annotations['Ubuntu One'].private_application_annotations.deleted)) && (doc.application_annotations.Firefox.profile)) {emit(doc.application_annotations.Firefox.profile, [doc.title, uri]);}}"
344 },
345 live_bookmarks: {
346- map: "function(doc) { var scheme = doc.uri.split(':',1)[0]; var uri; if (scheme == 'http' || scheme == 'https') {uri = doc.uri.split('/')[2];if (uri.length < 30) { uri += '/' + doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';}} else {uri = scheme + ' URL';}if (!doc.deleted) {emit(doc.title, uri);}}"
347+ map: "function(doc) { var scheme = doc.uri.split(':',1)[0]; var uri; if (scheme == 'http' || scheme == 'https') {uri = doc.uri.split('/')[2];if (uri.length < 30) { uri += '/' + doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';}} else {uri = scheme + ' URL';}if (!(doc.application_annotations && doc.application_annotations['Ubuntu One'] && doc.application_annotations['Ubuntu One'].private_application_annotations && doc.application_annotations['Ubuntu One'].private_application_annotations.deleted)) {emit(doc.title, uri);}}"
348 },
349 deleted_bookmarks: {
350- map: "function(doc) { if (doc.deleted) { emit (doc.title, doc.uri); } }"
351+ map: "function(doc) { if (doc.application_annotations && doc.application_annotations['Ubuntu One'] && doc.application_annotations['Ubuntu One'].private_application_annotations && doc.application_annotations['Ubuntu One'].private_application_annotations.deleted) { emit (doc.title, doc.uri); } }"
352 }
353 }
354 };
355@@ -412,7 +461,7 @@
356 // we get an updated folder record with a record situated properly
357 // in its children field, we need a place to temporarily store
358 // records from Couch. This is that place.
359- var folder = Bindwood.bookmarksService.unfiledBookmarksFolder;
360+ var folder = bookmarksService.unfiledBookmarksFolder;
361 var rootNode = Bindwood.getFolderRoot(folder);
362 rootNode.containerOpen = true;
363 for (var i=0; i<rootNode.childCount; i++) {
364@@ -424,7 +473,7 @@
365 }
366 rootNode.containerOpen = false;
367
368- var folderId = Bindwood.bookmarksService.createFolder(
369+ var folderId = bookmarksService.createFolder(
370 folder, 'Desktop Couch Scratch', -1);
371 return folderId;
372 },
373@@ -432,29 +481,194 @@
374 profileExists: function() {
375 // Check to see if the current profile's manifest exists in
376 // the database.
377- try {
378- Bindwood.couch.open('root_' + Bindwood.currentProfile);
379- } catch(e) {
380- if (e.error == 'not_found') {
381- return 0;
382- }
383- }
384- return 2;
385+ var root = Bindwood.couch.open('root_' + Bindwood.currentProfile);
386+ if (root) {
387+ return 2;
388+ }
389+ return 0;
390+ },
391+
392+ migrateOlderBookmarkRecords: function() {
393+ Bindwood.writeMessage("We're an older client. Let's migrate the remote records and re-sync.");
394+
395+ var additional = [];
396+ var all_docs = Bindwood.couch.allDocs();
397+ var rows = all_docs.rows;
398+
399+ // Pull all records from Couch, and for each:
400+
401+ for (var i = 0; i < rows.length; i++) {
402+ var row = rows[i];
403+ var id = row.id;
404+ var doc = Bindwood.couch.open(id);
405+
406+ if (!Bindwood.recordInCurrentProfile(doc)) {
407+ Bindwood.writeMessage("Record isn't in our current profile. Skipping...");
408+ continue;
409+ }
410+
411+ // get the uuid off the bookmark.
412+ var old_uuid = doc.application_annotations.Firefox.uuid;
413+ // look up itemId by uuid
414+ var itemId = Bindwood.itemIdForUUID(old_uuid);
415+ // annotate the itemId with the document's _id
416+ Bindwood.annotateItemWithUUID(itemId, id);
417+ // delete the uuid field off the record
418+ delete doc.application_annotations.Firefox.uuid;
419+ // delete the folder field off the record
420+ delete doc.application_annotations.Firefox.folder;
421+
422+ if (doc.deleted) {
423+ // swap .deleted for .application_annotations['Ubuntu On'].private_application_annotations.deleted
424+ if (!doc.application_annotations) {
425+ doc.application_annotations = {};
426+ }
427+ if (!doc.application_annotations['Ubuntu One']) {
428+ doc.application_annotations['Ubuntu One'] = {};
429+ }
430+ if (!doc.application_annotations['Ubuntu One'].private_application_annotations) {
431+ doc.application_annotations['Ubuntu One'].private_application_annotations = {};
432+ }
433+ doc.application_annotations['Ubuntu One'].private_application_annotations.deleted = true;
434+ delete doc.deleted;
435+ }
436+
437+ // update the document's record_type_version
438+ doc.record_type_version = 1;
439+
440+ // add to additional
441+ additional.push(doc);
442+ }
443+
444+ return additional;
445+ },
446+
447+ handleSubsequentClientFirstTimeSync: function() {
448+ Bindwood.writeMessage("We're a subsequent client. Let's merge the remote and the local.");
449+
450+ // get the remote root from Couch.
451+ var remote_root = Bindwood.couch.open('root_' + Bindwood.currentProfile);
452+ var local_roots = [bookmarksService.toolbarFolder,
453+ bookmarksService.bookmarksMenuFolder,
454+ bookmarksService.unfiledBookmarksFolder];
455+
456+ var records_needing_pushing = [];
457+
458+ for (var i = 0; i < local_roots.length; i++) {
459+ Bindwood.syncRemoteAndLocal(remote_root.children[i], local_roots[i], records_needing_pushing);
460+ }
461+
462+ return records_needing_pushing;
463+ },
464+
465+ syncRemoteAndLocal: function(remote_folder, local_folder, accum) {
466+ Bindwood.writeMessage("Syncing remote folder: " + remote_folder + " to local folder: " + local_folder);
467+ var local_needs_pushing = false;
468+
469+ // get the local folder's root, and open it for iteration
470+ var local = Bindwood.getFolderRoot(local_folder);
471+ local.containerOpen = true;
472+
473+ // walk the remote folder's children, and ask for each one:
474+ var remote = Bindwood.couch.open(remote_folder);
475+ var remote_children = remote.children;
476+ Bindwood.writeMessage("Beginning to walk remote children");
477+ for (var i = 0; i < remote_children.length; i++) {
478+ var remote_child = Bindwood.couch.open(remote_children[i]);
479+ var local_child;
480+ var found_local = false;
481+
482+ Bindwood.writeMessage("Looking for record type: " + remote_child.record_type +
483+ " identified by " + remote_child.record_type != Bindwood.TYPE_SEPARATOR ? remote_child.title : "being a separator");
484+
485+ // does my local toolbarFolder have this child anywhere in it?
486+ for (var j = 0; j < local.childCount; j++) {
487+ local_child = local.getChild(j);
488+
489+ // Check to see whether we're testing a separator (which has no title)
490+ // or whether we're testing the same type and title
491+ if ((Bindwood.sameType(local_child, remote_child) &&
492+ remote_child.record_type == Bindwood.TYPE_SEPARATOR) ||
493+ (Bindwood.sameType(local_child, remote_child) &&
494+ Bindwood.sameTitle(local_child, remote_child))) {
495+ found_local = true;
496+ Bindwood.writeMessage("Found the record.");
497+ Bindwood.annotateItemWithUUID(local_child.itemId, remote_child._id);
498+ // If we're dealing with a folder, we'll process it recursively,
499+ // and the only other thing we'd impose would be the title,
500+ // which already matches..
501+ if (remote_child.record_type != Bindwood.TYPE_FOLDER) {
502+ Bindwood.processCouchRecord(remote_child, null, null);
503+ }
504+ if (i != j) { // if yes, but in a different location
505+ // Move the local to the proper index within the same folder.
506+ Bindwood.writeMessage("Record isn't in the same location as remote, moving it.");
507+ Bindwood.makeLocalChangeOnly(
508+ function() {
509+ bookmarksService.moveItem(
510+ local_child.itemId, local_folder, i);
511+ }
512+ );
513+ local_needs_pushing = true;
514+ }
515+ }
516+ }
517+
518+ if (!found_local) {
519+ // Add the record locally, annotate it, and place it in the correct index.
520+ // Add current local folder as one that needs to be pushed back (changing its children)
521+
522+ Bindwood.writeMessage("Remote record doesn't exist here, recreating it in " + local_folder + " at index " + i + ".");
523+ Bindwood.processCouchRecord(remote_child, local_folder, i);
524+ local_needs_pushing = true;
525+ }
526+
527+ // is the child a folder?
528+ if (remote_child.record_type == Bindwood.TYPE_FOLDER) {
529+ // Recurse into the function with remote id and local folder id
530+ Bindwood.syncRemoteAndLocal(remote_child._id, local_child.itemId, accum);
531+ }
532+ }
533+
534+ local.containerOpen = false;
535+
536+ if (local_needs_pushing) {
537+ accum.push(Bindwood.couchRecordForItemId(local_folder));
538+ }
539+ },
540+
541+ sameType: function(localNode, remoteDoc) {
542+ switch(remoteDoc.record_type) {
543+ case Bindwood.TYPE_BOOKMARK:
544+ return PlacesUtils.nodeIsBookmark(localNode);
545+ case Bindwood.TYPE_FEED:
546+ return PlacesUtils.nodeIsLivemarkContainer(localNode);
547+ case Bindwood.TYPE_FOLDER:
548+ return PlacesUtils.nodeIsFolder(localNode);
549+ case Bindwood.TYPE_SEPARATOR:
550+ return PlacesUtils.nodeIsSeparator(localNode);
551+ default:
552+ return false;
553+ }
554+ },
555+
556+ sameTitle: function(localNode, remoteDoc) {
557+ return localNode.title == remoteDoc.title;
558 },
559
560 // Looking up records locally
561 annotateItemWithUUID: function(itemId, seed_uuid) {
562 var uuid = (seed_uuid ?
563 seed_uuid :
564- Bindwood.uuidService.generateUUID().toString());
565+ uuidService.generateUUID().toString());
566 Bindwood.writeMessage("UUID We came up with: " + uuid);
567 Bindwood.writeMessage("Annotating the item now.");
568- Bindwood.annotationService.setItemAnnotation(
569+ annotationService.setItemAnnotation(
570 itemId,
571 Bindwood.annotationKey,
572 uuid,
573 0,
574- Bindwood.annotationService.EXPIRE_NEVER);
575+ annotationService.EXPIRE_NEVER);
576 // Whenever we create a new UUID, stash it and the itemId in
577 // our local cache.
578 Bindwood.uuidItemIdMap[uuid] = itemId;
579@@ -467,11 +681,11 @@
580 var itemId = Bindwood.uuidItemIdMap[uuid];
581
582 if (!itemId) {
583- var items = Bindwood.annotationService.getItemsWithAnnotation(
584+ var items = annotationService.getItemsWithAnnotation(
585 Bindwood.annotationKey, {});
586 var num_items = items.length;
587 for (var i = 0; i < items.length; i++) {
588- if (Bindwood.annotationService.getItemAnnotation(
589+ if (annotationService.getItemAnnotation(
590 items[i], Bindwood.annotationKey) == uuid) {
591 Bindwood.uuidItemIdMap[uuid] = itemId = items[i];
592 break;
593@@ -490,7 +704,7 @@
594 // and return it.
595 var uuid;
596 try {
597- uuid = Bindwood.annotationService.getItemAnnotation(
598+ uuid = annotationService.getItemAnnotation(
599 itemId, Bindwood.annotationKey);
600 Bindwood.uuidItemIdMap[uuid] = itemId;
601 } catch(e) {
602@@ -505,14 +719,15 @@
603 },
604
605 couchRecordForItemId: function(itemId) {
606- var bs = Bindwood.bookmarksService;
607+ var bs = bookmarksService;
608
609 var uuid = Bindwood.uuidForItemId(itemId);
610 var profile = Bindwood.currentProfile;
611- var last_modified = Bindwood.bookmarksService.getItemLastModified(itemId);
612+ var last_modified = bookmarksService.getItemLastModified(itemId);
613
614 var record = {
615 "_id": uuid,
616+ record_type_version: Bindwood.SCHEMA_VERSION,
617 application_annotations: {
618 Firefox: {
619 profile: profile,
620@@ -532,10 +747,10 @@
621
622 // Firefox doesn't differentiate between regular folders
623 // and livemark folders. *sigh* So, we override it here
624- if (Bindwood.livemarkService.isLivemark(itemId)) {
625+ if (livemarkService.isLivemark(itemId)) {
626 record.record_type = Bindwood.TYPE_FEED;
627- record.site_uri = Bindwood.livemarkService.getSiteURI(itemId).spec;
628- record.feed_uri = Bindwood.livemarkService.getFeedURI(itemId).spec;
629+ record.site_uri = livemarkService.getSiteURI(itemId).spec;
630+ record.feed_uri = livemarkService.getFeedURI(itemId).spec;
631 } else {
632 record.record_type = Bindwood.TYPE_FOLDER;
633 record.children = [];
634@@ -560,10 +775,10 @@
635
636 // Back and forth
637 getFolderRoot: function(folder) {
638- var options = Bindwood.historyService.getNewQueryOptions();
639- var query = Bindwood.historyService.getNewQuery();
640+ var options = historyService.getNewQueryOptions();
641+ var query = historyService.getNewQuery();
642 query.setFolders([folder], 1);
643- var result = Bindwood.historyService.executeQuery(query, options);
644+ var result = historyService.executeQuery(query, options);
645 return result.root;
646 },
647
648@@ -608,9 +823,9 @@
649
650 generateManifest: function() {
651 // Fill up the Bindwood.manifest and initial push lists
652- var primaryFolders = [Bindwood.bookmarksService.toolbarFolder,
653- Bindwood.bookmarksService.bookmarksMenuFolder,
654- Bindwood.bookmarksService.unfiledBookmarksFolder];
655+ var primaryFolders = [bookmarksService.toolbarFolder,
656+ bookmarksService.bookmarksMenuFolder,
657+ bookmarksService.unfiledBookmarksFolder];
658
659 var profile_root = {
660 "_id": "root_" + Bindwood.currentProfile,
661@@ -695,11 +910,33 @@
662 },
663
664 pullChanges: function() {
665- Bindwood.pullRecords();
666+ var repeater = {
667+ notify: function(timer) {
668+ Bindwood.pullRecords();
669+ Bindwood.writeMessage(
670+ "Successful run, rescheduling ourself");
671+ }
672+ };
673+
674+ repeater.notify(); // Prime the pump, then schedule us out.
675
676 // reschedule ourself
677- Bindwood.writeMessage("Successful run, rescheduling ourself");
678- setTimeout(Bindwood.pullChanges, 30000);
679+ try {
680+ Bindwood.pull_changes_timer.initWithCallback(repeater, 30000, Ci.nsITimer.TYPE_REPEATING_SLACK);
681+ } catch(e) {
682+ Bindwood.writeError("Problem setting up repeater.", e);
683+ }
684+
685+ if (Bindwood.statusWindow) {
686+ Bindwood.reportDoneInWindow();
687+ }
688+ },
689+
690+ reportDoneInWindow: function() {
691+ Bindwood.status_timer.cancel();
692+ var div = Bindwood.statusWindow.document.getElementById('status');
693+ var dots = div.innerHTML;
694+ div.innerHTML = dots + ' Finished, you can close this window and proceed. Thanks for your patience.';
695 },
696
697 pullRecords: function() {
698@@ -770,35 +1007,7 @@
699 continue; // Don't bother continuing to process anything further in this revision
700 }
701
702- switch(record.record_type) {
703- case Bindwood.TYPE_BOOKMARK:
704- Bindwood.makeLocalChangeOnly(
705- function() {
706- Bindwood.processCouchBookmarkRevision(record);
707- });
708- break;
709- case Bindwood.TYPE_FOLDER:
710- Bindwood.makeLocalChangeOnly(
711- function() {
712- Bindwood.processCouchFolderRevision(record);
713- });
714- break;
715- case Bindwood.TYPE_FEED:
716- Bindwood.makeLocalChangeOnly(
717- function() {
718- Bindwood.processCouchFeedRevision(record);
719- });
720- break;
721- case Bindwood.TYPE_SEPARATOR:
722- Bindwood.makeLocalChangeOnly(
723- function() {
724- Bindwood.processCouchSeparatorRevision(record);
725- });
726- break;
727- default:
728- break;
729- }
730- // STOPPING HERE - Time to do per-type dispatch
731+ Bindwood.processCouchRecord(record, null, null);
732 }
733
734 Bindwood.last_seq = Bindwood.setLastSequence(results.last_seq);
735@@ -830,11 +1039,47 @@
736 // assume it's already gone.
737 var itemId = Bindwood.itemIdForUUID(record._id);
738 if (itemId) {
739- return Bindwood.bookmarksService.removeItem(itemId);
740- }
741- },
742-
743- processCouchBookmarkRevision: function(record) {
744+ return bookmarksService.removeItem(itemId);
745+ }
746+ },
747+
748+ processCouchRecord: function(record, aParent, aIndex) {
749+ var aParent = aParent ? aParent : Bindwood.scratch_folder;
750+ var aIndex = aIndex ? aIndex : -1;
751+
752+ Bindwood.writeMessage("Processing Couch Record: " + record + " placing it in " + aParent + " at location " + aIndex);
753+
754+ switch(record.record_type) {
755+ case Bindwood.TYPE_BOOKMARK:
756+ Bindwood.makeLocalChangeOnly(
757+ function() {
758+ Bindwood.processCouchBookmarkRevision(record, aParent, aIndex);
759+ });
760+ break;
761+ case Bindwood.TYPE_FOLDER:
762+ Bindwood.makeLocalChangeOnly(
763+ function() {
764+ Bindwood.processCouchFolderRevision(record, aParent, aIndex);
765+ });
766+ break;
767+ case Bindwood.TYPE_FEED:
768+ Bindwood.makeLocalChangeOnly(
769+ function() {
770+ Bindwood.processCouchFeedRevision(record, aParent, aIndex);
771+ });
772+ break;
773+ case Bindwood.TYPE_SEPARATOR:
774+ Bindwood.makeLocalChangeOnly(
775+ function() {
776+ Bindwood.processCouchSeparatorRevision(record, aParent, aIndex);
777+ });
778+ break;
779+ default:
780+ break;
781+ }
782+ },
783+
784+ processCouchBookmarkRevision: function(record, aParent, aIndex) {
785 // Could be an add or change revision. Delete was handled earlier.
786 // If it's an addition (we can't resolve its _id to be one of our itemIds),
787 // add it to the Desktop Couch folder in unfiled.
788@@ -842,22 +1087,22 @@
789 var itemId = Bindwood.itemIdForUUID(record._id);
790 if (itemId) {
791 // It's a change. Stamp everything remote on the local bookmark
792- Bindwood.bookmarksService.setItemTitle(itemId, record.title);
793- Bindwood.bookmarksService.changeBookmarkURI(itemId,
794- Bindwood.ioService.newURI(record.uri, null, null));
795+ bookmarksService.setItemTitle(itemId, record.title);
796+ bookmarksService.changeBookmarkURI(itemId,
797+ ioService.newURI(record.uri, null, null));
798 } else {
799 // It's an addition. Add a new bookmark to our scratch folder,
800 // annotate it, and we're done.
801- itemId = Bindwood.bookmarksService.insertBookmark(
802- Bindwood.scratch_folder,
803- Bindwood.ioService.newURI(record.uri, null, null),
804- -1,
805+ itemId = bookmarksService.insertBookmark(
806+ aParent,
807+ ioService.newURI(record.uri, null, null),
808+ aIndex,
809 record.title);
810 Bindwood.annotateItemWithUUID(itemId, record._id);
811 }
812 },
813
814- processCouchFolderRevision: function(record) {
815+ processCouchFolderRevision: function(record, aParent, aIndex) {
816 // Could be an add or change revision. Delete was handled earlier.
817 // If it's an addition (we can't resolve its _id to be one of our itemIds),
818 // add it to the Desktop Couch folder in unfiled.
819@@ -867,7 +1112,7 @@
820 // It's a change. Stamp remote title on the folder, and deal with any
821 // changed children.
822 Bindwood.noteStartTime('Shuffling folder children');
823- Bindwood.bookmarksService.setItemTitle(itemId, record.title);
824+ bookmarksService.setItemTitle(itemId, record.title);
825 // Iterate through our current folder children, and compare with remote.
826 // Move all local children to the scratch folder, then move them back
827 // in the order of the remote children.
828@@ -877,7 +1122,7 @@
829 var child = local_children[i];
830 var child_itemId = Bindwood.itemIdForUUID(child);
831 try {
832- Bindwood.bookmarksService.moveItem(child_itemId, Bindwood.scratch_folder, -1);
833+ bookmarksService.moveItem(child_itemId, Bindwood.scratch_folder, -1);
834 } catch(e) {
835 Bindwood.writeError("Problem moving item to scratch folder: " + JSON.stringify(e), e);
836 }
837@@ -887,7 +1132,7 @@
838 var new_child = record.children[j];
839 var new_child_itemId = Bindwood.itemIdForUUID(new_child);
840 try {
841- Bindwood.bookmarksService.moveItem(new_child_itemId, itemId, -1);
842+ bookmarksService.moveItem(new_child_itemId, itemId, -1);
843 } catch(e) {
844 Bindwood.writeError("Problem moving item from scratch folder: " + JSON.stringify(e), e);
845 }
846@@ -896,15 +1141,15 @@
847 } else {
848 // It's an addition. Add a new bookmark to our scratch folder,
849 // annotate it, and we're done.
850- itemId = Bindwood.bookmarksService.createFolder(
851- Bindwood.scratch_folder,
852+ itemId = bookmarksService.createFolder(
853+ aParent,
854 record.title,
855- -1);
856+ aIndex);
857 Bindwood.annotateItemWithUUID(itemId, record._id);
858 }
859 },
860
861- processCouchFeedRevision: function(record) {
862+ processCouchFeedRevision: function(record, aParent, aIndex) {
863 // Could be an add or change revision. Delete was handled earlier.
864 // If it's an addition (we can't resolve its _id to be one of our itemIds),
865 // add it to the Desktop Couch folder in unfiled.
866@@ -912,26 +1157,25 @@
867 var itemId = Bindwood.itemIdForUUID(record._id);
868 if (itemId) {
869 // It's a change. Stamp everything remote on the local bookmark
870- Bindwood.bookmarksService.setItemTitle(itemId, record.title);
871- Bindwood.livemarkService.setSiteURI(itemId,
872- Bindwood.ioService.newURI(record.site_uri, null, null));
873- Bindwood.livemarkService.setFeedURI(itemId,
874- Bindwood.ioService.newURI(record.feed_uri, null, null));
875+ bookmarksService.setItemTitle(itemId, record.title);
876+ livemarkService.setSiteURI(itemId,
877+ ioService.newURI(record.site_uri, null, null));
878+ livemarkService.setFeedURI(itemId,
879+ ioService.newURI(record.feed_uri, null, null));
880 } else {
881 // It's an addition. Add a new bookmark to our scratch folder,
882 // annotate it, and we're done.
883- var newItemId = Bindwood.livemarkService.createLivemarkFolderOnly(
884- Bindwood.bookmarksService,
885- Bindwood.scratch_folder,
886+ var newItemId = livemarkService.createLivemark(
887+ aParent,
888 record.title,
889- Bindwood.ioService.newURI(record.site_uri, null, null),
890- Bindwood.ioService.newURI(record.feed_uri, null, null),
891- -1);
892+ ioService.newURI(record.site_uri, null, null),
893+ ioService.newURI(record.feed_uri, null, null),
894+ aIndex);
895 Bindwood.annotateItemWithUUID(newItemId, record._id);
896 }
897 },
898
899- processCouchSeparatorRevision: function(record) {
900+ processCouchSeparatorRevision: function(record, aParent, aIndex) {
901 // Should only be an add revision. There's nothing to change, and delete was
902 // handled earlier.
903 // If it's an addition (we can't resolve its _id to be one of our itemIds),
904@@ -942,9 +1186,9 @@
905 // There's nothing to change about a separator, so...
906 // It's an addition. Add a new bookmark to our scratch folder,
907 // annotate it, and we're done.
908- var newItemId = Bindwood.bookmarksService.insertSeparator(
909- Bindwood.scratch_folder,
910- -1);
911+ var newItemId = bookmarksService.insertSeparator(
912+ aParent,
913+ aIndex);
914 Bindwood.annotateItemWithUUID(newItemId, record._id);
915 }
916 },
917@@ -1003,9 +1247,9 @@
918 var parent;
919 while (parent != root) {
920 Bindwood.writeMessage("Looking for parent of " + itemId);
921- parent = Bindwood.bookmarksService.getFolderIdForItem(itemId);
922+ parent = bookmarksService.getFolderIdForItem(itemId);
923 if (parent != root &&
924- Bindwood.annotationService.itemHasAnnotation(
925+ annotationService.itemHasAnnotation(
926 parent, 'livemark/feedURI')) {
927 return false;
928 }
929@@ -1053,14 +1297,14 @@
930 }
931
932 Bindwood.setLatestModified(
933- Bindwood.bookmarksService.getItemLastModified(aItemId));
934+ bookmarksService.getItemLastModified(aItemId));
935 },
936 onBeforeItemRemoved: function(aItemId) {
937 Bindwood.writeMessage("onBeforeItemRemoved: called when push is " + Bindwood.push);
938 // A bookmark has been removed. This is called before it's
939 // been removed locally, though we're passed the itemId,
940 // which we use to delete from Couch.
941- var folderId = Bindwood.bookmarksService.getFolderIdForItem(aItemId);
942+ var folderId = bookmarksService.getFolderIdForItem(aItemId);
943 if (!Bindwood.itemWeCareAbout(aItemId)) {
944 Bindwood.writeMessage("Ignoring this before remove event");
945 return;
946@@ -1091,7 +1335,7 @@
947 doc.application_annotations['Ubuntu One'].private_application_annotations = {};
948 }
949 doc.application_annotations['Ubuntu One'].private_application_annotations.deleted = true;
950-
951+
952 try {
953 // Also remove from our local cache and remove
954 // annotation from service.
955@@ -1125,7 +1369,7 @@
956
957 Bindwood.makeLocalChangeOnly(
958 function() {
959- return Bindwood.annotationService.removeItemAnnotation(
960+ return annotationService.removeItemAnnotation(
961 aItemId, Bindwood.annotationKey); });
962 Bindwood.writeMessage(
963 "Removed annotations from bookmark identified by: " + aItemId);
964@@ -1173,7 +1417,7 @@
965 }
966
967 Bindwood.setLatestModified(
968- Bindwood.bookmarksService.getItemLastModified(aItemId));
969+ bookmarksService.getItemLastModified(aItemId));
970 },
971
972 onItemMoved: function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
973@@ -1182,29 +1426,45 @@
974 "The item: " + aItemId + " was moved from (" + aOldParent + ", " + aOldIndex +
975 ") to (" + aNewParent + ", " + aNewIndex + ")"
976 );
977- var uuid = Bindwood.uuidForItemId(aItemId);
978- var old_parent_uuid = Bindwood.uuidForItemId(aOldParent);
979- var old_parent_doc = Bindwood.couch.open(old_parent_uuid);
980- old_parent_doc.children = Bindwood.getUUIDsFromFolder(aOldParent);
981- try {
982- var response = Bindwood.couch.save(old_parent_doc);
983- Bindwood.seen_revisions[response.rev] = true;
984- } catch(e) {
985- Bindwood.writeError(
986- "Problem saving updated old parent doc to Couch: ", e);
987- }
988- if (aOldParent != aNewParent) {
989- var new_parent_uuid = Bindwood.uuidForItemId(aNewParent);
990- var new_parent_doc = Bindwood.couch.open(new_parent_uuid);
991- new_parent_doc.children = Bindwood.getUUIDsFromFolder(aNewParent);
992+ switch (Bindwood.push) {
993+ case 'DISABLED':
994+ Bindwood.writeMessage(
995+ "Moved, but not saving back to Couch.");
996+ break;
997+ case 'ENABLED':
998+ var uuid = Bindwood.uuidForItemId(aItemId);
999+ var old_parent_uuid = Bindwood.uuidForItemId(aOldParent);
1000+ var old_parent_doc = Bindwood.couch.open(old_parent_uuid);
1001+ old_parent_doc.children = Bindwood.getUUIDsFromFolder(aOldParent);
1002 try {
1003- var response = Bindwood.couch.save(new_parent_doc);
1004+ var response = Bindwood.couch.save(old_parent_doc);
1005 Bindwood.seen_revisions[response.rev] = true;
1006 } catch(e) {
1007 Bindwood.writeError(
1008- "Problem saving updated new parent doc to Couch: ", e);
1009- }
1010+ "Problem saving updated old parent doc to Couch: ", e);
1011+ }
1012+ if (aOldParent != aNewParent) {
1013+ var new_parent_uuid = Bindwood.uuidForItemId(aNewParent);
1014+ var new_parent_doc = Bindwood.couch.open(new_parent_uuid);
1015+ new_parent_doc.children = Bindwood.getUUIDsFromFolder(aNewParent);
1016+ try {
1017+ var response = Bindwood.couch.save(new_parent_doc);
1018+ Bindwood.seen_revisions[response.rev] = true;
1019+ } catch(e) {
1020+ Bindwood.writeError(
1021+ "Problem saving updated new parent doc to Couch: ", e);
1022+ }
1023+ }
1024+ break;
1025+ default:
1026+ break;
1027 }
1028+
1029+ // Set the latest modified to the greatest of aItemId, aOldParent, or aNewParent's last_modified
1030+ Bindwood.setLatestModified(
1031+ [bookmarksService.getItemLastModified(aItemId),
1032+ bookmarksService.getItemLastModified(aOldParent),
1033+ bookmarksService.getItemLastModified(aNewParent)].sort()[2]);
1034 },
1035
1036 // Currently unhandled
1037
1038=== modified file 'content/browserOverlay.xul'
1039--- content/browserOverlay.xul 2010-01-14 18:18:44 +0000
1040+++ content/browserOverlay.xul 2010-02-01 20:31:10 +0000
1041@@ -19,16 +19,11 @@
1042 <overlay id="bindwood"
1043 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
1044
1045- <script type="application/x-javascript" src="chrome://bindwood/content/oauth.js" />
1046- <script type="application/x-javascript" src="chrome://bindwood/content/couch.js" />
1047- <script type="application/x-javascript" src="chrome://bindwood/content/bindwood.js" />
1048-
1049 <window id="main-window">
1050 <script type="application/x-javascript">
1051- window.addEventListener("load", Bindwood.init, true);
1052+ Components.utils.import("resource://bindwood/bindwood.jsm");
1053
1054- var bmsvc = Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Components.interfaces.nsINavBookmarksService);
1055- window.addEventListener("load", function() { bmsvc.addObserver(Bindwood.Observer, false); }, false);
1056+ Bindwood.init();
1057 </script>
1058 </window>
1059
1060
1061=== renamed file 'content/couch.js' => 'content/couch.jsm'
1062--- content/couch.js 2009-11-04 21:42:45 +0000
1063+++ content/couch.jsm 2010-02-01 20:31:10 +0000
1064@@ -10,6 +10,16 @@
1065 // License for the specific language governing permissions and limitations under
1066 // the License.
1067
1068+Components.utils.import("resource://bindwood/oauth.jsm");
1069+
1070+var EXPORTED_SYMBOLS = ["CouchDB", "XMLHttpRequest"];
1071+
1072+var XMLHttpRequest = function () {
1073+ var class = "@mozilla.org/xmlextras/xmlhttprequest;1";
1074+ var service = Components.interfaces.nsIXMLHttpRequest;
1075+ return Components.classes[class].getService(service);
1076+}
1077+
1078 // A simple class to represent a database. Uses XMLHttpRequest to interface with
1079 // the CouchDB server.
1080
1081
1082=== added file 'content/first-time.html'
1083--- content/first-time.html 1970-01-01 00:00:00 +0000
1084+++ content/first-time.html 2010-02-01 20:31:10 +0000
1085@@ -0,0 +1,10 @@
1086+<html>
1087+ <head>
1088+ <title>Bindwood: First time syncing</title>
1089+ </head>
1090+ <body>
1091+ <h1>Bindwood</h1>
1092+ <p>Welcome to Bindwood. Please don't be alarmed if you notice a lag while Bindwood is syncing your bookmarks.</p>
1093+ <div id="status"></div>
1094+ </body>
1095+</html>
1096
1097=== added file 'content/migrate-old-bookmarks.html'
1098--- content/migrate-old-bookmarks.html 1970-01-01 00:00:00 +0000
1099+++ content/migrate-old-bookmarks.html 2010-02-01 20:31:10 +0000
1100@@ -0,0 +1,10 @@
1101+<html>
1102+ <head>
1103+ <title>Bindwood: Migrating older bookmarks</title>
1104+ </head>
1105+ <body>
1106+ <h1>Bindwood</h1>
1107+ <p>Welcome back to Bindwood. Bindwood now can preserve all your bookmarks, folders, and feeds, but we need to tidy up the records in the database before we can proceed. Please don't be alarmed if you notice a lag while Bindwood is migrating your bookmarks.</p>
1108+ <div id="status"></div>
1109+ </body>
1110+</html>
1111
1112=== renamed file 'content/oauth.js' => 'content/oauth.jsm'
1113--- content/oauth.js 2009-10-07 20:39:43 +0000
1114+++ content/oauth.jsm 2010-02-01 20:31:10 +0000
1115@@ -59,6 +59,8 @@
1116 The browser encodes each value before transmitting it. For example,
1117 see consumer.setInputs in example/consumer.js.
1118 */
1119+var EXPORTED_SYMBOLS = ["OAuth"];
1120+
1121 var OAuth; if (OAuth == null) OAuth = {};
1122
1123 OAuth.setProperties = function setProperties(into, from) {
1124
1125=== added file 'content/subsequent-client-first-time-sync.html'
1126--- content/subsequent-client-first-time-sync.html 1970-01-01 00:00:00 +0000
1127+++ content/subsequent-client-first-time-sync.html 2010-02-01 20:31:10 +0000
1128@@ -0,0 +1,10 @@
1129+<html>
1130+ <head>
1131+ <title>Bindwood: First time syncing another computer</title>
1132+ </head>
1133+ <body>
1134+ <h1>Bindwood</h1>
1135+ <p>Welcome back to Bindwood. While you've previously synced another computer, this computer needs to sync and merge its bookmarks. Please don't be alarmed if you notice a lag while Bindwood is syncing your bookmarks.</p>
1136+ <div id="status"></div>
1137+ </body>
1138+</html>
1139
1140=== modified file 'install.rdf'
1141--- install.rdf 2009-11-05 16:38:10 +0000
1142+++ install.rdf 2010-02-01 20:31:10 +0000
1143@@ -4,7 +4,7 @@
1144
1145 <Description about="urn:mozilla:install-manifest">
1146 <em:id>bindwood@ubuntu.com</em:id>
1147- <em:version>0.5</em:version>
1148+ <em:version>1.0</em:version>
1149 <em:type>2</em:type>
1150
1151 <!-- Target Application this extension can install into,
1152@@ -13,7 +13,7 @@
1153 <Description>
1154 <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
1155 <em:minVersion>3.5</em:minVersion>
1156- <em:maxVersion>3.5.*</em:maxVersion>
1157+ <em:maxVersion>3.6.*</em:maxVersion>
1158 </Description>
1159 </em:targetApplication>
1160

Subscribers

People subscribed via source and target branches