michael@0: #ifdef 0
michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0: #endif
michael@0:
michael@0: /**
michael@0: * This singleton represents the grid that contains all sites.
michael@0: */
michael@0: let gGrid = {
michael@0: /**
michael@0: * The DOM node of the grid.
michael@0: */
michael@0: _node: null,
michael@0: get node() this._node,
michael@0:
michael@0: /**
michael@0: * The cached DOM fragment for sites.
michael@0: */
michael@0: _siteFragment: null,
michael@0:
michael@0: /**
michael@0: * All cells contained in the grid.
michael@0: */
michael@0: _cells: null,
michael@0: get cells() this._cells,
michael@0:
michael@0: /**
michael@0: * All sites contained in the grid's cells. Sites may be empty.
michael@0: */
michael@0: get sites() [cell.site for each (cell in this.cells)],
michael@0:
michael@0: // Tells whether the grid has already been initialized.
michael@0: get ready() !!this._node,
michael@0:
michael@0: /**
michael@0: * Initializes the grid.
michael@0: * @param aSelector The query selector of the grid.
michael@0: */
michael@0: init: function Grid_init() {
michael@0: this._node = document.getElementById("newtab-grid");
michael@0: this._createSiteFragment();
michael@0: this._render();
michael@0: },
michael@0:
michael@0: /**
michael@0: * Creates a new site in the grid.
michael@0: * @param aLink The new site's link.
michael@0: * @param aCell The cell that will contain the new site.
michael@0: * @return The newly created site.
michael@0: */
michael@0: createSite: function Grid_createSite(aLink, aCell) {
michael@0: let node = aCell.node;
michael@0: node.appendChild(this._siteFragment.cloneNode(true));
michael@0: return new Site(node.firstElementChild, aLink);
michael@0: },
michael@0:
michael@0: /**
michael@0: * Refreshes the grid and re-creates all sites.
michael@0: */
michael@0: refresh: function Grid_refresh() {
michael@0: // Remove all sites.
michael@0: this.cells.forEach(function (cell) {
michael@0: let node = cell.node;
michael@0: let child = node.firstElementChild;
michael@0:
michael@0: if (child)
michael@0: node.removeChild(child);
michael@0: }, this);
michael@0:
michael@0: // Render the grid again.
michael@0: this._render();
michael@0: },
michael@0:
michael@0: /**
michael@0: * Locks the grid to block all pointer events.
michael@0: */
michael@0: lock: function Grid_lock() {
michael@0: this.node.setAttribute("locked", "true");
michael@0: },
michael@0:
michael@0: /**
michael@0: * Unlocks the grid to allow all pointer events.
michael@0: */
michael@0: unlock: function Grid_unlock() {
michael@0: this.node.removeAttribute("locked");
michael@0: },
michael@0:
michael@0: /**
michael@0: * Creates the newtab grid.
michael@0: */
michael@0: _renderGrid: function Grid_renderGrid() {
michael@0: let row = document.createElementNS(HTML_NAMESPACE, "div");
michael@0: let cell = document.createElementNS(HTML_NAMESPACE, "div");
michael@0: row.classList.add("newtab-row");
michael@0: cell.classList.add("newtab-cell");
michael@0:
michael@0: // Clear the grid
michael@0: this._node.innerHTML = "";
michael@0:
michael@0: // Creates the structure of one row
michael@0: for (let i = 0; i < gGridPrefs.gridColumns; i++) {
michael@0: row.appendChild(cell.cloneNode(true));
michael@0: }
michael@0: // Creates the grid
michael@0: for (let j = 0; j < gGridPrefs.gridRows; j++) {
michael@0: this._node.appendChild(row.cloneNode(true));
michael@0: }
michael@0:
michael@0: // (Re-)initialize all cells.
michael@0: let cellElements = this.node.querySelectorAll(".newtab-cell");
michael@0: this._cells = [new Cell(this, cell) for (cell of cellElements)];
michael@0: },
michael@0:
michael@0: /**
michael@0: * Creates the DOM fragment that is re-used when creating sites.
michael@0: */
michael@0: _createSiteFragment: function Grid_createSiteFragment() {
michael@0: let site = document.createElementNS(HTML_NAMESPACE, "div");
michael@0: site.classList.add("newtab-site");
michael@0: site.setAttribute("draggable", "true");
michael@0:
michael@0: // Create the site's inner HTML code.
michael@0: site.innerHTML =
michael@0: '' +
michael@0: ' ' +
michael@0: ' ' +
michael@0: '' +
michael@0: '' +
michael@0: '' +
michael@0: '';
michael@0:
michael@0: this._siteFragment = document.createDocumentFragment();
michael@0: this._siteFragment.appendChild(site);
michael@0: },
michael@0:
michael@0: /**
michael@0: * Renders the sites, creates all sites and puts them into their cells.
michael@0: */
michael@0: _renderSites: function Grid_renderSites() {
michael@0: let cells = this.cells;
michael@0: // Put sites into the cells.
michael@0: let links = gLinks.getLinks();
michael@0: let length = Math.min(links.length, cells.length);
michael@0:
michael@0: for (let i = 0; i < length; i++) {
michael@0: if (links[i])
michael@0: this.createSite(links[i], cells[i]);
michael@0: }
michael@0: },
michael@0:
michael@0: /**
michael@0: * Renders the grid.
michael@0: */
michael@0: _render: function Grid_render() {
michael@0: if (this._shouldRenderGrid()) {
michael@0: this._renderGrid();
michael@0: }
michael@0:
michael@0: this._renderSites();
michael@0: },
michael@0:
michael@0: _shouldRenderGrid : function Grid_shouldRenderGrid() {
michael@0: let rowsLength = this._node.querySelectorAll(".newtab-row").length;
michael@0: let cellsLength = this._node.querySelectorAll(".newtab-cell").length;
michael@0:
michael@0: return (rowsLength != gGridPrefs.gridRows ||
michael@0: cellsLength != (gGridPrefs.gridRows * gGridPrefs.gridColumns));
michael@0: }
michael@0: };