All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.dirigible.dev-tools.resources.ApplicationCacheItemsView.js Maven / Gradle / Ivy

There is a newer version: 10.6.27
Show newest version
/*
 * Copyright (C) 2010 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

import * as Common from '../common/common.js';
import * as DataGrid from '../data_grid/data_grid.js';
import * as UI from '../ui/ui.js';

import {CHECKING, DOWNLOADING, IDLE, OBSOLETE, UNCACHED, UPDATEREADY} from './ApplicationCacheModel.js';

/**
 * @unrestricted
 */
export class ApplicationCacheItemsView extends UI.View.SimpleView {
  constructor(model, frameId) {
    super(Common.UIString.UIString('AppCache'));

    this._model = model;

    this.element.classList.add('storage-view', 'table');

    this._deleteButton = new UI.Toolbar.ToolbarButton(Common.UIString.UIString('Delete'), 'largeicon-delete');
    this._deleteButton.setVisible(false);
    this._deleteButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._deleteButtonClicked, this);

    this._connectivityIcon = createElement('span', 'dt-icon-label');
    this._connectivityIcon.style.margin = '0 2px 0 5px';
    this._statusIcon = createElement('span', 'dt-icon-label');
    this._statusIcon.style.margin = '0 2px 0 5px';

    this._frameId = frameId;

    this._emptyWidget =
        new UI.EmptyWidget.EmptyWidget(Common.UIString.UIString('No Application Cache information available.'));
    this._emptyWidget.show(this.element);

    this._markDirty();

    const status = this._model.frameManifestStatus(frameId);
    this.updateStatus(status);
    this.updateNetworkState(this._model.onLine);

