browser/components/places/content/bookmarkProperties.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/components/places/content/bookmarkProperties.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,650 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/**
    1.10 + * The panel is initialized based on data given in the js object passed
    1.11 + * as window.arguments[0]. The object must have the following fields set:
    1.12 + *   @ action (String). Possible values:
    1.13 + *     - "add" - for adding a new item.
    1.14 + *       @ type (String). Possible values:
    1.15 + *         - "bookmark"
    1.16 + *           @ loadBookmarkInSidebar - optional, the default state for the
    1.17 + *             "Load this bookmark in the sidebar" field.
    1.18 + *         - "folder"
    1.19 + *           @ URIList (Array of nsIURI objects) - optional, list of uris to
    1.20 + *             be bookmarked under the new folder.
    1.21 + *         - "livemark"
    1.22 + *       @ uri (nsIURI object) - optional, the default uri for the new item.
    1.23 + *         The property is not used for the "folder with items" type.
    1.24 + *       @ title (String) - optional, the default title for the new item.
    1.25 + *       @ description (String) - optional, the default description for the new
    1.26 + *         item.
    1.27 + *       @ defaultInsertionPoint (InsertionPoint JS object) - optional, the
    1.28 + *         default insertion point for the new item.
    1.29 + *       @ keyword (String) - optional, the default keyword for the new item.
    1.30 + *       @ postData (String) - optional, POST data to accompany the keyword.
    1.31 + *       @ charSet (String) - optional, character-set to accompany the keyword.
    1.32 + *      Notes:
    1.33 + *        1) If |uri| is set for a bookmark/livemark item and |title| isn't,
    1.34 + *           the dialog will query the history tables for the title associated
    1.35 + *           with the given uri. If the dialog is set to adding a folder with
    1.36 + *           bookmark items under it (see URIList), a default static title is
    1.37 + *           used ("[Folder Name]").
    1.38 + *        2) The index field of the default insertion point is ignored if
    1.39 + *           the folder picker is shown.
    1.40 + *     - "edit" - for editing a bookmark item or a folder.
    1.41 + *       @ type (String). Possible values:
    1.42 + *         - "bookmark"
    1.43 + *           @ itemId (Integer) - the id of the bookmark item.
    1.44 + *         - "folder" (also applies to livemarks)
    1.45 + *           @ itemId (Integer) - the id of the folder.
    1.46 + *   @ hiddenRows (Strings array) - optional, list of rows to be hidden
    1.47 + *     regardless of the item edited or added by the dialog.
    1.48 + *     Possible values:
    1.49 + *     - "title"
    1.50 + *     - "location"
    1.51 + *     - "description"
    1.52 + *     - "keyword"
    1.53 + *     - "tags"
    1.54 + *     - "loadInSidebar"
    1.55 + *     - "feedLocation"
    1.56 + *     - "siteLocation"
    1.57 + *     - "folderPicker" - hides both the tree and the menu.
    1.58 + *   @ readOnly (Boolean) - optional, states if the panel should be read-only
    1.59 + *
    1.60 + * window.arguments[0].performed is set to true if any transaction has
    1.61 + * been performed by the dialog.
    1.62 + */
    1.63 +
    1.64 +Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
    1.65 +XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
    1.66 +                                  "resource://gre/modules/PrivateBrowsingUtils.jsm");
    1.67 +
    1.68 +const BOOKMARK_ITEM = 0;
    1.69 +const BOOKMARK_FOLDER = 1;
    1.70 +const LIVEMARK_CONTAINER = 2;
    1.71 +
    1.72 +const ACTION_EDIT = 0;
    1.73 +const ACTION_ADD = 1;
    1.74 +
    1.75 +var BookmarkPropertiesPanel = {
    1.76 +
    1.77 +  /** UI Text Strings */
    1.78 +  __strings: null,
    1.79 +  get _strings() {
    1.80 +    if (!this.__strings) {
    1.81 +      this.__strings = document.getElementById("stringBundle");
    1.82 +    }
    1.83 +    return this.__strings;
    1.84 +  },
    1.85 +
    1.86 +  _action: null,
    1.87 +  _itemType: null,
    1.88 +  _itemId: -1,
    1.89 +  _uri: null,
    1.90 +  _loadInSidebar: false,
    1.91 +  _title: "",
    1.92 +  _description: "",
    1.93 +  _URIs: [],
    1.94 +  _keyword: "",
    1.95 +  _postData: null,
    1.96 +  _charSet: "",
    1.97 +  _feedURI: null,
    1.98 +  _siteURI: null,
    1.99 +
   1.100 +  _defaultInsertionPoint: null,
   1.101 +  _hiddenRows: [],
   1.102 +  _batching: false,
   1.103 +  _readOnly: false,
   1.104 +
   1.105 +  /**
   1.106 +   * This method returns the correct label for the dialog's "accept"
   1.107 +   * button based on the variant of the dialog.
   1.108 +   */
   1.109 +  _getAcceptLabel: function BPP__getAcceptLabel() {
   1.110 +    if (this._action == ACTION_ADD) {
   1.111 +      if (this._URIs.length)
   1.112 +        return this._strings.getString("dialogAcceptLabelAddMulti");
   1.113 +
   1.114 +      if (this._itemType == LIVEMARK_CONTAINER)
   1.115 +        return this._strings.getString("dialogAcceptLabelAddLivemark");
   1.116 +
   1.117 +      if (this._dummyItem || this._loadInSidebar)
   1.118 +        return this._strings.getString("dialogAcceptLabelAddItem");
   1.119 +
   1.120 +      return this._strings.getString("dialogAcceptLabelSaveItem");
   1.121 +    }
   1.122 +    return this._strings.getString("dialogAcceptLabelEdit");
   1.123 +  },
   1.124 +
   1.125 +  /**
   1.126 +   * This method returns the correct title for the current variant
   1.127 +   * of this dialog.
   1.128 +   */
   1.129 +  _getDialogTitle: function BPP__getDialogTitle() {
   1.130 +    if (this._action == ACTION_ADD) {
   1.131 +      if (this._itemType == BOOKMARK_ITEM)
   1.132 +        return this._strings.getString("dialogTitleAddBookmark");
   1.133 +      if (this._itemType == LIVEMARK_CONTAINER)
   1.134 +        return this._strings.getString("dialogTitleAddLivemark");
   1.135 +
   1.136 +      // add folder
   1.137 +      NS_ASSERT(this._itemType == BOOKMARK_FOLDER, "Unknown item type");
   1.138 +      if (this._URIs.length)
   1.139 +        return this._strings.getString("dialogTitleAddMulti");
   1.140 +
   1.141 +      return this._strings.getString("dialogTitleAddFolder");
   1.142 +    }
   1.143 +    if (this._action == ACTION_EDIT) {
   1.144 +      return this._strings.getFormattedString("dialogTitleEdit", [this._title]);
   1.145 +    }
   1.146 +    return "";
   1.147 +  },
   1.148 +
   1.149 +  /**
   1.150 +   * Determines the initial data for the item edited or added by this dialog
   1.151 +   */
   1.152 +  _determineItemInfo: function BPP__determineItemInfo() {
   1.153 +    var dialogInfo = window.arguments[0];
   1.154 +    this._action = dialogInfo.action == "add" ? ACTION_ADD : ACTION_EDIT;
   1.155 +    this._hiddenRows = dialogInfo.hiddenRows ? dialogInfo.hiddenRows : [];
   1.156 +    if (this._action == ACTION_ADD) {
   1.157 +      NS_ASSERT("type" in dialogInfo, "missing type property for add action");
   1.158 +
   1.159 +      if ("title" in dialogInfo)
   1.160 +        this._title = dialogInfo.title;
   1.161 +
   1.162 +      if ("defaultInsertionPoint" in dialogInfo) {
   1.163 +        this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint;
   1.164 +      }
   1.165 +      else
   1.166 +        this._defaultInsertionPoint =
   1.167 +          new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
   1.168 +                             PlacesUtils.bookmarks.DEFAULT_INDEX,
   1.169 +                             Ci.nsITreeView.DROP_ON);
   1.170 +
   1.171 +      switch (dialogInfo.type) {
   1.172 +        case "bookmark":
   1.173 +          this._itemType = BOOKMARK_ITEM;
   1.174 +          if ("uri" in dialogInfo) {
   1.175 +            NS_ASSERT(dialogInfo.uri instanceof Ci.nsIURI,
   1.176 +                      "uri property should be a uri object");
   1.177 +            this._uri = dialogInfo.uri;
   1.178 +            if (typeof(this._title) != "string") {
   1.179 +              this._title = this._getURITitleFromHistory(this._uri) ||
   1.180 +                            this._uri.spec;
   1.181 +            }
   1.182 +          }
   1.183 +          else {
   1.184 +            this._uri = PlacesUtils._uri("about:blank");
   1.185 +            this._title = this._strings.getString("newBookmarkDefault");
   1.186 +            this._dummyItem = true;
   1.187 +          }
   1.188 +
   1.189 +          if ("loadBookmarkInSidebar" in dialogInfo)
   1.190 +            this._loadInSidebar = dialogInfo.loadBookmarkInSidebar;
   1.191 +
   1.192 +          if ("keyword" in dialogInfo) {
   1.193 +            this._keyword = dialogInfo.keyword;
   1.194 +            this._isAddKeywordDialog = true;
   1.195 +            if ("postData" in dialogInfo)
   1.196 +              this._postData = dialogInfo.postData;
   1.197 +            if ("charSet" in dialogInfo)
   1.198 +              this._charSet = dialogInfo.charSet;
   1.199 +          }
   1.200 +          break;
   1.201 +
   1.202 +        case "folder":
   1.203 +          this._itemType = BOOKMARK_FOLDER;
   1.204 +          if (!this._title) {
   1.205 +            if ("URIList" in dialogInfo) {
   1.206 +              this._title = this._strings.getString("bookmarkAllTabsDefault");
   1.207 +              this._URIs = dialogInfo.URIList;
   1.208 +            }
   1.209 +            else
   1.210 +              this._title = this._strings.getString("newFolderDefault");
   1.211 +              this._dummyItem = true;
   1.212 +          }
   1.213 +          break;
   1.214 +
   1.215 +        case "livemark":
   1.216 +          this._itemType = LIVEMARK_CONTAINER;
   1.217 +          if ("feedURI" in dialogInfo)
   1.218 +            this._feedURI = dialogInfo.feedURI;
   1.219 +          if ("siteURI" in dialogInfo)
   1.220 +            this._siteURI = dialogInfo.siteURI;
   1.221 +
   1.222 +          if (!this._title) {
   1.223 +            if (this._feedURI) {
   1.224 +              this._title = this._getURITitleFromHistory(this._feedURI) ||
   1.225 +                            this._feedURI.spec;
   1.226 +            }
   1.227 +            else
   1.228 +              this._title = this._strings.getString("newLivemarkDefault");
   1.229 +          }
   1.230 +      }
   1.231 +
   1.232 +      if ("description" in dialogInfo)
   1.233 +        this._description = dialogInfo.description;
   1.234 +    }
   1.235 +    else { // edit
   1.236 +      NS_ASSERT("itemId" in dialogInfo);
   1.237 +      this._itemId = dialogInfo.itemId;
   1.238 +      this._title = PlacesUtils.bookmarks.getItemTitle(this._itemId);
   1.239 +      this._readOnly = !!dialogInfo.readOnly;
   1.240 +
   1.241 +      switch (dialogInfo.type) {
   1.242 +        case "bookmark":
   1.243 +          this._itemType = BOOKMARK_ITEM;
   1.244 +
   1.245 +          this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
   1.246 +          // keyword
   1.247 +          this._keyword = PlacesUtils.bookmarks
   1.248 +                                     .getKeywordForBookmark(this._itemId);
   1.249 +          // Load In Sidebar
   1.250 +          this._loadInSidebar = PlacesUtils.annotations
   1.251 +                                           .itemHasAnnotation(this._itemId,
   1.252 +                                                              PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
   1.253 +          break;
   1.254 +
   1.255 +        case "folder":
   1.256 +          this._itemType = BOOKMARK_FOLDER;
   1.257 +          PlacesUtils.livemarks.getLivemark({ id: this._itemId })
   1.258 +            .then(aLivemark => {
   1.259 +              this._itemType = LIVEMARK_CONTAINER;
   1.260 +              this._feedURI = aLivemark.feedURI;
   1.261 +              this._siteURI = aLivemark.siteURI;
   1.262 +              this._fillEditProperties();
   1.263 +
   1.264 +              let acceptButton = document.documentElement.getButton("accept");
   1.265 +              acceptButton.disabled = !this._inputIsValid();
   1.266 +
   1.267 +              let newHeight = window.outerHeight +
   1.268 +                              this._element("descriptionField").boxObject.height;
   1.269 +              window.resizeTo(window.outerWidth, newHeight);
   1.270 +            }, () => undefined);
   1.271 +
   1.272 +          break;
   1.273 +      }
   1.274 +
   1.275 +      // Description
   1.276 +      if (PlacesUtils.annotations
   1.277 +                     .itemHasAnnotation(this._itemId, PlacesUIUtils.DESCRIPTION_ANNO)) {
   1.278 +        this._description = PlacesUtils.annotations
   1.279 +                                       .getItemAnnotation(this._itemId,
   1.280 +                                                          PlacesUIUtils.DESCRIPTION_ANNO);
   1.281 +      }
   1.282 +    }
   1.283 +  },
   1.284 +
   1.285 +  /**
   1.286 +   * This method returns the title string corresponding to a given URI.
   1.287 +   * If none is available from the bookmark service (probably because
   1.288 +   * the given URI doesn't appear in bookmarks or history), we synthesize
   1.289 +   * a title from the first 100 characters of the URI.
   1.290 +   *
   1.291 +   * @param aURI
   1.292 +   *        nsIURI object for which we want the title
   1.293 +   *
   1.294 +   * @returns a title string
   1.295 +   */
   1.296 +  _getURITitleFromHistory: function BPP__getURITitleFromHistory(aURI) {
   1.297 +    NS_ASSERT(aURI instanceof Ci.nsIURI);
   1.298 +
   1.299 +    // get the title from History
   1.300 +    return PlacesUtils.history.getPageTitle(aURI);
   1.301 +  },
   1.302 +
   1.303 +  /**
   1.304 +   * This method should be called by the onload of the Bookmark Properties
   1.305 +   * dialog to initialize the state of the panel.
   1.306 +   */
   1.307 +  onDialogLoad: function BPP_onDialogLoad() {
   1.308 +    this._determineItemInfo();
   1.309 +
   1.310 +    document.title = this._getDialogTitle();
   1.311 +    var acceptButton = document.documentElement.getButton("accept");
   1.312 +    acceptButton.label = this._getAcceptLabel();
   1.313 +
   1.314 +    this._beginBatch();
   1.315 +
   1.316 +    switch (this._action) {
   1.317 +      case ACTION_EDIT:
   1.318 +        this._fillEditProperties();
   1.319 +        acceptButton.disabled = this._readOnly;
   1.320 +        break;
   1.321 +      case ACTION_ADD:
   1.322 +        this._fillAddProperties();
   1.323 +        // if this is an uri related dialog disable accept button until
   1.324 +        // the user fills an uri value.
   1.325 +        if (this._itemType == BOOKMARK_ITEM)
   1.326 +          acceptButton.disabled = !this._inputIsValid();
   1.327 +        break;
   1.328 +    }
   1.329 +
   1.330 +    // When collapsible elements change their collapsed attribute we must
   1.331 +    // resize the dialog.
   1.332 +    // sizeToContent is not usable due to bug 90276, so we'll use resizeTo
   1.333 +    // instead and cache the element size. See WSucks in the legacy
   1.334 +    // UI code (addBookmark2.js).
   1.335 +    if (!this._element("tagsRow").collapsed) {
   1.336 +      this._element("tagsSelectorRow")
   1.337 +          .addEventListener("DOMAttrModified", this, false);
   1.338 +    }
   1.339 +    if (!this._element("folderRow").collapsed) {
   1.340 +      this._element("folderTreeRow")
   1.341 +          .addEventListener("DOMAttrModified", this, false);
   1.342 +    }
   1.343 +
   1.344 +    if (!this._readOnly) {
   1.345 +      // Listen on uri fields to enable accept button if input is valid
   1.346 +      if (this._itemType == BOOKMARK_ITEM) {
   1.347 +        this._element("locationField")
   1.348 +            .addEventListener("input", this, false);
   1.349 +        if (this._isAddKeywordDialog) {
   1.350 +          this._element("keywordField")
   1.351 +              .addEventListener("input", this, false);
   1.352 +        }
   1.353 +      }
   1.354 +      else if (this._itemType == LIVEMARK_CONTAINER) {
   1.355 +        this._element("feedLocationField")
   1.356 +            .addEventListener("input", this, false);
   1.357 +        this._element("siteLocationField")
   1.358 +            .addEventListener("input", this, false);
   1.359 +      }
   1.360 +    }
   1.361 +
   1.362 +    window.sizeToContent();
   1.363 +  },
   1.364 +
   1.365 +  // nsIDOMEventListener
   1.366 +  _elementsHeight: [],
   1.367 +  handleEvent: function BPP_handleEvent(aEvent) {
   1.368 +    var target = aEvent.target;
   1.369 +    switch (aEvent.type) {
   1.370 +      case "input":
   1.371 +        if (target.id == "editBMPanel_locationField" ||
   1.372 +            target.id == "editBMPanel_feedLocationField" ||
   1.373 +            target.id == "editBMPanel_siteLocationField" ||
   1.374 +            target.id == "editBMPanel_keywordField") {
   1.375 +          // Check uri fields to enable accept button if input is valid
   1.376 +          document.documentElement
   1.377 +                  .getButton("accept").disabled = !this._inputIsValid();
   1.378 +        }
   1.379 +        break;
   1.380 +
   1.381 +      case "DOMAttrModified":
   1.382 +        // this is called when collapsing a node, but also its direct children,
   1.383 +        // we only need to resize when the original node changes.
   1.384 +        if ((target.id == "editBMPanel_tagsSelectorRow" ||
   1.385 +             target.id == "editBMPanel_folderTreeRow") &&
   1.386 +            aEvent.attrName == "collapsed" &&
   1.387 +            target == aEvent.originalTarget) {
   1.388 +          var id = target.id;
   1.389 +          var newHeight = window.outerHeight;
   1.390 +          if (aEvent.newValue) // is collapsed
   1.391 +            newHeight -= this._elementsHeight[id];
   1.392 +          else {
   1.393 +            this._elementsHeight[id] = target.boxObject.height;
   1.394 +            newHeight += this._elementsHeight[id];
   1.395 +          }
   1.396 +
   1.397 +          window.resizeTo(window.outerWidth, newHeight);
   1.398 +        }
   1.399 +        break;
   1.400 +    }
   1.401 +  },
   1.402 +
   1.403 +  _beginBatch: function BPP__beginBatch() {
   1.404 +    if (this._batching)
   1.405 +      return;
   1.406 +
   1.407 +    PlacesUtils.transactionManager.beginBatch(null);
   1.408 +    this._batching = true;
   1.409 +  },
   1.410 +
   1.411 +  _endBatch: function BPP__endBatch() {
   1.412 +    if (!this._batching)
   1.413 +      return;
   1.414 +
   1.415 +    PlacesUtils.transactionManager.endBatch(false);
   1.416 +    this._batching = false;
   1.417 +  },
   1.418 +
   1.419 +  _fillEditProperties: function BPP__fillEditProperties() {
   1.420 +    gEditItemOverlay.initPanel(this._itemId,
   1.421 +                               { hiddenRows: this._hiddenRows,
   1.422 +                                 forceReadOnly: this._readOnly });
   1.423 +  },
   1.424 +
   1.425 +  _fillAddProperties: function BPP__fillAddProperties() {
   1.426 +    this._createNewItem();
   1.427 +    // Edit the new item
   1.428 +    gEditItemOverlay.initPanel(this._itemId,
   1.429 +                               { hiddenRows: this._hiddenRows });
   1.430 +    // Empty location field if the uri is about:blank, this way inserting a new
   1.431 +    // url will be easier for the user, Accept button will be automatically
   1.432 +    // disabled by the input listener until the user fills the field.
   1.433 +    var locationField = this._element("locationField");
   1.434 +    if (locationField.value == "about:blank")
   1.435 +      locationField.value = "";
   1.436 +  },
   1.437 +
   1.438 +  // nsISupports
   1.439 +  QueryInterface: function BPP_QueryInterface(aIID) {
   1.440 +    if (aIID.equals(Ci.nsIDOMEventListener) ||
   1.441 +        aIID.equals(Ci.nsISupports))
   1.442 +      return this;
   1.443 +
   1.444 +    throw Cr.NS_NOINTERFACE;
   1.445 +  },
   1.446 +
   1.447 +  _element: function BPP__element(aID) {
   1.448 +    return document.getElementById("editBMPanel_" + aID);
   1.449 +  },
   1.450 +
   1.451 +  onDialogUnload: function BPP_onDialogUnload() {
   1.452 +    // gEditItemOverlay does not exist anymore here, so don't rely on it.
   1.453 +    // Calling removeEventListener with arguments which do not identify any
   1.454 +    // currently registered EventListener on the EventTarget has no effect.
   1.455 +    this._element("tagsSelectorRow")
   1.456 +        .removeEventListener("DOMAttrModified", this, false);
   1.457 +    this._element("folderTreeRow")
   1.458 +        .removeEventListener("DOMAttrModified", this, false);
   1.459 +    this._element("locationField")
   1.460 +        .removeEventListener("input", this, false);
   1.461 +    this._element("feedLocationField")
   1.462 +        .removeEventListener("input", this, false);
   1.463 +    this._element("siteLocationField")
   1.464 +        .removeEventListener("input", this, false);
   1.465 +  },
   1.466 +
   1.467 +  onDialogAccept: function BPP_onDialogAccept() {
   1.468 +    // We must blur current focused element to save its changes correctly
   1.469 +    document.commandDispatcher.focusedElement.blur();
   1.470 +    // The order here is important! We have to uninit the panel first, otherwise
   1.471 +    // late changes could force it to commit more transactions.
   1.472 +    gEditItemOverlay.uninitPanel(true);
   1.473 +    gEditItemOverlay = null;
   1.474 +    this._endBatch();
   1.475 +    window.arguments[0].performed = true;
   1.476 +  },
   1.477 +
   1.478 +  onDialogCancel: function BPP_onDialogCancel() {
   1.479 +    // The order here is important! We have to uninit the panel first, otherwise
   1.480 +    // changes done as part of Undo may change the panel contents and by
   1.481 +    // that force it to commit more transactions.
   1.482 +    gEditItemOverlay.uninitPanel(true);
   1.483 +    gEditItemOverlay = null;
   1.484 +    this._endBatch();
   1.485 +    PlacesUtils.transactionManager.undoTransaction();
   1.486 +    window.arguments[0].performed = false;
   1.487 +  },
   1.488 +
   1.489 +  /**
   1.490 +   * This method checks to see if the input fields are in a valid state.
   1.491 +   *
   1.492 +   * @returns  true if the input is valid, false otherwise
   1.493 +   */
   1.494 +  _inputIsValid: function BPP__inputIsValid() {
   1.495 +    if (this._itemType == BOOKMARK_ITEM &&
   1.496 +        !this._containsValidURI("locationField"))
   1.497 +      return false;
   1.498 +    if (this._isAddKeywordDialog && !this._element("keywordField").value.length)
   1.499 +      return false;
   1.500 +
   1.501 +    return true;
   1.502 +  },
   1.503 +
   1.504 +  /**
   1.505 +   * Determines whether the XUL textbox with the given ID contains a
   1.506 +   * string that can be converted into an nsIURI.
   1.507 +   *
   1.508 +   * @param aTextboxID
   1.509 +   *        the ID of the textbox element whose contents we'll test
   1.510 +   *
   1.511 +   * @returns true if the textbox contains a valid URI string, false otherwise
   1.512 +   */
   1.513 +  _containsValidURI: function BPP__containsValidURI(aTextboxID) {
   1.514 +    try {
   1.515 +      var value = this._element(aTextboxID).value;
   1.516 +      if (value) {
   1.517 +        PlacesUIUtils.createFixedURI(value);
   1.518 +        return true;
   1.519 +      }
   1.520 +    } catch (e) { }
   1.521 +    return false;
   1.522 +  },
   1.523 +
   1.524 +  /**
   1.525 +   * [New Item Mode] Get the insertion point details for the new item, given
   1.526 +   * dialog state and opening arguments.
   1.527 +   *
   1.528 +   * The container-identifier and insertion-index are returned separately in
   1.529 +   * the form of [containerIdentifier, insertionIndex]
   1.530 +   */
   1.531 +  _getInsertionPointDetails: function BPP__getInsertionPointDetails() {
   1.532 +    var containerId = this._defaultInsertionPoint.itemId;
   1.533 +    var indexInContainer = this._defaultInsertionPoint.index;
   1.534 +
   1.535 +    return [containerId, indexInContainer];
   1.536 +  },
   1.537 +
   1.538 +  /**
   1.539 +   * Returns a transaction for creating a new bookmark item representing the
   1.540 +   * various fields and opening arguments of the dialog.
   1.541 +   */
   1.542 +  _getCreateNewBookmarkTransaction:
   1.543 +  function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
   1.544 +    var annotations = [];
   1.545 +    var childTransactions = [];
   1.546 +
   1.547 +    if (this._description) {
   1.548 +      let annoObj = { name   : PlacesUIUtils.DESCRIPTION_ANNO,
   1.549 +                      type   : Ci.nsIAnnotationService.TYPE_STRING,
   1.550 +                      flags  : 0,
   1.551 +                      value  : this._description,
   1.552 +                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
   1.553 +      let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
   1.554 +      childTransactions.push(editItemTxn);
   1.555 +    }
   1.556 +
   1.557 +    if (this._loadInSidebar) {
   1.558 +      let annoObj = { name   : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
   1.559 +                      value  : true };
   1.560 +      let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
   1.561 +      childTransactions.push(setLoadTxn);
   1.562 +    }
   1.563 +
   1.564 +    if (this._postData) {
   1.565 +      let postDataTxn = new PlacesEditBookmarkPostDataTransaction(-1, this._postData);
   1.566 +      childTransactions.push(postDataTxn);
   1.567 +    }
   1.568 +
   1.569 +    //XXX TODO: this should be in a transaction!
   1.570 +    if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window))
   1.571 +      PlacesUtils.setCharsetForURI(this._uri, this._charSet);
   1.572 +
   1.573 +    let createTxn = new PlacesCreateBookmarkTransaction(this._uri,
   1.574 +                                                        aContainer,
   1.575 +                                                        aIndex,
   1.576 +                                                        this._title,
   1.577 +                                                        this._keyword,
   1.578 +                                                        annotations,
   1.579 +                                                        childTransactions);
   1.580 +
   1.581 +    return new PlacesAggregatedTransaction(this._getDialogTitle(),
   1.582 +                                           [createTxn]);
   1.583 +  },
   1.584 +
   1.585 +  /**
   1.586 +   * Returns a childItems-transactions array representing the URIList with
   1.587 +   * which the dialog has been opened.
   1.588 +   */
   1.589 +  _getTransactionsForURIList: function BPP__getTransactionsForURIList() {
   1.590 +    var transactions = [];
   1.591 +    for (var i = 0; i < this._URIs.length; ++i) {
   1.592 +      var uri = this._URIs[i];
   1.593 +      var title = this._getURITitleFromHistory(uri);
   1.594 +      var createTxn = new PlacesCreateBookmarkTransaction(uri, -1, 
   1.595 +                                                          PlacesUtils.bookmarks.DEFAULT_INDEX,
   1.596 +                                                          title);
   1.597 +      transactions.push(createTxn);
   1.598 +    }
   1.599 +    return transactions; 
   1.600 +  },
   1.601 +
   1.602 +  /**
   1.603 +   * Returns a transaction for creating a new folder item representing the
   1.604 +   * various fields and opening arguments of the dialog.
   1.605 +   */
   1.606 +  _getCreateNewFolderTransaction:
   1.607 +  function BPP__getCreateNewFolderTransaction(aContainer, aIndex) {
   1.608 +    var annotations = [];
   1.609 +    var childItemsTransactions;
   1.610 +    if (this._URIs.length)
   1.611 +      childItemsTransactions = this._getTransactionsForURIList();
   1.612 +
   1.613 +    if (this._description)
   1.614 +      annotations.push(this._getDescriptionAnnotation(this._description));
   1.615 +
   1.616 +    return new PlacesCreateFolderTransaction(this._title, aContainer,
   1.617 +                                             aIndex, annotations,
   1.618 +                                             childItemsTransactions);
   1.619 +  },
   1.620 +
   1.621 +  /**
   1.622 +   * Returns a transaction for creating a new live-bookmark item representing
   1.623 +   * the various fields and opening arguments of the dialog.
   1.624 +   */
   1.625 +  _getCreateNewLivemarkTransaction:
   1.626 +  function BPP__getCreateNewLivemarkTransaction(aContainer, aIndex) {
   1.627 +    return new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI,
   1.628 +                                               this._title,
   1.629 +                                               aContainer, aIndex);
   1.630 +  },
   1.631 +
   1.632 +  /**
   1.633 +   * Dialog-accept code-path for creating a new item (any type)
   1.634 +   */
   1.635 +  _createNewItem: function BPP__getCreateItemTransaction() {
   1.636 +    var [container, index] = this._getInsertionPointDetails();
   1.637 +    var txn;
   1.638 +
   1.639 +    switch (this._itemType) {
   1.640 +      case BOOKMARK_FOLDER:
   1.641 +        txn = this._getCreateNewFolderTransaction(container, index);
   1.642 +        break;
   1.643 +      case LIVEMARK_CONTAINER:
   1.644 +        txn = this._getCreateNewLivemarkTransaction(container, index);
   1.645 +        break;      
   1.646 +      default: // BOOKMARK_ITEM
   1.647 +        txn = this._getCreateNewBookmarkTransaction(container, index);
   1.648 +    }
   1.649 +
   1.650 +    PlacesUtils.transactionManager.doTransaction(txn);
   1.651 +    this._itemId = PlacesUtils.bookmarks.getIdForItemAt(container, index);
   1.652 +  }
   1.653 +};

mercurial