Blob Blame History Raw
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const promise = require("devtools/shared/deprecated-sync-thenables");

const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const eventSource = require("devtools/shared/client/event-source");
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");

const noop = () => {};

/**
 * Creates a tab client for the remote debugging protocol server. This client
 * is a front to the tab actor created in the server side, hiding the protocol
 * details in a traditional JavaScript API.
 *
 * @param client DebuggerClient
 *        The debugger client parent.
 * @param form object
 *        The protocol form for this tab.
 */
function TabClient(client, form) {
  this.client = client;
  this._actor = form.from;
  this._threadActor = form.threadActor;
  this.javascriptEnabled = form.javascriptEnabled;
  this.cacheDisabled = form.cacheDisabled;
  this.thread = null;
  this.request = this.client.request;
  this.traits = form.traits || {};
  this.events = ["workerListChanged"];
}

TabClient.prototype = {
  get actor() {
    return this._actor;
  },
  get _transport() {
    return this.client._transport;
  },

  /**
   * Attach to a thread actor.
   *
   * @param object options
   *        Configuration options.
   *        - useSourceMaps: whether to use source maps or not.
   * @param function onResponse
   *        Called with the response packet and a ThreadClient
   *        (which will be undefined on error).
   */
  attachThread: function (options = {}, onResponse = noop) {
    if (this.thread) {
      DevToolsUtils.executeSoon(() => onResponse({}, this.thread));
      return promise.resolve([{}, this.thread]);
    }

    let packet = {
      to: this._threadActor,
      type: "attach",
      options,
    };
    return this.request(packet).then(response => {
      if (!response.error) {
        this.thread = new ThreadClient(this, this._threadActor);
        this.client.registerClient(this.thread);
      }
      onResponse(response, this.thread);
      return [response, this.thread];
    });
  },

  /**
   * Detach the client from the tab actor.
   *
   * @param function onResponse
   *        Called with the response packet.
   */
  detach: DebuggerClient.requester({
    type: "detach"
  }, {
    before: function (packet) {
      if (this.thread) {
        this.thread.detach();
      }
      return packet;
    },
    after: function (response) {
      this.client.unregisterClient(this);
      return response;
    },
  }),

  /**
   * Bring the window to the front.
   */
  focus: DebuggerClient.requester({
    type: "focus"
  }, {}),

  /**
   * Reload the page in this tab.
   *
   * @param [optional] object options
   *        An object with a `force` property indicating whether or not
   *        this reload should skip the cache
   */
  reload: function (options = { force: false }) {
    return this._reload(options);
  },
  _reload: DebuggerClient.requester({
    type: "reload",
    options: arg(0)
  }),

  /**
   * Navigate to another URL.
   *
   * @param string url
   *        The URL to navigate to.
   */
  navigateTo: DebuggerClient.requester({
    type: "navigateTo",
    url: arg(0)
  }),

  /**
   * Reconfigure the tab actor.
   *
   * @param object options
   *        A dictionary object of the new options to use in the tab actor.
   * @param function onResponse
   *        Called with the response packet.
   */
  reconfigure: DebuggerClient.requester({
    type: "reconfigure",
    options: arg(0)
  }),

  listWorkers: DebuggerClient.requester({
    type: "listWorkers"
  }),

  attachWorker: function (workerActor, onResponse) {
    return this.client.attachWorker(workerActor, onResponse);
  },
};

eventSource(TabClient.prototype);

module.exports = TabClient;