/services/sync/tps/extensions/tps/modules/bookmarks.jsm

http://github.com/zpao/v8monkey · Unknown · 1037 lines · 977 code · 60 blank · 0 comment · 0 complexity · 2e6ffaeef13e0ef68aa389f7a2ecd2f2 MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is Crossweave.
  15. *
  16. * The Initial Developer of the Original Code is Mozilla.
  17. * Portions created by the Initial Developer are Copyright (C) 2010
  18. * the Initial Developer. All Rights Reserved.
  19. *
  20. * Contributor(s):
  21. * Jonathan Griffin <jgriffin@mozilla.com>
  22. * Philipp von Weitershausen <philipp@weitershausen.de>
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either the GNU General Public License Version 2 or later (the "GPL"), or
  26. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. /* This is a JavaScript module (JSM) to be imported via
  38. * Components.utils.import() and acts as a singleton. Only the following
  39. * listed symbols will exposed on import, and only when and where imported.
  40. */
  41. var EXPORTED_SYMBOLS = ["PlacesItem", "Bookmark", "Separator", "Livemark",
  42. "BookmarkFolder", "DumpBookmarks"];
  43. const CC = Components.classes;
  44. const CI = Components.interfaces;
  45. const CU = Components.utils;
  46. CU.import("resource://tps/logger.jsm");
  47. CU.import("resource://gre/modules/Services.jsm");
  48. CU.import("resource://gre/modules/PlacesUtils.jsm");
  49. var DumpBookmarks = function TPS_Bookmarks__DumpBookmarks() {
  50. let writer = {
  51. value: "",
  52. write: function PlacesItem__dump__write(aStr, aLen) {
  53. this.value += aStr;
  54. }
  55. };
  56. let options = PlacesUtils.history.getNewQueryOptions();
  57. options.queryType = options.QUERY_TYPE_BOOKMARKS;
  58. let query = PlacesUtils.history.getNewQuery();
  59. query.setFolders([PlacesUtils.placesRootId], 1);
  60. let root = PlacesUtils.history.executeQuery(query, options).root;
  61. root.containerOpen = true;
  62. PlacesUtils.serializeNodeAsJSONToOutputStream(root, writer, true, false);
  63. let value = JSON.parse(writer.value);
  64. Logger.logInfo("dumping bookmarks\n\n" + JSON.stringify(value, null, ' ') + "\n\n");
  65. };
  66. /**
  67. * extend, causes a child object to inherit from a parent
  68. */
  69. function extend(child, supertype)
  70. {
  71. child.prototype.__proto__ = supertype.prototype;
  72. }
  73. /**
  74. * PlacesItemProps object, holds properties for places items
  75. */
  76. function PlacesItemProps(props) {
  77. this.location = null;
  78. this.uri = null;
  79. this.loadInSidebar = null;
  80. this.keyword = null;
  81. this.title = null;
  82. this.description = null;
  83. this.after = null;
  84. this.before = null;
  85. this.folder = null;
  86. this.position = null;
  87. this.delete = false;
  88. this.siteUri = null;
  89. this.feedUri = null;
  90. this.livemark = null;
  91. this.tags = null;
  92. this.last_item_pos = null;
  93. this.type = null;
  94. for (var prop in props) {
  95. if (prop in this)
  96. this[prop] = props[prop];
  97. }
  98. }
  99. /**
  100. * PlacesItem object. Base class for places items.
  101. */
  102. function PlacesItem(props) {
  103. this.props = new PlacesItemProps(props);
  104. if (this.props.location == null)
  105. this.props.location = "menu";
  106. if ("changes" in props)
  107. this.updateProps = new PlacesItemProps(props.changes);
  108. else
  109. this.updateProps = null;
  110. }
  111. /**
  112. * Instance methods for generic places items.
  113. */
  114. PlacesItem.prototype = {
  115. // an array of possible root folders for places items
  116. _bookmarkFolders: {
  117. "places": "placesRoot",
  118. "menu": "bookmarksMenuFolder",
  119. "tags": "tagFolder",
  120. "unfiled": "unfiledBookmarksFolder",
  121. "toolbar": "toolbarFolder",
  122. },
  123. toString: function() {
  124. var that = this;
  125. var props = ['uri', 'title', 'location', 'folder', 'feedUri', 'siteUri', 'livemark'];
  126. var string = (this.props.type ? this.props.type + " " : "") +
  127. "(" +
  128. (function() {
  129. var ret = [];
  130. for (var i in props) {
  131. if (that.props[props[i]]) {
  132. ret.push(props[i] + ": " + that.props[props[i]])
  133. }
  134. }
  135. return ret;
  136. })().join(", ") + ")";
  137. return string;
  138. },
  139. /**
  140. * GetPlacesNodeId
  141. *
  142. * Finds the id of the an item with the specified properties in the places
  143. * database.
  144. *
  145. * @param folder The id of the folder to search
  146. * @param type The type of the item to find, or null to match any item;
  147. * this is one of the values listed at
  148. * https://developer.mozilla.org/en/nsINavHistoryResultNode#Constants
  149. * @param title The title of the item to find, or null to match any title
  150. * @param uri The uri of the item to find, or null to match any uri
  151. *
  152. * @return the node id if the item was found, otherwise -1
  153. */
  154. GetPlacesNodeId: function (folder, type, title, uri) {
  155. let node_id = -1;
  156. let options = PlacesUtils.history.getNewQueryOptions();
  157. let query = PlacesUtils.history.getNewQuery();
  158. query.setFolders([folder], 1);
  159. let result = PlacesUtils.history.executeQuery(query, options);
  160. let rootNode = result.root;
  161. rootNode.containerOpen = true;
  162. for (let j = 0; j < rootNode.childCount; j ++) {
  163. let node = rootNode.getChild(j);
  164. if (node.title == title) {
  165. if (type == null || type == undefined || node.type == type)
  166. if (uri == undefined || uri == null || node.uri.spec == uri.spec)
  167. node_id = node.itemId;
  168. }
  169. }
  170. rootNode.containerOpen = false;
  171. return node_id;
  172. },
  173. /**
  174. * IsAdjacentTo
  175. *
  176. * Determines if this object is immediately adjacent to another.
  177. *
  178. * @param itemName The name of the other object; this may be any kind of
  179. * places item
  180. * @param relativePos The relative position of the other object. If -1,
  181. * it means the other object should precede this one, if +1,
  182. * the other object should come after this one
  183. * @return true if this object is immediately adjacent to the other object,
  184. * otherwise false
  185. */
  186. IsAdjacentTo: function(itemName, relativePos) {
  187. Logger.AssertTrue(this.props.folder_id != -1 && this.props.item_id != -1,
  188. "Either folder_id or item_id was invalid");
  189. let other_id = this.GetPlacesNodeId(this.props.folder_id, null, itemName);
  190. Logger.AssertTrue(other_id != -1, "item " + itemName + " not found");
  191. let other_pos = PlacesUtils.bookmarks.getItemIndex(other_id);
  192. let this_pos = PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
  193. if (other_pos + relativePos != this_pos) {
  194. Logger.logPotentialError("Invalid position - " +
  195. (this.props.title ? this.props.title : this.props.folder) +
  196. " not " + (relativePos == 1 ? "after " : "before ") + itemName +
  197. " for " + this.toString());
  198. return false;
  199. }
  200. return true;
  201. },
  202. /**
  203. * GetItemIndex
  204. *
  205. * Gets the item index for this places item.
  206. *
  207. * @return the item index, or -1 if there's an error
  208. */
  209. GetItemIndex: function() {
  210. if (this.props.item_id == -1)
  211. return -1;
  212. return PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
  213. },
  214. /**
  215. * GetFolder
  216. *
  217. * Gets the folder id for the specified bookmark folder
  218. *
  219. * @param location The full path of the folder, which must begin
  220. * with one of the bookmark root folders
  221. * @return the folder id if the folder is found, otherwise -1
  222. */
  223. GetFolder: function(location) {
  224. let folder_parts = location.split("/");
  225. if (!(folder_parts[0] in this._bookmarkFolders)) {
  226. return -1;
  227. }
  228. let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
  229. for (let i = 1; i < folder_parts.length; i++) {
  230. let subfolder_id = this.GetPlacesNodeId(
  231. folder_id,
  232. CI.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
  233. folder_parts[i]);
  234. if (subfolder_id == -1) {
  235. return -1;
  236. }
  237. else {
  238. folder_id = subfolder_id;
  239. }
  240. }
  241. return folder_id;
  242. },
  243. /**
  244. * CreateFolder
  245. *
  246. * Creates a bookmark folder.
  247. *
  248. * @param location The full path of the folder, which must begin
  249. * with one of the bookmark root folders
  250. * @return the folder id if the folder was created, otherwise -1
  251. */
  252. CreateFolder: function(location) {
  253. let folder_parts = location.split("/");
  254. if (!(folder_parts[0] in this._bookmarkFolders)) {
  255. return -1;
  256. }
  257. let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
  258. for (let i = 1; i < folder_parts.length; i++) {
  259. let subfolder_id = this.GetPlacesNodeId(
  260. folder_id,
  261. CI.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
  262. folder_parts[i]);
  263. if (subfolder_id == -1) {
  264. folder_id = PlacesUtils.bookmarks.createFolder(folder_id,
  265. folder_parts[i], -1);
  266. }
  267. else {
  268. folder_id = subfolder_id;
  269. }
  270. }
  271. return folder_id;
  272. },
  273. /**
  274. * GetOrCreateFolder
  275. *
  276. * Locates the specified folder; if not found it is created.
  277. *
  278. * @param location The full path of the folder, which must begin
  279. * with one of the bookmark root folders
  280. * @return the folder id if the folder was found or created, otherwise -1
  281. */
  282. GetOrCreateFolder: function(location) {
  283. folder_id = this.GetFolder(location);
  284. if (folder_id == -1)
  285. folder_id = this.CreateFolder(location);
  286. return folder_id;
  287. },
  288. /**
  289. * CheckDescription
  290. *
  291. * Compares the description of this places item with an expected
  292. * description.
  293. *
  294. * @param expectedDescription The description this places item is
  295. * expected to have
  296. * @return true if the actual and expected descriptions match, or if
  297. * there is no expected description; otherwise false
  298. */
  299. CheckDescription: function(expectedDescription) {
  300. if (expectedDescription != null) {
  301. let description = "";
  302. if (PlacesUtils.annotations.itemHasAnnotation(this.props.item_id,
  303. "bookmarkProperties/description")) {
  304. description = PlacesUtils.annotations.getItemAnnotation(
  305. this.props.item_id, "bookmarkProperties/description");
  306. }
  307. if (description != expectedDescription) {
  308. Logger.logPotentialError("Invalid description, expected: " +
  309. expectedDescription + ", actual: " + description + " for " +
  310. this.toString());
  311. return false;
  312. }
  313. }
  314. return true;
  315. },
  316. /**
  317. * CheckPosition
  318. *
  319. * Verifies the position of this places item.
  320. *
  321. * @param before The name of the places item that this item should be
  322. before, or null if this check should be skipped
  323. * @param after The name of the places item that this item should be
  324. after, or null if this check should be skipped
  325. * @param last_item_pos The index of the places item above this one,
  326. * or null if this check should be skipped
  327. * @return true if this item is in the correct position, otherwise false
  328. */
  329. CheckPosition: function(before, after, last_item_pos) {
  330. if (after)
  331. if (!this.IsAdjacentTo(after, 1)) return false;
  332. if (before)
  333. if (!this.IsAdjacentTo(before, -1)) return false;
  334. if (last_item_pos != null && last_item_pos > -1) {
  335. if (this.GetItemIndex() != last_item_pos + 1) {
  336. Logger.logPotentialError("Item not found at the expected index, got " +
  337. this.GetItemIndex() + ", expected " + (last_item_pos + 1) + " for " +
  338. this.toString());
  339. return false;
  340. }
  341. }
  342. return true;
  343. },
  344. /**
  345. * SetLocation
  346. *
  347. * Moves this places item to a different folder.
  348. *
  349. * @param location The full path of the folder to which to move this
  350. * places item, which must begin with one of the bookmark root
  351. * folders; if null, no changes are made
  352. * @return nothing if successful, otherwise an exception is thrown
  353. */
  354. SetLocation: function(location) {
  355. if (location != null) {
  356. let newfolder_id = this.GetOrCreateFolder(location);
  357. Logger.AssertTrue(newfolder_id != -1, "Location " + location +
  358. " doesn't exist; can't change item's location");
  359. PlacesUtils.bookmarks.moveItem(this.props.item_id, newfolder_id, -1);
  360. this.props.folder_id = newfolder_id;
  361. }
  362. },
  363. /**
  364. * SetDescription
  365. *
  366. * Updates the description for this places item.
  367. *
  368. * @param description The new description to set; if null, no changes are
  369. * made
  370. * @return nothing
  371. */
  372. SetDescription: function(description) {
  373. if (description != null) {
  374. if (description != "")
  375. PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
  376. "bookmarkProperties/description",
  377. description,
  378. 0,
  379. PlacesUtils.annotations.EXPIRE_NEVER);
  380. else
  381. PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
  382. "bookmarkProperties/description");
  383. }
  384. },
  385. /**
  386. * SetPosition
  387. *
  388. * Updates the position of this places item within this item's current
  389. * folder. Use SetLocation to change folders.
  390. *
  391. * @param position The new index this item should be moved to; if null,
  392. * no changes are made; if -1, this item is moved to the bottom of
  393. * the current folder
  394. * @return nothing if successful, otherwise an exception is thrown
  395. */
  396. SetPosition: function(position) {
  397. if (position != null) {
  398. let newposition = -1;
  399. if (position != -1) {
  400. newposition = this.GetPlacesNodeId(this.props.folder_id,
  401. null, position);
  402. Logger.AssertTrue(newposition != -1, "position " + position +
  403. " is invalid; unable to change position");
  404. newposition = PlacesUtils.bookmarks.getItemIndex(newposition);
  405. }
  406. PlacesUtils.bookmarks.moveItem(this.props.item_id,
  407. this.props.folder_id, newposition);
  408. }
  409. },
  410. /**
  411. * Update the title of this places item
  412. *
  413. * @param title The new title to set for this item; if null, no changes
  414. * are made
  415. * @return nothing
  416. */
  417. SetTitle: function(title) {
  418. if (title != null) {
  419. PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
  420. }
  421. },
  422. };
  423. /**
  424. * Bookmark class constructor. Initializes instance properties.
  425. */
  426. function Bookmark(props) {
  427. PlacesItem.call(this, props);
  428. if (this.props.title == null)
  429. this.props.title = this.props.uri;
  430. this.props.type = "bookmark";
  431. }
  432. /**
  433. * Bookmark instance methods.
  434. */
  435. Bookmark.prototype = {
  436. /**
  437. * SetKeyword
  438. *
  439. * Update this bookmark's keyword.
  440. *
  441. * @param keyword The keyword to set for this bookmark; if null, no
  442. * changes are made
  443. * @return nothing
  444. */
  445. SetKeyword: function(keyword) {
  446. if (keyword != null)
  447. PlacesUtils.bookmarks.setKeywordForBookmark(this.props.item_id, keyword);
  448. },
  449. /**
  450. * SetLoadInSidebar
  451. *
  452. * Updates this bookmark's loadInSidebar property.
  453. *
  454. * @param loadInSidebar if true, the loadInSidebar property will be set,
  455. * if false, it will be cleared, and any other value will result
  456. * in no change
  457. * @return nothing
  458. */
  459. SetLoadInSidebar: function(loadInSidebar) {
  460. if (loadInSidebar == true)
  461. PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
  462. "bookmarkProperties/loadInSidebar",
  463. true,
  464. 0,
  465. PlacesUtils.annotations.EXPIRE_NEVER);
  466. else if (loadInSidebar == false)
  467. PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
  468. "bookmarkProperties/loadInSidebar");
  469. },
  470. /**
  471. * SetTitle
  472. *
  473. * Updates this bookmark's title.
  474. *
  475. * @param title The new title to set for this boomark; if null, no changes
  476. * are made
  477. * @return nothing
  478. */
  479. SetTitle: function(title) {
  480. if (title)
  481. PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
  482. },
  483. /**
  484. * SetUri
  485. *
  486. * Updates this bookmark's URI.
  487. *
  488. * @param uri The new URI to set for this boomark; if null, no changes
  489. * are made
  490. * @return nothing
  491. */
  492. SetUri: function(uri) {
  493. if (uri) {
  494. let newURI = Services.io.newURI(uri, null, null);
  495. PlacesUtils.bookmarks.changeBookmarkURI(this.props.item_id, newURI);
  496. }
  497. },
  498. /**
  499. * SetTags
  500. *
  501. * Updates this bookmark's tags.
  502. *
  503. * @param tags An array of tags which should be associated with this
  504. * bookmark; any previous tags are removed; if this param is null,
  505. * no changes are made. If this param is an empty array, all
  506. * tags are removed from this bookmark.
  507. * @return nothing
  508. */
  509. SetTags: function(tags) {
  510. if (tags != null) {
  511. let URI = Services.io.newURI(this.props.uri, null, null);
  512. PlacesUtils.tagging.untagURI(URI, null);
  513. if (tags.length > 0)
  514. PlacesUtils.tagging.tagURI(URI, tags);
  515. }
  516. },
  517. /**
  518. * Create
  519. *
  520. * Creates the bookmark described by this object's properties.
  521. *
  522. * @return the id of the created bookmark
  523. */
  524. Create: function() {
  525. this.props.folder_id = this.GetOrCreateFolder(this.props.location);
  526. Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
  527. "bookmark, error creating folder " + this.props.location);
  528. let bookmarkURI = Services.io.newURI(this.props.uri, null, null);
  529. this.props.item_id = PlacesUtils.bookmarks.insertBookmark(this.props.folder_id,
  530. bookmarkURI,
  531. -1,
  532. this.props.title);
  533. this.SetKeyword(this.props.keyword);
  534. this.SetDescription(this.props.description);
  535. this.SetLoadInSidebar(this.props.loadInSidebar);
  536. this.SetTags(this.props.tags);
  537. return this.props.item_id;
  538. },
  539. /**
  540. * Update
  541. *
  542. * Updates this bookmark's properties according the properties on this
  543. * object's 'updateProps' property.
  544. *
  545. * @return nothing
  546. */
  547. Update: function() {
  548. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  549. "Invalid item_id during Remove");
  550. this.SetKeyword(this.updateProps.keyword);
  551. this.SetDescription(this.updateProps.description);
  552. this.SetLoadInSidebar(this.updateProps.loadInSidebar);
  553. this.SetTitle(this.updateProps.title);
  554. this.SetUri(this.updateProps.uri);
  555. this.SetTags(this.updateProps.tags);
  556. this.SetLocation(this.updateProps.location);
  557. this.SetPosition(this.updateProps.position);
  558. },
  559. /**
  560. * Find
  561. *
  562. * Locates the bookmark which corresponds to this object's properties.
  563. *
  564. * @return the bookmark id if the bookmark was found, otherwise -1
  565. */
  566. Find: function() {
  567. this.props.folder_id = this.GetFolder(this.props.location);
  568. if (this.props.folder_id == -1) {
  569. Logger.logError("Unable to find folder " + this.props.location);
  570. return -1;
  571. }
  572. let bookmarkTitle = this.props.title;
  573. this.props.item_id = this.GetPlacesNodeId(this.props.folder_id,
  574. null,
  575. bookmarkTitle,
  576. this.props.uri);
  577. if (this.props.item_id == -1) {
  578. Logger.logPotentialError(this.toString() + " not found");
  579. return -1;
  580. }
  581. if (!this.CheckDescription(this.props.description))
  582. return -1;
  583. if (this.props.keyword != null) {
  584. let keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this.props.item_id);
  585. if (keyword != this.props.keyword) {
  586. Logger.logPotentialError("Incorrect keyword - expected: " +
  587. this.props.keyword + ", actual: " + keyword +
  588. " for " + this.toString());
  589. return -1;
  590. }
  591. }
  592. let loadInSidebar = PlacesUtils.annotations.itemHasAnnotation(
  593. this.props.item_id,
  594. "bookmarkProperties/loadInSidebar");
  595. if (loadInSidebar)
  596. loadInSidebar = PlacesUtils.annotations.getItemAnnotation(
  597. this.props.item_id,
  598. "bookmarkProperties/loadInSidebar");
  599. if (this.props.loadInSidebar != null &&
  600. loadInSidebar != this.props.loadInSidebar) {
  601. Logger.logPotentialError("Incorrect loadInSidebar setting - expected: " +
  602. this.props.loadInSidebar + ", actual: " + loadInSidebar +
  603. " for " + this.toString());
  604. return -1;
  605. }
  606. if (this.props.tags != null) {
  607. try {
  608. let URI = Services.io.newURI(this.props.uri, null, null);
  609. let tags = PlacesUtils.tagging.getTagsForURI(URI, {});
  610. tags.sort();
  611. this.props.tags.sort();
  612. if (JSON.stringify(tags) != JSON.stringify(this.props.tags)) {
  613. Logger.logPotentialError("Wrong tags - expected: " +
  614. JSON.stringify(this.props.tags) + ", actual: " +
  615. JSON.stringify(tags) + " for " + this.toString());
  616. return -1;
  617. }
  618. }
  619. catch (e) {
  620. Logger.logPotentialError("error processing tags " + e);
  621. return -1;
  622. }
  623. }
  624. if (!this.CheckPosition(this.props.before,
  625. this.props.after,
  626. this.props.last_item_pos))
  627. return -1;
  628. return this.props.item_id;
  629. },
  630. /**
  631. * Remove
  632. *
  633. * Removes this bookmark. The bookmark should have been located previously
  634. * by a call to Find.
  635. *
  636. * @return nothing
  637. */
  638. Remove: function() {
  639. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  640. "Invalid item_id during Remove");
  641. PlacesUtils.bookmarks.removeItem(this.props.item_id);
  642. },
  643. };
  644. extend(Bookmark, PlacesItem);
  645. /**
  646. * BookmarkFolder class constructor. Initializes instance properties.
  647. */
  648. function BookmarkFolder(props) {
  649. PlacesItem.call(this, props);
  650. this.props.type = "folder";
  651. }
  652. /**
  653. * BookmarkFolder instance methods
  654. */
  655. BookmarkFolder.prototype = {
  656. /**
  657. * Create
  658. *
  659. * Creates the bookmark folder described by this object's properties.
  660. *
  661. * @return the id of the created bookmark folder
  662. */
  663. Create: function() {
  664. this.props.folder_id = this.GetOrCreateFolder(this.props.location);
  665. Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
  666. "folder, error creating parent folder " + this.props.location);
  667. this.props.item_id = PlacesUtils.bookmarks.createFolder(this.props.folder_id,
  668. this.props.folder,
  669. -1);
  670. this.SetDescription(this.props.description);
  671. return this.props.folder_id;
  672. },
  673. /**
  674. * Find
  675. *
  676. * Locates the bookmark folder which corresponds to this object's
  677. * properties.
  678. *
  679. * @return the folder id if the folder was found, otherwise -1
  680. */
  681. Find: function() {
  682. this.props.folder_id = this.GetFolder(this.props.location);
  683. if (this.props.folder_id == -1) {
  684. Logger.logError("Unable to find folder " + this.props.location);
  685. return -1;
  686. }
  687. this.props.item_id = this.GetPlacesNodeId(
  688. this.props.folder_id,
  689. CI.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
  690. this.props.folder);
  691. if (!this.CheckDescription(this.props.description))
  692. return -1;
  693. if (!this.CheckPosition(this.props.before,
  694. this.props.after,
  695. this.props.last_item_pos))
  696. return -1;
  697. return this.props.item_id;
  698. },
  699. /**
  700. * Remove
  701. *
  702. * Removes this folder. The folder should have been located previously
  703. * by a call to Find.
  704. *
  705. * @return nothing
  706. */
  707. Remove: function() {
  708. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  709. "Invalid item_id during Remove");
  710. PlacesUtils.bookmarks.removeFolderChildren(this.props.item_id);
  711. PlacesUtils.bookmarks.removeItem(this.props.item_id);
  712. },
  713. /**
  714. * Update
  715. *
  716. * Updates this bookmark's properties according the properties on this
  717. * object's 'updateProps' property.
  718. *
  719. * @return nothing
  720. */
  721. Update: function() {
  722. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  723. "Invalid item_id during Update");
  724. this.SetLocation(this.updateProps.location);
  725. this.SetPosition(this.updateProps.position);
  726. this.SetTitle(this.updateProps.folder);
  727. this.SetDescription(this.updateProps.description);
  728. },
  729. };
  730. extend(BookmarkFolder, PlacesItem);
  731. /**
  732. * Livemark class constructor. Initialzes instance properties.
  733. */
  734. function Livemark(props) {
  735. PlacesItem.call(this, props);
  736. this.props.type = "livemark";
  737. }
  738. /**
  739. * Livemark instance methods
  740. */
  741. Livemark.prototype = {
  742. /**
  743. * Create
  744. *
  745. * Creates the livemark described by this object's properties.
  746. *
  747. * @return the id of the created livemark
  748. */
  749. Create: function() {
  750. this.props.folder_id = this.GetOrCreateFolder(this.props.location);
  751. Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
  752. "folder, error creating parent folder " + this.props.location);
  753. let siteURI = null;
  754. if (this.props.siteUri != null)
  755. siteURI = Services.io.newURI(this.props.siteUri, null, null);
  756. this.props.item_id = PlacesUtils.livemarks.createLivemark(
  757. this.props.folder_id,
  758. this.props.livemark,
  759. siteURI,
  760. Services.io.newURI(this.props.feedUri, null, null),
  761. -1);
  762. return this.props.item_id;
  763. },
  764. /**
  765. * Find
  766. *
  767. * Locates the livemark which corresponds to this object's
  768. * properties.
  769. *
  770. * @return the item id if the livemark was found, otherwise -1
  771. */
  772. Find: function() {
  773. this.props.folder_id = this.GetFolder(this.props.location);
  774. if (this.props.folder_id == -1) {
  775. Logger.logError("Unable to find folder " + this.props.location);
  776. return -1;
  777. }
  778. this.props.item_id = this.GetPlacesNodeId(
  779. this.props.folder_id,
  780. CI.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
  781. this.props.livemark);
  782. if (!PlacesUtils.livemarks.isLivemark(this.props.item_id)) {
  783. Logger.logPotentialError("livemark folder found, but it's just a regular folder, for " +
  784. this.toString());
  785. this.props.item_id = -1;
  786. return -1;
  787. }
  788. let feedURI = Services.io.newURI(this.props.feedUri, null, null);
  789. let lmFeedURI = PlacesUtils.livemarks.getFeedURI(this.props.item_id);
  790. if (feedURI.spec != lmFeedURI.spec) {
  791. Logger.logPotentialError("livemark feed uri not correct, expected: " +
  792. this.props.feedUri + ", actual: " + lmFeedURI.spec +
  793. " for " + this.toString());
  794. return -1;
  795. }
  796. if (this.props.siteUri != null) {
  797. let siteURI = Services.io.newURI(this.props.siteUri, null, null);
  798. let lmSiteURI = PlacesUtils.livemarks.getSiteURI(this.props.item_id);
  799. if (siteURI.spec != lmSiteURI.spec) {
  800. Logger.logPotentialError("livemark site uri not correct, expected: " +
  801. this.props.siteUri + ", actual: " + lmSiteURI.spec + " for " +
  802. this.toString());
  803. return -1;
  804. }
  805. }
  806. if (!this.CheckPosition(this.props.before,
  807. this.props.after,
  808. this.props.last_item_pos))
  809. return -1;
  810. return this.props.item_id;
  811. },
  812. /**
  813. * SetSiteUri
  814. *
  815. * Sets the siteURI property for this livemark.
  816. *
  817. * @param siteUri the URI to set; if null, no changes are made
  818. * @return nothing
  819. */
  820. SetSiteUri: function(siteUri) {
  821. if (siteUri) {
  822. let siteURI = Services.io.newURI(siteUri, null, null);
  823. PlacesUtils.livemarks.setSiteURI(this.props.item_id, siteURI);
  824. }
  825. },
  826. /**
  827. * SetFeedUri
  828. *
  829. * Sets the feedURI property for this livemark.
  830. *
  831. * @param feedUri the URI to set; if null, no changes are made
  832. * @return nothing
  833. */
  834. SetFeedUri: function(feedUri) {
  835. if (feedUri) {
  836. let feedURI = Services.io.newURI(feedUri, null, null);
  837. PlacesUtils.livemarks.setFeedURI(this.props.item_id, feedURI);
  838. }
  839. },
  840. /**
  841. * Update
  842. *
  843. * Updates this livemark's properties according the properties on this
  844. * object's 'updateProps' property.
  845. *
  846. * @return nothing
  847. */
  848. Update: function() {
  849. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  850. "Invalid item_id during Update");
  851. this.SetLocation(this.updateProps.location);
  852. this.SetPosition(this.updateProps.position);
  853. this.SetSiteUri(this.updateProps.siteUri);
  854. this.SetFeedUri(this.updateProps.feedUri);
  855. this.SetTitle(this.updateProps.livemark);
  856. return true;
  857. },
  858. /**
  859. * Remove
  860. *
  861. * Removes this livemark. The livemark should have been located previously
  862. * by a call to Find.
  863. *
  864. * @return nothing
  865. */
  866. Remove: function() {
  867. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  868. "Invalid item_id during Remove");
  869. PlacesUtils.bookmarks.removeItem(this.props.item_id);
  870. },
  871. };
  872. extend(Livemark, PlacesItem);
  873. /**
  874. * Separator class constructor. Initializes instance properties.
  875. */
  876. function Separator(props) {
  877. PlacesItem.call(this, props);
  878. this.props.type = "separator";
  879. }
  880. /**
  881. * Separator instance methods.
  882. */
  883. Separator.prototype = {
  884. /**
  885. * Create
  886. *
  887. * Creates the bookmark separator described by this object's properties.
  888. *
  889. * @return the id of the created separator
  890. */
  891. Create: function () {
  892. this.props.folder_id = this.GetOrCreateFolder(this.props.location);
  893. Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
  894. "folder, error creating parent folder " + this.props.location);
  895. this.props.item_id = PlacesUtils.bookmarks.insertSeparator(this.props.folder_id,
  896. -1);
  897. return this.props.item_id;
  898. },
  899. /**
  900. * Find
  901. *
  902. * Locates the bookmark separator which corresponds to this object's
  903. * properties.
  904. *
  905. * @return the item id if the separator was found, otherwise -1
  906. */
  907. Find: function () {
  908. this.props.folder_id = this.GetFolder(this.props.location);
  909. if (this.props.folder_id == -1) {
  910. Logger.logError("Unable to find folder " + this.props.location);
  911. return -1;
  912. }
  913. if (this.props.before == null && this.props.last_item_pos == null) {
  914. Logger.logPotentialError("Separator requires 'before' attribute if it's the" +
  915. "first item in the list");
  916. return -1;
  917. }
  918. let expected_pos = -1;
  919. if (this.props.before) {
  920. other_id = this.GetPlacesNodeId(this.props.folder_id,
  921. null,
  922. this.props.before);
  923. if (other_id == -1) {
  924. Logger.logPotentialError("Can't find places item " + this.props.before +
  925. " for locating separator");
  926. return -1;
  927. }
  928. expected_pos = PlacesUtils.bookmarks.getItemIndex(other_id) - 1;
  929. }
  930. else {
  931. expected_pos = this.props.last_item_pos + 1;
  932. }
  933. this.props.item_id = PlacesUtils.bookmarks.getIdForItemAt(this.props.folder_id,
  934. expected_pos);
  935. if (this.props.item_id == -1) {
  936. Logger.logPotentialError("No separator found at position " + expected_pos);
  937. }
  938. else {
  939. if (PlacesUtils.bookmarks.getItemType(this.props.item_id) !=
  940. PlacesUtils.bookmarks.TYPE_SEPARATOR) {
  941. Logger.logPotentialError("Places item at position " + expected_pos +
  942. " is not a separator");
  943. return -1;
  944. }
  945. }
  946. return this.props.item_id;
  947. },
  948. /**
  949. * Update
  950. *
  951. * Updates this separator's properties according the properties on this
  952. * object's 'updateProps' property.
  953. *
  954. * @return nothing
  955. */
  956. Update: function() {
  957. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  958. "Invalid item_id during Update");
  959. this.SetLocation(this.updateProps.location);
  960. this.SetPosition(this.updateProps.position);
  961. return true;
  962. },
  963. /**
  964. * Remove
  965. *
  966. * Removes this separator. The separator should have been located
  967. * previously by a call to Find.
  968. *
  969. * @return nothing
  970. */
  971. Remove: function() {
  972. Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
  973. "Invalid item_id during Update");
  974. PlacesUtils.bookmarks.removeItem(this.props.item_id);
  975. },
  976. };
  977. extend(Separator, PlacesItem);