browser/base/content/newtab/dropPreview.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/base/content/newtab/dropPreview.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,222 @@
     1.4 +#ifdef 0
     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 file,
     1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +#endif
     1.9 +
    1.10 +/**
    1.11 + * This singleton provides the ability to re-arrange the current grid to
    1.12 + * indicate the transformation that results from dropping a cell at a certain
    1.13 + * position.
    1.14 + */
    1.15 +let gDropPreview = {
    1.16 +  /**
    1.17 +   * Rearranges the sites currently contained in the grid when a site would be
    1.18 +   * dropped onto the given cell.
    1.19 +   * @param aCell The drop target cell.
    1.20 +   * @return The re-arranged array of sites.
    1.21 +   */
    1.22 +  rearrange: function DropPreview_rearrange(aCell) {
    1.23 +    let sites = gGrid.sites;
    1.24 +
    1.25 +    // Insert the dragged site into the current grid.
    1.26 +    this._insertDraggedSite(sites, aCell);
    1.27 +
    1.28 +    // After the new site has been inserted we need to correct the positions
    1.29 +    // of all pinned tabs that have been moved around.
    1.30 +    this._repositionPinnedSites(sites, aCell);
    1.31 +
    1.32 +    return sites;
    1.33 +  },
    1.34 +
    1.35 +  /**
    1.36 +   * Inserts the currently dragged site into the given array of sites.
    1.37 +   * @param aSites The array of sites to insert into.
    1.38 +   * @param aCell The drop target cell.
    1.39 +   */
    1.40 +  _insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) {
    1.41 +    let dropIndex = aCell.index;
    1.42 +    let draggedSite = gDrag.draggedSite;
    1.43 +
    1.44 +    // We're currently dragging a site.
    1.45 +    if (draggedSite) {
    1.46 +      let dragCell = draggedSite.cell;
    1.47 +      let dragIndex = dragCell.index;
    1.48 +
    1.49 +      // Move the dragged site into its new position.
    1.50 +      if (dragIndex != dropIndex) {
    1.51 +        aSites.splice(dragIndex, 1);
    1.52 +        aSites.splice(dropIndex, 0, draggedSite);
    1.53 +      }
    1.54 +    // We're handling an external drag item.
    1.55 +    } else {
    1.56 +      aSites.splice(dropIndex, 0, null);
    1.57 +    }
    1.58 +  },
    1.59 +
    1.60 +  /**
    1.61 +   * Correct the position of all pinned sites that might have been moved to
    1.62 +   * different positions after the dragged site has been inserted.
    1.63 +   * @param aSites The array of sites containing the dragged site.
    1.64 +   * @param aCell The drop target cell.
    1.65 +   */
    1.66 +  _repositionPinnedSites:
    1.67 +    function DropPreview_repositionPinnedSites(aSites, aCell) {
    1.68 +
    1.69 +    // Collect all pinned sites.
    1.70 +    let pinnedSites = this._filterPinnedSites(aSites, aCell);
    1.71 +
    1.72 +    // Correct pinned site positions.
    1.73 +    pinnedSites.forEach(function (aSite) {
    1.74 +      aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index];
    1.75 +      aSites[aSite.cell.index] = aSite;
    1.76 +    }, this);
    1.77 +
    1.78 +    // There might be a pinned cell that got pushed out of the grid, try to
    1.79 +    // sneak it in by removing a lower-priority cell.
    1.80 +    if (this._hasOverflowedPinnedSite(aSites, aCell))
    1.81 +      this._repositionOverflowedPinnedSite(aSites, aCell);
    1.82 +  },
    1.83 +
    1.84 +  /**
    1.85 +   * Filter pinned sites out of the grid that are still on their old positions
    1.86 +   * and have not moved.
    1.87 +   * @param aSites The array of sites to filter.
    1.88 +   * @param aCell The drop target cell.
    1.89 +   * @return The filtered array of sites.
    1.90 +   */
    1.91 +  _filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) {
    1.92 +    let draggedSite = gDrag.draggedSite;
    1.93 +
    1.94 +    // When dropping on a cell that contains a pinned site make sure that all
    1.95 +    // pinned cells surrounding the drop target are moved as well.
    1.96 +    let range = this._getPinnedRange(aCell);
    1.97 +
    1.98 +    return aSites.filter(function (aSite, aIndex) {
    1.99 +      // The site must be valid, pinned and not the dragged site.
   1.100 +      if (!aSite || aSite == draggedSite || !aSite.isPinned())
   1.101 +        return false;
   1.102 +
   1.103 +      let index = aSite.cell.index;
   1.104 +
   1.105 +      // If it's not in the 'pinned range' it's a valid pinned site.
   1.106 +      return (index > range.end || index < range.start);
   1.107 +    });
   1.108 +  },
   1.109 +
   1.110 +  /**
   1.111 +   * Determines the range of pinned sites surrounding the drop target cell.
   1.112 +   * @param aCell The drop target cell.
   1.113 +   * @return The range of pinned cells.
   1.114 +   */
   1.115 +  _getPinnedRange: function DropPreview_getPinnedRange(aCell) {
   1.116 +    let dropIndex = aCell.index;
   1.117 +    let range = {start: dropIndex, end: dropIndex};
   1.118 +
   1.119 +    // We need a pinned range only when dropping on a pinned site.
   1.120 +    if (aCell.containsPinnedSite()) {
   1.121 +      let links = gPinnedLinks.links;
   1.122 +
   1.123 +      // Find all previous siblings of the drop target that are pinned as well.
   1.124 +      while (range.start && links[range.start - 1])
   1.125 +        range.start--;
   1.126 +
   1.127 +      let maxEnd = links.length - 1;
   1.128 +
   1.129 +      // Find all next siblings of the drop target that are pinned as well.
   1.130 +      while (range.end < maxEnd && links[range.end + 1])
   1.131 +        range.end++;
   1.132 +    }
   1.133 +
   1.134 +    return range;
   1.135 +  },
   1.136 +
   1.137 +  /**
   1.138 +   * Checks if the given array of sites contains a pinned site that has
   1.139 +   * been pushed out of the grid.
   1.140 +   * @param aSites The array of sites to check.
   1.141 +   * @param aCell The drop target cell.
   1.142 +   * @return Whether there is an overflowed pinned cell.
   1.143 +   */
   1.144 +  _hasOverflowedPinnedSite:
   1.145 +    function DropPreview_hasOverflowedPinnedSite(aSites, aCell) {
   1.146 +
   1.147 +    // If the drop target isn't pinned there's no way a pinned site has been
   1.148 +    // pushed out of the grid so we can just exit here.
   1.149 +    if (!aCell.containsPinnedSite())
   1.150 +      return false;
   1.151 +
   1.152 +    let cells = gGrid.cells;
   1.153 +
   1.154 +    // No cells have been pushed out of the grid, nothing to do here.
   1.155 +    if (aSites.length <= cells.length)
   1.156 +      return false;
   1.157 +
   1.158 +    let overflowedSite = aSites[cells.length];
   1.159 +
   1.160 +    // Nothing to do if the site that got pushed out of the grid is not pinned.
   1.161 +    return (overflowedSite && overflowedSite.isPinned());
   1.162 +  },
   1.163 +
   1.164 +  /**
   1.165 +   * We have a overflowed pinned site that we need to re-position so that it's
   1.166 +   * visible again. We try to find a lower-priority cell (empty or containing
   1.167 +   * an unpinned site) that we can move it to.
   1.168 +   * @param aSites The array of sites.
   1.169 +   * @param aCell The drop target cell.
   1.170 +   */
   1.171 +  _repositionOverflowedPinnedSite:
   1.172 +    function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) {
   1.173 +
   1.174 +    // Try to find a lower-priority cell (empty or containing an unpinned site).
   1.175 +    let index = this._indexOfLowerPrioritySite(aSites, aCell);
   1.176 +
   1.177 +    if (index > -1) {
   1.178 +      let cells = gGrid.cells;
   1.179 +      let dropIndex = aCell.index;
   1.180 +
   1.181 +      // Move all pinned cells to their new positions to let the overflowed
   1.182 +      // site fit into the grid.
   1.183 +      for (let i = index + 1, lastPosition = index; i < aSites.length; i++) {
   1.184 +        if (i != dropIndex) {
   1.185 +          aSites[lastPosition] = aSites[i];
   1.186 +          lastPosition = i;
   1.187 +        }
   1.188 +      }
   1.189 +
   1.190 +      // Finally, remove the overflowed site from its previous position.
   1.191 +      aSites.splice(cells.length, 1);
   1.192 +    }
   1.193 +  },
   1.194 +
   1.195 +  /**
   1.196 +   * Finds the index of the last cell that is empty or contains an unpinned
   1.197 +   * site. These are considered to be of a lower priority.
   1.198 +   * @param aSites The array of sites.
   1.199 +   * @param aCell The drop target cell.
   1.200 +   * @return The cell's index.
   1.201 +   */
   1.202 +  _indexOfLowerPrioritySite:
   1.203 +    function DropPreview_indexOfLowerPrioritySite(aSites, aCell) {
   1.204 +
   1.205 +    let cells = gGrid.cells;
   1.206 +    let dropIndex = aCell.index;
   1.207 +
   1.208 +    // Search (beginning with the last site in the grid) for a site that is
   1.209 +    // empty or unpinned (an thus lower-priority) and can be pushed out of the
   1.210 +    // grid instead of the pinned site.
   1.211 +    for (let i = cells.length - 1; i >= 0; i--) {
   1.212 +      // The cell that is our drop target is not a good choice.
   1.213 +      if (i == dropIndex)
   1.214 +        continue;
   1.215 +
   1.216 +      let site = aSites[i];
   1.217 +
   1.218 +      // We can use the cell only if it's empty or the site is un-pinned.
   1.219 +      if (!site || !site.isPinned())
   1.220 +        return i;
   1.221 +    }
   1.222 +
   1.223 +    return -1;
   1.224 +  }
   1.225 +};

mercurial