mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 15:15:23 +00:00
161 lines
5.0 KiB
JavaScript
161 lines
5.0 KiB
JavaScript
/* 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 { Ci, Cc } = require("chrome");
|
|
const { Services } = require("resource://gre/modules/Services.jsm");
|
|
const { DOMHelpers } = require("resource:///modules/devtools/DOMHelpers.jsm");
|
|
const { Task } = require("resource://gre/modules/Task.jsm");
|
|
const { Promise } = require("resource://gre/modules/Promise.jsm");
|
|
const { setTimeout } = require("sdk/timers");
|
|
const { getMostRecentBrowserWindow } = require("sdk/window/utils");
|
|
|
|
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
const DEV_EDITION_PROMO_URL = "chrome://browser/content/devtools/framework/dev-edition-promo.xul";
|
|
const DEV_EDITION_PROMO_ENABLED_PREF = "devtools.devedition.promo.enabled";
|
|
const DEV_EDITION_PROMO_SHOWN_PREF = "devtools.devedition.promo.shown";
|
|
const DEV_EDITION_PROMO_URL_PREF = "devtools.devedition.promo.url";
|
|
const LOCALE = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
|
.getService(Ci.nsIXULChromeRegistry)
|
|
.getSelectedLocale("global");
|
|
|
|
/**
|
|
* Only show Dev Edition promo if it's enabled (beta channel),
|
|
* if it has not been shown before, and it's a locale build
|
|
* for `en-US`
|
|
*/
|
|
function shouldDevEditionPromoShow () {
|
|
return Services.prefs.getBoolPref(DEV_EDITION_PROMO_ENABLED_PREF) &&
|
|
!Services.prefs.getBoolPref(DEV_EDITION_PROMO_SHOWN_PREF) &&
|
|
LOCALE === "en-US";
|
|
}
|
|
|
|
let TYPES = {
|
|
// The Developer Edition promo doorhanger, called by
|
|
// opening the toolbox, browser console, WebIDE, or responsive design mode
|
|
// in Beta releases. Only displayed once per profile.
|
|
deveditionpromo: {
|
|
predicate: shouldDevEditionPromoShow,
|
|
success: () => Services.prefs.setBoolPref(DEV_EDITION_PROMO_SHOWN_PREF, true),
|
|
action: () => {
|
|
let url = Services.prefs.getCharPref(DEV_EDITION_PROMO_URL_PREF);
|
|
getGBrowser().selectedTab = getGBrowser().addTab(url);
|
|
},
|
|
url: DEV_EDITION_PROMO_URL
|
|
}
|
|
};
|
|
|
|
let panelAttrs = {
|
|
orient: "vertical",
|
|
hidden: "false",
|
|
consumeoutsideclicks: "true",
|
|
noautofocus: "true",
|
|
align: "start",
|
|
role: "alert"
|
|
};
|
|
|
|
/**
|
|
* Helper to call a doorhanger, defined in `TYPES`, with defined conditions,
|
|
* success handlers and loads its own XUL in a frame. Takes an object with
|
|
* several properties:
|
|
*
|
|
* @param {XULWindow} window
|
|
* The window that should house the doorhanger.
|
|
* @param {String} type
|
|
* The type of doorhanger to be displayed is, using the `TYPES` definition.
|
|
* @param {String} selector
|
|
* The selector that the doorhanger should be appended to within `window`.
|
|
* Defaults to a XUL Document's `window` element.
|
|
*/
|
|
exports.showDoorhanger = Task.async(function *({ window, type, anchor }) {
|
|
let { predicate, success, url, action } = TYPES[type];
|
|
// Abort if predicate fails
|
|
if (!predicate()) {
|
|
return;
|
|
}
|
|
|
|
// Call success function to set preferences/cleanup immediately,
|
|
// so if triggered multiple times, only happens once (Windows/Linux)
|
|
success();
|
|
|
|
// Wait 200ms to prevent flickering where the popup is displayed
|
|
// before the underlying window (Windows 7, 64bit)
|
|
yield wait(200);
|
|
|
|
let document = window.document;
|
|
|
|
let panel = document.createElementNS(XULNS, "panel");
|
|
let frame = document.createElementNS(XULNS, "iframe");
|
|
let parentEl = document.querySelector("window");
|
|
|
|
frame.setAttribute("src", url);
|
|
let close = () => parentEl.removeChild(panel);
|
|
|
|
setDoorhangerStyle(panel, frame);
|
|
|
|
panel.appendChild(frame);
|
|
parentEl.appendChild(panel);
|
|
|
|
yield onFrameLoad(frame);
|
|
|
|
panel.openPopup(anchor);
|
|
|
|
let closeBtn = frame.contentDocument.querySelector("#close");
|
|
if (closeBtn) {
|
|
closeBtn.addEventListener("click", close);
|
|
}
|
|
|
|
let goBtn = frame.contentDocument.querySelector("#go");
|
|
if (goBtn) {
|
|
goBtn.addEventListener("click", () => {
|
|
if (action) {
|
|
action();
|
|
}
|
|
close();
|
|
});
|
|
}
|
|
});
|
|
|
|
function setDoorhangerStyle (panel, frame) {
|
|
Object.keys(panelAttrs).forEach(prop => panel.setAttribute(prop, panelAttrs[prop]));
|
|
panel.style.margin = "20px";
|
|
panel.style.borderRadius = "5px";
|
|
panel.style.border = "none";
|
|
panel.style.MozAppearance = "none";
|
|
panel.style.backgroundColor = "transparent";
|
|
|
|
frame.style.borderRadius = "5px";
|
|
frame.setAttribute("flex", "1");
|
|
frame.setAttribute("width", "450");
|
|
frame.setAttribute("height", "179");
|
|
}
|
|
|
|
function onFrameLoad (frame) {
|
|
let { resolve, promise } = Promise.defer();
|
|
|
|
if (frame.contentWindow) {
|
|
let domHelper = new DOMHelpers(frame.contentWindow);
|
|
domHelper.onceDOMReady(resolve);
|
|
} else {
|
|
let callback = () => {
|
|
frame.removeEventListener("DOMContentLoaded", callback);
|
|
resolve();
|
|
}
|
|
frame.addEventListener("DOMContentLoaded", callback);
|
|
}
|
|
|
|
return promise;
|
|
}
|
|
|
|
function getGBrowser () {
|
|
return getMostRecentBrowserWindow().gBrowser;
|
|
}
|
|
|
|
function wait (n) {
|
|
let { resolve, promise } = Promise.defer();
|
|
setTimeout(resolve, n);
|
|
return promise;
|
|
}
|