    // FIXME: Status bar items don't work well enough yet, so they are being hidden.
    // http://webkit.org/b/41637 Web Inspector: Give Semantics to "Refresh" and "Delete" Buttons in ApplicationCache DataGrid
    this._deleteButton.element.style.display = 'none';
  }

  /**
   * @override
   * @return {!Promise>}
   */
  async toolbarItems() {
    return [
      this._deleteButton, new UI.Toolbar.ToolbarItem(this._connectivityIcon), new UI.Toolbar.ToolbarSeparator(),
      new UI.Toolbar.ToolbarItem(this._statusIcon)
    ];
  }

  /**
   * @override
   */
  wasShown() {
    this._maybeUpdate();
  }

  /**
   * @override
   */
  willHide() {
    this._deleteButton.setVisible(false);
  }

  _maybeUpdate() {
    if (!this.isShowing() || !this._viewDirty) {
      return;
    }

    this._update();
    this._viewDirty = false;
  }

  _markDirty() {
    this._viewDirty = true;
  }

  /**
   * @param {number} status
   */
  updateStatus(status) {
    const oldStatus = this._status;
    this._status = status;

    const statusInformation = {};
    // We should never have UNCACHED status, since we remove frames with UNCACHED application cache status from the tree.
    statusInformation[UNCACHED] = {type: 'smallicon-red-ball', text: 'UNCACHED'};
    statusInformation[IDLE] = {type: 'smallicon-green-ball', text: 'IDLE'};
    statusInformation[CHECKING] = {type: 'smallicon-orange-ball', text: 'CHECKING'};
    statusInformation[DOWNLOADING] = {type: 'smallicon-orange-ball', text: 'DOWNLOADING'};
    statusInformation[UPDATEREADY] = {type: 'smallicon-green-ball', text: 'UPDATEREADY'};
    statusInformation[OBSOLETE] = {type: 'smallicon-red-ball', text: 'OBSOLETE'};

    const info = statusInformation[status] || statusInformation[UNCACHED];

    this._statusIcon.type = info.type;
    this._statusIcon.textContent = info.text;

    if (this.isShowing() && this._status === IDLE && (oldStatus === UPDATEREADY || !this._resources)) {
      this._markDirty();
    }
    this._maybeUpdate();
  }

  /**
   * @param {boolean} isNowOnline
   */
  updateNetworkState(isNowOnline) {
    if (isNowOnline) {
      this._connectivityIcon.type = 'smallicon-green-ball';
      this._connectivityIcon.textContent = Common.UIString.UIString('Online');
    } else {
      this._connectivityIcon.type = 'smallicon-red-ball';
      this._connectivityIcon.textContent = Common.UIString.UIString('Offline');
    }
  }

  async _update() {
    const applicationCache = await this._model.requestApplicationCache(this._frameId);

    if (!applicationCache || !applicationCache.manifestURL) {
      delete this._manifest;
      delete this._creationTime;
      delete this._updateTime;
      delete this._size;
      delete this._resources;

      this._emptyWidget.show(this.element);
      this._deleteButton.setVisible(false);
      if (this._dataGrid) {
        this._dataGrid.element.classList.add('hidden');
      }
      return;
    }
    // FIXME: are these variables needed anywhere else?
    this._manifest = applicationCache.manifestURL;
    this._creationTime = applicationCache.creationTime;
    this._updateTime = applicationCache.updateTime;
    this._size = applicationCache.size;
    this._resources = applicationCache.resources;

    if (!this._dataGrid) {
      this._createDataGrid();
    }

    this._populateDataGrid();
    this._dataGrid.autoSizeColumns(20, 80);
    this._dataGrid.element.classList.remove('hidden');
    this._emptyWidget.detach();
    this._deleteButton.setVisible(true);

    // FIXME: For Chrome, put creationTime and updateTime somewhere.
    // NOTE: localizedString has not yet been added.
    // Common.UIString.UIString("(%s) Created: %s Updated: %s", this._size, this._creationTime, this._updateTime);
  }

  _createDataGrid() {
    const columns = /** @type {!Array} */ ([
      {
        id: 'resource',
        title: Common.UIString.UIString('Resource'),
        sort: DataGrid.DataGrid.Order.Ascending,
        sortable: true
      },
      {id: 'type', title: Common.UIString.UIString('Type'), sortable: true},
      {id: 'size', title: Common.UIString.UIString('Size'), align: DataGrid.DataGrid.Align.Right, sortable: true}
    ]);
    this._dataGrid = new DataGrid.DataGrid.DataGridImpl({displayName: ls`Application Cache`, columns});
    this._dataGrid.setStriped(true);
    this._dataGrid.asWidget().show(this.element);
    this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged, this._populateDataGrid, this);
  }

  _populateDataGrid() {
    const selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
    const sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1;

    function numberCompare(field, resource1, resource2) {
      return sortDirection * (resource1[field] - resource2[field]);
    }
    function localeCompare(field, resource1, resource2) {
      return sortDirection * (resource1[field] + '').localeCompare(resource2[field] + '');
    }

    let comparator;
    switch (this._dataGrid.sortColumnId()) {
      case 'resource':
        comparator = localeCompare.bind(null, 'url');
        break;
      case 'type':
        comparator = localeCompare.bind(null, 'type');
        break;
      case 'size':
        comparator = numberCompare.bind(null, 'size');
        break;
      default:
        localeCompare.bind(null, 'resource');  // FIXME: comparator = ?
    }

    this._resources.sort(comparator);
    this._dataGrid.rootNode().removeChildren();

    let nodeToSelect;
    for (let i = 0; i < this._resources.length; ++i) {
      const data = {};
      const resource = this._resources[i];
      data.resource = resource.url;
      data.type = resource.type;
      data.size = Number.bytesToString(resource.size);
      const node = new DataGrid.DataGrid.DataGridNode(data);
      node.resource = resource;
      node.selectable = true;
      this._dataGrid.rootNode().appendChild(node);
      if (resource === selectedResource) {
        nodeToSelect = node;
        nodeToSelect.selected = true;
      }
    }

    if (!nodeToSelect && this._dataGrid.rootNode().children.length) {
      this._dataGrid.rootNode().children[0].selected = true;
    }
  }

  /**
   * @param {!Common.EventTarget.EventTargetEvent} event
   */
  _deleteButtonClicked(event) {
    if (!this._dataGrid || !this._dataGrid.selectedNode) {
      return;
    }

    // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
    this._deleteCallback(this._dataGrid.selectedNode);
  }

  _deleteCallback(node) {
    // FIXME: Should we delete a single (selected) resource or all resources?
    // ProtocolClient.inspectorBackend.deleteCachedResource(...)
    // this._update();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy