Merge fx-team to m-c
|
@ -1,7 +1,11 @@
|
|||
/* 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";
|
||||
|
||||
// Disable tests below for now.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=987348
|
||||
/*
|
||||
var m = require("main");
|
||||
var self = require("sdk/self");
|
||||
|
||||
|
@ -22,3 +26,4 @@ exports.testID = function(test) {
|
|||
test.assertEqual(self.data.url("sample.html"),
|
||||
"resource://reading-data-example-at-jetpack-dot-mozillalabs-dot-com/reading-data/data/sample.html");
|
||||
};
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
/* 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";
|
||||
|
||||
// Disable tests below for now.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=987348
|
||||
/*
|
||||
var m = require("main");
|
||||
var self = require("sdk/self");
|
||||
|
||||
|
@ -19,3 +23,4 @@ exports.testMain = function(test) {
|
|||
exports.testData = function(test) {
|
||||
test.assert(self.data.load("panel.js").length > 0);
|
||||
};
|
||||
*/
|
||||
|
|
|
@ -9,66 +9,124 @@ module.metadata = {
|
|||
};
|
||||
|
||||
|
||||
let { Class } = require("./heritage");
|
||||
let { on, off } = require('../system/events');
|
||||
let unloadSubject = require('@loader/unload');
|
||||
const { Class } = require("./heritage");
|
||||
const { Observer, subscribe, unsubscribe, observe } = require("./observer");
|
||||
const { isWeak, WeakReference } = require("./reference");
|
||||
const method = require("../../method/core");
|
||||
|
||||
let disposables = WeakMap();
|
||||
const unloadSubject = require('@loader/unload');
|
||||
const addonUnloadTopic = "sdk:loader:destroy";
|
||||
|
||||
function initialize(instance) {
|
||||
// Create an event handler that will dispose instance on unload.
|
||||
function handler(event) {
|
||||
if (event.subject.wrappedJSObject === unloadSubject) {
|
||||
instance.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// Form weak reference between disposable instance and an unload event
|
||||
// handler associated with it. This will make sure that event handler can't
|
||||
// be garbage collected as long as instance is referenced. Also note that
|
||||
// system events intentionally hold weak reference to an event handler, this
|
||||
// will let GC claim both instance and an unload handler before actual add-on
|
||||
// unload if instance contains no other references.
|
||||
disposables.set(instance, handler);
|
||||
on("sdk:loader:destroy", handler);
|
||||
}
|
||||
exports.initialize = initialize;
|
||||
|
||||
function dispose(instance) {
|
||||
// Disposes given instance by removing it from weak map so that handler can
|
||||
// be GC-ed even if references to instance are kept. Also unregister unload
|
||||
// handler.
|
||||
const uninstall = method("disposable/uninstall");
|
||||
exports.uninstall = uninstall;
|
||||
|
||||
let handler = disposables.get(instance);
|
||||
if (handler) off("sdk:loader:destroy", handler);
|
||||
disposables.delete(instance);
|
||||
}
|
||||
|
||||
const shutdown = method("disposable/shutdown");
|
||||
exports.shutdown = shutdown;
|
||||
|
||||
const disable = method("disposable/disable");
|
||||
exports.disable = disable;
|
||||
|
||||
const upgrade = method("disposable/upgrade");
|
||||
exports.upgrade = upgrade;
|
||||
|
||||
const downgrade = method("disposable/downgrade");
|
||||
exports.downgrade = downgrade;
|
||||
|
||||
const unload = method("disposable/unload");
|
||||
exports.unload = unload;
|
||||
|
||||
const dispose = method("disposable/dispose");
|
||||
exports.dispose = dispose;
|
||||
dispose.define(Object, object => object.dispose());
|
||||
|
||||
|
||||
const setup = method("disposable/setup");
|
||||
exports.setup = setup;
|
||||
setup.define(Object, (object, ...args) => object.setup(...args));
|
||||
|
||||
|
||||
// Set's up disposable instance.
|
||||
const setupDisposable = disposable => {
|
||||
subscribe(disposable, addonUnloadTopic, isWeak(disposable));
|
||||
};
|
||||
|
||||
// Tears down disposable instance.
|
||||
const disposeDisposable = disposable => {
|
||||
unsubscribe(disposable, addonUnloadTopic);
|
||||
};
|
||||
|
||||
// Base type that takes care of disposing it's instances on add-on unload.
|
||||
// Also makes sure to remove unload listener if it's already being disposed.
|
||||
let Disposable = Class({
|
||||
initialize: function setupDisposable() {
|
||||
const Disposable = Class({
|
||||
implements: [Observer],
|
||||
initialize: function(...args) {
|
||||
// First setup instance before initializing it's disposal. If instance
|
||||
// fails to initialize then there is no instance to be disposed at the
|
||||
// unload.
|
||||
this.setup.apply(this, arguments);
|
||||
initialize(this);
|
||||
setup(this, ...args);
|
||||
setupDisposable(this);
|
||||
},
|
||||
setup: function setup() {
|
||||
// Implement your initialize logic here.
|
||||
},
|
||||
dispose: function dispose() {
|
||||
// Implement your cleanup logic here.
|
||||
},
|
||||
|
||||
destroy: function destroy() {
|
||||
destroy: function(reason) {
|
||||
// Destroying disposable removes unload handler so that attempt to dispose
|
||||
// won't be made at unload & delegates to dispose.
|
||||
if (disposables.has(this)) {
|
||||
dispose(this);
|
||||
this.dispose();
|
||||
}
|
||||
disposeDisposable(this);
|
||||
unload(this, reason);
|
||||
},
|
||||
setup: function() {
|
||||
// Implement your initialize logic here.
|
||||
},
|
||||
dispose: function() {
|
||||
// Implement your cleanup logic here.
|
||||
}
|
||||
});
|
||||
exports.Disposable = Disposable;
|
||||
|
||||
// Disposable instances observe add-on unload notifications in
|
||||
// order to trigger `unload` on them.
|
||||
observe.define(Disposable, (disposable, subject, topic, data) => {
|
||||
const isUnloadTopic = topic === addonUnloadTopic;
|
||||
const isUnloadSubject = subject.wrappedJSObject === unloadSubject;
|
||||
if (isUnloadTopic && isUnloadSubject) {
|
||||
unsubscribe(disposable, topic);
|
||||
unload(disposable);
|
||||
}
|
||||
});
|
||||
|
||||
const unloaders = {
|
||||
destroy: dispose,
|
||||
uninstall: uninstall,
|
||||
shutdown: shutdown,
|
||||
disable: disable,
|
||||
upgrade: upgrade,
|
||||
downgrade: downgrade
|
||||
}
|
||||
const unloaded = new WeakMap();
|
||||
unload.define(Disposable, (disposable, reason) => {
|
||||
if (!unloaded.get(disposable)) {
|
||||
unloaded.set(disposable, true);
|
||||
// Pick an unload handler associated with an unload
|
||||
// reason (falling back to destroy if not found) and
|
||||
// delegate unloading to it.
|
||||
const unload = unloaders[reason] || unloaders.destroy;
|
||||
unload(disposable);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// If add-on is disabled munally, it's being upgraded, downgraded
|
||||
// or uniststalled `dispose` is invoked to undo any changes that
|
||||
// has being done by it in this session.
|
||||
disable.define(Disposable, dispose);
|
||||
downgrade.define(Disposable, dispose);
|
||||
upgrade.define(Disposable, dispose);
|
||||
uninstall.define(Disposable, dispose);
|
||||
|
||||
// If application is shut down no dispose is invoked as undo-ing
|
||||
// changes made by instance is likely to just waste of resources &
|
||||
// increase shutdown time. Although specefic components may choose
|
||||
// to implement shutdown handler that does something better.
|
||||
shutdown.define(Disposable, disposable => {});
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
|
||||
const { Cc, Ci, Cr } = require("chrome");
|
||||
const { Class } = require("./heritage");
|
||||
const { isWeak } = require("./reference");
|
||||
const method = require("../../method/core");
|
||||
|
||||
const { addObserver, removeObserver } = Cc['@mozilla.org/observer-service;1'].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
|
||||
// This is a method that will be invoked when notification observer
|
||||
// subscribed to occurs.
|
||||
const observe = method("observer/observe");
|
||||
exports.observe = observe;
|
||||
|
||||
// Method to subscribe to the observer notification.
|
||||
const subscribe = method("observe/subscribe");
|
||||
exports.subscribe = subscribe;
|
||||
|
||||
|
||||
// Method to unsubscribe from the observer notifications.
|
||||
const unsubscribe = method("observer/unsubscribe");
|
||||
exports.unsubscribe = unsubscribe;
|
||||
|
||||
|
||||
// This is wrapper class that takes a `delegate` and produces
|
||||
// instance of `nsIObserver` which will delegate to a given
|
||||
// object when observer notification occurs.
|
||||
const ObserverDelegee = Class({
|
||||
initialize: function(delegate) {
|
||||
this.delegate = delegate;
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
const isObserver = iid.equals(Ci.nsIObserver);
|
||||
const isWeakReference = iid.equals(Ci.nsISupportsWeakReference);
|
||||
|
||||
if (!isObserver && !isWeakReference)
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
return this;
|
||||
},
|
||||
observe: function(subject, topic, data) {
|
||||
observe(this.delegate, subject, topic, data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Class that can be either mixed in or inherited from in
|
||||
// order to subscribe / unsubscribe for observer notifications.
|
||||
const Observer = Class({});
|
||||
exports.Observer = Observer;
|
||||
|
||||
// Weak maps that associates instance of `ObserverDelegee` with
|
||||
// an actual observer. It ensures that `ObserverDelegee` instance
|
||||
// won't be GC-ed until given `observer` is.
|
||||
const subscribers = new WeakMap();
|
||||
|
||||
// Implementation of `subscribe` for `Observer` type just registers
|
||||
// observer for an observer service. If `isWeak(observer)` is `true`
|
||||
// observer service won't hold strong reference to a given `observer`.
|
||||
subscribe.define(Observer, (observer, topic) => {
|
||||
if (!subscribers.has(observer)) {
|
||||
const delegee = new ObserverDelegee(observer);
|
||||
subscribers.set(observer, delegee);
|
||||
addObserver(delegee, topic, isWeak(observer));
|
||||
}
|
||||
});
|
||||
|
||||
// Unsubscribes `observer` from observer notifications for the
|
||||
// given `topic`.
|
||||
unsubscribe.define(Observer, (observer, topic) => {
|
||||
const delegee = subscribers.get(observer);
|
||||
if (delegee) {
|
||||
subscribers.delete(observer);
|
||||
removeObserver(delegee, topic);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
/* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const method = require("../../method/core");
|
||||
const { Class } = require("./heritage");
|
||||
|
||||
// Object that inherit or mix WeakRefence inn will register
|
||||
// weak observes for system notifications.
|
||||
const WeakReference = Class({});
|
||||
exports.WeakReference = WeakReference;
|
||||
|
||||
|
||||
// If `isWeak(object)` is `true` observer installed
|
||||
// for such `object` will be weak, meaning that it will
|
||||
// be GC-ed if nothing else but observer is observing it.
|
||||
// By default everything except `WeakReference` will return
|
||||
// `false`.
|
||||
const isWeak = method("reference/weak?");
|
||||
exports.isWeak = isWeak;
|
||||
|
||||
isWeak.define(Object, _ => false);
|
||||
isWeak.define(WeakReference, _ => true);
|
|
@ -13,6 +13,7 @@ const { contract } = require('./util/contract');
|
|||
const { getAttachEventType, WorkerHost } = require('./content/utils');
|
||||
const { Class } = require('./core/heritage');
|
||||
const { Disposable } = require('./core/disposable');
|
||||
const { WeakReference } = require('./core/reference');
|
||||
const { Worker } = require('./content/worker');
|
||||
const { EventTarget } = require('./event/target');
|
||||
const { on, emit, once, setListeners } = require('./event/core');
|
||||
|
@ -97,7 +98,8 @@ const PageMod = Class({
|
|||
implements: [
|
||||
modContract.properties(modelFor),
|
||||
EventTarget,
|
||||
Disposable
|
||||
Disposable,
|
||||
WeakReference
|
||||
],
|
||||
extends: WorkerHost(workerFor),
|
||||
setup: function PageMod(options) {
|
||||
|
@ -128,7 +130,7 @@ const PageMod = Class({
|
|||
applyOnExistingDocuments(mod);
|
||||
},
|
||||
|
||||
destroy: function destroy() {
|
||||
dispose: function() {
|
||||
let style = styleFor(this);
|
||||
if (style)
|
||||
detach(style);
|
||||
|
|
|
@ -13,6 +13,7 @@ const { filter, pipe, map, merge: streamMerge, stripListeners } = require('./eve
|
|||
const { detach, attach, destroy, WorkerHost } = require('./content/utils');
|
||||
const { Worker } = require('./content/worker');
|
||||
const { Disposable } = require('./core/disposable');
|
||||
const { WeakReference } = require('./core/reference');
|
||||
const { EventTarget } = require('./event/target');
|
||||
const { unload } = require('./system/unload');
|
||||
const { events, streamEventsFrom } = require('./content/events');
|
||||
|
@ -84,7 +85,8 @@ function isValidURL(page, url) !page.rules || page.rules.matchesAny(url)
|
|||
const Page = Class({
|
||||
implements: [
|
||||
EventTarget,
|
||||
Disposable
|
||||
Disposable,
|
||||
WeakReference
|
||||
],
|
||||
extends: WorkerHost(workerFor),
|
||||
setup: function Page(options) {
|
||||
|
|
|
@ -21,6 +21,7 @@ const { merge } = require("./util/object");
|
|||
const { WorkerHost, detach, attach, destroy } = require("./content/utils");
|
||||
const { Worker } = require("./content/worker");
|
||||
const { Disposable } = require("./core/disposable");
|
||||
const { WeakReference } = require('./core/reference');
|
||||
const { contract: loaderContract } = require("./content/loader");
|
||||
const { contract } = require("./util/contract");
|
||||
const { on, off, emit, setListeners } = require("./event/core");
|
||||
|
@ -111,7 +112,8 @@ const Panel = Class({
|
|||
// set and return values from model on get.
|
||||
panelContract.properties(modelFor),
|
||||
EventTarget,
|
||||
Disposable
|
||||
Disposable,
|
||||
WeakReference
|
||||
],
|
||||
extends: WorkerHost(workerFor),
|
||||
setup: function setup(options) {
|
||||
|
@ -197,7 +199,7 @@ const Panel = Class({
|
|||
|
||||
let model = modelFor(this);
|
||||
let view = viewFor(this);
|
||||
let anchorView = getNodeView(anchor || options.position);
|
||||
let anchorView = getNodeView(anchor || options.position || model.position);
|
||||
|
||||
options = merge({
|
||||
position: model.position,
|
||||
|
|
|
@ -174,10 +174,11 @@ function state(contract) {
|
|||
state: function state(target, state) {
|
||||
let nativeTarget = target === 'window' ? getFocusedBrowser()
|
||||
: target === 'tab' ? getMostRecentTab()
|
||||
: target === this ? null
|
||||
: viewFor(target);
|
||||
|
||||
if (!nativeTarget && target !== this && !isNil(target))
|
||||
throw new Error('target not allowed.');
|
||||
throw new Error(ERR_INVALID_TARGET);
|
||||
|
||||
target = nativeTarget || target;
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/* 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";
|
||||
|
||||
// The widget module currently supports only Firefox.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=560716
|
||||
module.metadata = {
|
||||
"stability": "stable",
|
||||
"stability": "deprecated",
|
||||
"engines": {
|
||||
"Firefox": "*"
|
||||
}
|
||||
|
@ -39,6 +38,7 @@ const EVENTS = {
|
|||
// normal toolbarbuttons. If they're any wider than this margin, we'll
|
||||
// treat them as wide widgets instead, which fill up the width of the panel:
|
||||
const AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF = 70;
|
||||
const AUSTRALIS_PANEL_WIDE_CLASSNAME = "panel-wide-item";
|
||||
|
||||
const { validateOptions } = require("./deprecated/api-utils");
|
||||
const panels = require("./panel");
|
||||
|
@ -55,6 +55,11 @@ const unload = require("./system/unload");
|
|||
const { getNodeView } = require("./view/core");
|
||||
const prefs = require('./preferences/service');
|
||||
|
||||
require("./util/deprecate").deprecateUsage(
|
||||
"The widget module is deprecated. " +
|
||||
"Please consider using the sdk/ui module instead."
|
||||
);
|
||||
|
||||
// Data types definition
|
||||
const valid = {
|
||||
number: { is: ["null", "undefined", "number"] },
|
||||
|
@ -230,6 +235,8 @@ function haveInserted(widgetId) {
|
|||
return prefs.has(INSERTION_PREF_ROOT + widgetId);
|
||||
}
|
||||
|
||||
const isWide = node => node.classList.contains(AUSTRALIS_PANEL_WIDE_CLASSNAME);
|
||||
|
||||
/**
|
||||
* Main Widget class: entry point of the widget API
|
||||
*
|
||||
|
@ -626,7 +633,7 @@ BrowserWindow.prototype = {
|
|||
let placement = CustomizableUI.getPlacementOfWidget(id);
|
||||
|
||||
if (!placement) {
|
||||
if (haveInserted(id))
|
||||
if (haveInserted(id) || isWide(node))
|
||||
return;
|
||||
|
||||
placement = {area: 'nav-bar', position: undefined};
|
||||
|
@ -703,7 +710,7 @@ WidgetChrome.prototype._createNode = function WC__createNode() {
|
|||
node.setAttribute("sdkstylewidget", "true");
|
||||
|
||||
if (this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) {
|
||||
node.classList.add("panel-wide-item");
|
||||
node.classList.add(AUSTRALIS_PANEL_WIDE_CLASSNAME);
|
||||
}
|
||||
|
||||
// TODO move into a stylesheet, configurable by consumers.
|
||||
|
|
|
@ -11,8 +11,8 @@ const app = require("sdk/system/xul-app");
|
|||
// module.metadata.engines
|
||||
if (app.is('Firefox')) {
|
||||
merge(module.exports,
|
||||
require('./tests/test-places-bookmarks'),
|
||||
require('./tests/test-places-events'),
|
||||
require('./tests/test-places-bookmarks'),
|
||||
require('./tests/test-places-favicon'),
|
||||
require('./tests/test-places-history'),
|
||||
require('./tests/test-places-host'),
|
||||
|
|
|
@ -18,6 +18,13 @@ const { setTimeout } = require('sdk/timers');
|
|||
const { before, after } = require('sdk/test/utils');
|
||||
const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
const { release, platform } = require('node/os');
|
||||
|
||||
const isOSX10_6 = (() => {
|
||||
let vString = release();
|
||||
return vString && /darwin/.test(platform()) && /10\.6/.test(vString);
|
||||
})();
|
||||
|
||||
const {
|
||||
search
|
||||
} = require('sdk/places/history');
|
||||
|
@ -51,6 +58,14 @@ exports['test bookmark-item-added'] = function (assert, done) {
|
|||
exports['test bookmark-item-changed'] = function (assert, done) {
|
||||
let id;
|
||||
let complete = makeCompleted(done);
|
||||
|
||||
// Due to bug 969616 and bug 971964, disabling tests in 10.6 (happens only
|
||||
// in debug builds) to prevent intermittent failures
|
||||
if (isOSX10_6) {
|
||||
assert.ok(true, 'skipping test in OSX 10.6');
|
||||
return done();
|
||||
}
|
||||
|
||||
function handler ({type, data}) {
|
||||
if (type !== 'bookmark-item-changed') return;
|
||||
if (data.id !== id) return;
|
||||
|
@ -87,6 +102,13 @@ exports['test bookmark-item-moved'] = function (assert, done) {
|
|||
let complete = makeCompleted(done);
|
||||
let previousIndex, previousParentId;
|
||||
|
||||
// Due to bug 969616 and bug 971964, disabling tests in 10.6 (happens only
|
||||
// in debug builds) to prevent intermittent failures
|
||||
if (isOSX10_6) {
|
||||
assert.ok(true, 'skipping test in OSX 10.6');
|
||||
return done();
|
||||
}
|
||||
|
||||
function handler ({type, data}) {
|
||||
if (type !== 'bookmark-item-moved') return;
|
||||
if (data.id !== id) return;
|
||||
|
@ -213,7 +235,7 @@ exports['test history-start-batch, history-end-batch, history-start-clear'] = fu
|
|||
off(clearEvent, 'data', clearHandler);
|
||||
complete();
|
||||
}
|
||||
|
||||
|
||||
on(startEvent, 'data', startHandler);
|
||||
on(clearEvent, 'data', clearHandler);
|
||||
|
||||
|
|
|
@ -5,9 +5,150 @@
|
|||
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
const { Disposable } = require("sdk/core/disposable");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
|
||||
exports["test destroy reasons"] = assert => {
|
||||
const Foo = Class({
|
||||
extends: Disposable,
|
||||
dispose: function() {
|
||||
disposals = disposals + 1;
|
||||
}
|
||||
});
|
||||
|
||||
let disposals = 0;
|
||||
const f1 = new Foo();
|
||||
|
||||
f1.destroy();
|
||||
assert.equal(disposals, 1, "disposed on destroy");
|
||||
f1.destroy();
|
||||
assert.equal(disposals, 1, "second destroy is ignored");
|
||||
|
||||
disposals = 0;
|
||||
const f2 = new Foo();
|
||||
|
||||
f2.destroy("uninstall");
|
||||
assert.equal(disposals, 1, "uninstall invokes disposal");
|
||||
f2.destroy("uninstall")
|
||||
f2.destroy();
|
||||
assert.equal(disposals, 1, "disposal happens just once");
|
||||
|
||||
disposals = 0;
|
||||
const f3 = new Foo();
|
||||
|
||||
f3.destroy("shutdown");
|
||||
assert.equal(disposals, 0, "shutdown doesn't invoke disposal");
|
||||
f3.destroy();
|
||||
assert.equal(disposals, 0, "shutdown already skipped disposal");
|
||||
|
||||
disposals = 0;
|
||||
const f4 = new Foo();
|
||||
|
||||
f4.destroy("disable");
|
||||
assert.equal(disposals, 1, "disable invokes disposal");
|
||||
f4.destroy("disable")
|
||||
f4.destroy();
|
||||
assert.equal(disposals, 1, "destroy happens just once");
|
||||
|
||||
disposals = 0;
|
||||
const f5 = new Foo();
|
||||
|
||||
f5.destroy("disable");
|
||||
assert.equal(disposals, 1, "disable invokes disposal");
|
||||
f5.destroy("disable")
|
||||
f5.destroy();
|
||||
assert.equal(disposals, 1, "destroy happens just once");
|
||||
|
||||
disposals = 0;
|
||||
const f6 = new Foo();
|
||||
|
||||
f6.destroy("upgrade");
|
||||
assert.equal(disposals, 1, "upgrade invokes disposal");
|
||||
f6.destroy("upgrade")
|
||||
f6.destroy();
|
||||
assert.equal(disposals, 1, "destroy happens just once");
|
||||
|
||||
disposals = 0;
|
||||
const f7 = new Foo();
|
||||
|
||||
f7.destroy("downgrade");
|
||||
assert.equal(disposals, 1, "downgrade invokes disposal");
|
||||
f7.destroy("downgrade")
|
||||
f7.destroy();
|
||||
assert.equal(disposals, 1, "destroy happens just once");
|
||||
|
||||
|
||||
disposals = 0;
|
||||
const f8 = new Foo();
|
||||
|
||||
f8.destroy("whatever");
|
||||
assert.equal(disposals, 1, "unrecognized reason invokes disposal");
|
||||
f8.destroy("meh")
|
||||
f8.destroy();
|
||||
assert.equal(disposals, 1, "destroy happens just once");
|
||||
};
|
||||
|
||||
exports["test different unload hooks"] = assert => {
|
||||
const { uninstall, shutdown, disable, upgrade,
|
||||
downgrade, dispose } = require("sdk/core/disposable");
|
||||
const UberUnload = Class({
|
||||
extends: Disposable,
|
||||
setup: function() {
|
||||
this.log = [];
|
||||
}
|
||||
});
|
||||
|
||||
uninstall.define(UberUnload, x => x.log.push("uninstall"));
|
||||
shutdown.define(UberUnload, x => x.log.push("shutdown"));
|
||||
disable.define(UberUnload, x => x.log.push("disable"));
|
||||
upgrade.define(UberUnload, x => x.log.push("upgrade"));
|
||||
downgrade.define(UberUnload, x => x.log.push("downgrade"));
|
||||
dispose.define(UberUnload, x => x.log.push("dispose"));
|
||||
|
||||
const u1 = new UberUnload();
|
||||
u1.destroy("uninstall");
|
||||
u1.destroy();
|
||||
u1.destroy("shutdown");
|
||||
assert.deepEqual(u1.log, ["uninstall"], "uninstall hook invoked");
|
||||
|
||||
const u2 = new UberUnload();
|
||||
u2.destroy("shutdown");
|
||||
u2.destroy();
|
||||
u2.destroy("uninstall");
|
||||
assert.deepEqual(u2.log, ["shutdown"], "shutdown hook invoked");
|
||||
|
||||
const u3 = new UberUnload();
|
||||
u3.destroy("disable");
|
||||
u3.destroy();
|
||||
u3.destroy("uninstall");
|
||||
assert.deepEqual(u3.log, ["disable"], "disable hook invoked");
|
||||
|
||||
const u4 = new UberUnload();
|
||||
u4.destroy("upgrade");
|
||||
u4.destroy();
|
||||
u4.destroy("uninstall");
|
||||
assert.deepEqual(u4.log, ["upgrade"], "upgrade hook invoked");
|
||||
|
||||
const u5 = new UberUnload();
|
||||
u5.destroy("downgrade");
|
||||
u5.destroy();
|
||||
u5.destroy("uninstall");
|
||||
assert.deepEqual(u5.log, ["downgrade"], "downgrade hook invoked");
|
||||
|
||||
const u6 = new UberUnload();
|
||||
u6.destroy();
|
||||
u6.destroy();
|
||||
u6.destroy("uninstall");
|
||||
assert.deepEqual(u6.log, ["dispose"], "dispose hook invoked");
|
||||
|
||||
const u7 = new UberUnload();
|
||||
u7.destroy("whatever");
|
||||
u7.destroy();
|
||||
u7.destroy("uninstall");
|
||||
assert.deepEqual(u7.log, ["dispose"], "dispose hook invoked");
|
||||
};
|
||||
|
||||
exports["test disposables are desposed on unload"] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { Disposable } = loader.require("sdk/core/disposable");
|
||||
|
@ -84,6 +225,7 @@ exports["test destroyed windows dispose before unload"] = function(assert) {
|
|||
exports["test disposables are GC-able"] = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
let { Disposable } = loader.require("sdk/core/disposable");
|
||||
let { WeakReference } = loader.require("sdk/core/reference");
|
||||
|
||||
let arg1 = {}
|
||||
let arg2 = 2
|
||||
|
@ -91,6 +233,7 @@ exports["test disposables are GC-able"] = function(assert, done) {
|
|||
|
||||
let Foo = Class({
|
||||
extends: Disposable,
|
||||
implements: [WeakReference],
|
||||
setup: function setup(a, b) {
|
||||
assert.equal(a, arg1,
|
||||
"arguments passed to constructur is passed to setup");
|
||||
|
@ -106,7 +249,7 @@ exports["test disposables are GC-able"] = function(assert, done) {
|
|||
this.fooed = false
|
||||
disposals = disposals + 1
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let foo1 = Foo(arg1, arg2)
|
||||
let foo2 = Foo(arg1, arg2)
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* 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 { Loader } = require("sdk/test/loader");
|
||||
const { isWeak, WeakReference } = require("sdk/core/reference");
|
||||
const { subscribe, unsubscribe,
|
||||
observe, Observer } = require("sdk/core/observer");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { notifyObservers } = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
const message = x => ({wrappedJSObject: x});
|
||||
|
||||
exports["test subscribe unsubscribe"] = assert => {
|
||||
const topic = Date.now().toString(32);
|
||||
const Subscriber = Class({
|
||||
extends: Observer,
|
||||
initialize: function(observe) {
|
||||
this.observe = observe;
|
||||
}
|
||||
});
|
||||
observe.define(Subscriber, (x, subject, _, data) =>
|
||||
x.observe(subject.wrappedJSObject.x));
|
||||
|
||||
let xs = [];
|
||||
const x = Subscriber((...rest) => xs.push(...rest));
|
||||
|
||||
let ys = [];
|
||||
const y = Subscriber((...rest) => ys.push(...rest));
|
||||
|
||||
const publish = (topic, data) =>
|
||||
notifyObservers(message(data), topic, null);
|
||||
|
||||
publish({x:0});
|
||||
|
||||
subscribe(x, topic);
|
||||
|
||||
publish(topic, {x:1});
|
||||
|
||||
subscribe(y, topic);
|
||||
|
||||
publish(topic, {x:2});
|
||||
publish(topic + "!", {x: 2.5});
|
||||
|
||||
unsubscribe(x, topic);
|
||||
|
||||
publish(topic, {x:3});
|
||||
|
||||
subscribe(y, topic);
|
||||
|
||||
publish(topic, {x:4});
|
||||
|
||||
subscribe(x, topic);
|
||||
|
||||
publish(topic, {x:5});
|
||||
|
||||
unsubscribe(x, topic);
|
||||
unsubscribe(y, topic);
|
||||
|
||||
publish(topic, {x:6});
|
||||
|
||||
assert.deepEqual(xs, [1, 2, 5]);
|
||||
assert.deepEqual(ys, [2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
exports["test weak observers are GC-ed on unload"] = (assert, end) => {
|
||||
const topic = Date.now().toString(32);
|
||||
const loader = Loader(module);
|
||||
const { Observer, observe,
|
||||
subscribe, unsubscribe } = loader.require("sdk/core/observer");
|
||||
const { isWeak, WeakReference } = loader.require("sdk/core/reference");
|
||||
|
||||
const MyObserver = Class({
|
||||
extends: Observer,
|
||||
initialize: function(observe) {
|
||||
this.observe = observe;
|
||||
}
|
||||
});
|
||||
observe.define(MyObserver, (x, ...rest) => x.observe(...rest));
|
||||
|
||||
const MyWeakObserver = Class({
|
||||
extends: MyObserver,
|
||||
implements: [WeakReference]
|
||||
});
|
||||
|
||||
let xs = [];
|
||||
let ys = [];
|
||||
let x = new MyObserver((subject, topic, data) => {
|
||||
xs.push(subject.wrappedJSObject, topic, data);
|
||||
});
|
||||
let y = new MyWeakObserver((subject, topic, data) => {
|
||||
ys.push(subject.wrappedJSObject, topic, data);
|
||||
});
|
||||
|
||||
subscribe(x, topic);
|
||||
subscribe(y, topic);
|
||||
|
||||
|
||||
notifyObservers(message({ foo: 1 }), topic, null);
|
||||
x = null;
|
||||
y = null;
|
||||
loader.unload();
|
||||
|
||||
Cu.schedulePreciseGC(() => {
|
||||
|
||||
notifyObservers(message({ bar: 2 }), topic, ":)");
|
||||
|
||||
assert.deepEqual(xs, [{ foo: 1 }, topic, null,
|
||||
{ bar: 2 }, topic, ":)"],
|
||||
"non week observer is kept");
|
||||
|
||||
assert.deepEqual(ys, [{ foo: 1 }, topic, null],
|
||||
"week observer was GC-ed");
|
||||
|
||||
end();
|
||||
});
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
|
@ -859,6 +859,8 @@ exports['test passing DOM node as first argument'] = function (assert, done) {
|
|||
let shown = defer();
|
||||
|
||||
function onMessage(type, message) {
|
||||
if (type != 'warn') return;
|
||||
|
||||
let warning = 'Passing a DOM node to Panel.show() method is an unsupported ' +
|
||||
'feature that will be soon replaced. ' +
|
||||
'See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877';
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* 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 { isWeak, WeakReference } = require("sdk/core/reference");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
|
||||
exports["test non WeakReferences"] = assert => {
|
||||
assert.equal(isWeak({}), false,
|
||||
"regular objects aren't weak");
|
||||
|
||||
assert.equal(isWeak([]), false,
|
||||
"arrays aren't weak");
|
||||
};
|
||||
|
||||
exports["test a WeakReference"] = assert => {
|
||||
assert.equal(isWeak(new WeakReference()), true,
|
||||
"instances of WeakReferences are weak");
|
||||
};
|
||||
|
||||
exports["test a subclass"] = assert => {
|
||||
const SubType = Class({
|
||||
extends: WeakReference,
|
||||
foo: function() {
|
||||
}
|
||||
});
|
||||
|
||||
const x = new SubType();
|
||||
assert.equal(isWeak(x), true,
|
||||
"subtypes of WeakReferences are weak");
|
||||
|
||||
const SubSubType = Class({
|
||||
extends: SubType
|
||||
});
|
||||
|
||||
const y = new SubSubType();
|
||||
assert.equal(isWeak(y), true,
|
||||
"sub subtypes of WeakReferences are weak");
|
||||
};
|
||||
|
||||
exports["test a mixin"] = assert => {
|
||||
const Mixer = Class({
|
||||
implements: [WeakReference]
|
||||
});
|
||||
|
||||
assert.equal(isWeak(new Mixer()), true,
|
||||
"instances with mixed WeakReference are weak");
|
||||
|
||||
const Mux = Class({});
|
||||
const MixMux = Class({
|
||||
extends: Mux,
|
||||
implements: [WeakReference]
|
||||
});
|
||||
|
||||
assert.equal(isWeak(new MixMux()), true,
|
||||
"instances with mixed WeakReference that " +
|
||||
"inheret from other are weak");
|
||||
|
||||
|
||||
const Base = Class({});
|
||||
const ReMix = Class({
|
||||
extends: Base,
|
||||
implements: [MixMux]
|
||||
});
|
||||
|
||||
assert.equal(isWeak(new ReMix()), true,
|
||||
"subtime of mix is still weak");
|
||||
};
|
||||
|
||||
exports["test an override"] = assert => {
|
||||
const SubType = Class({ extends: WeakReference });
|
||||
isWeak.define(SubType, x => false);
|
||||
|
||||
assert.equal(isWeak(new SubType()), false,
|
||||
"behavior of isWeak can still be overrided on subtype");
|
||||
|
||||
const Mixer = Class({ implements: [WeakReference] });
|
||||
const SubMixer = Class({ extends: Mixer });
|
||||
isWeak.define(SubMixer, x => false);
|
||||
assert.equal(isWeak(new SubMixer()), false,
|
||||
"behavior of isWeak can still be overrided on mixed type");
|
||||
};
|
||||
|
||||
exports["test an opt-in"] = assert => {
|
||||
var BaseType = Class({});
|
||||
var SubType = Class({ extends: BaseType });
|
||||
|
||||
isWeak.define(SubType, x => true);
|
||||
assert.equal(isWeak(new SubType()), true,
|
||||
"isWeak can be just implemented");
|
||||
|
||||
var x = {};
|
||||
isWeak.implement(x, x => true);
|
||||
assert.equal(isWeak(x), true,
|
||||
"isWeak can be implemented per instance");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
|
@ -288,6 +288,43 @@ exports['test button global state updated'] = function(assert) {
|
|||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button global state set and get with state method'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ActionButton } = loader.require('sdk/ui');
|
||||
|
||||
let button = ActionButton({
|
||||
id: 'my-button-16',
|
||||
label: 'my button',
|
||||
icon: './icon.png'
|
||||
});
|
||||
|
||||
// read the button's state
|
||||
let state = button.state(button);
|
||||
|
||||
assert.equal(state.label, 'my button',
|
||||
'label is correct');
|
||||
assert.equal(state.icon, './icon.png',
|
||||
'icon is correct');
|
||||
assert.equal(state.disabled, false,
|
||||
'disabled is correct');
|
||||
|
||||
// set the new button's state
|
||||
button.state(button, {
|
||||
label: 'New label',
|
||||
icon: './new-icon.png',
|
||||
disabled: true
|
||||
});
|
||||
|
||||
assert.equal(button.label, 'New label',
|
||||
'label is updated');
|
||||
assert.equal(button.icon, './new-icon.png',
|
||||
'icon is updated');
|
||||
assert.equal(button.disabled, true,
|
||||
'disabled is updated');
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button global state updated on multiple windows'] = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
let { ActionButton } = loader.require('sdk/ui');
|
||||
|
|
|
@ -298,6 +298,43 @@ exports['test button global state updated'] = function(assert) {
|
|||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button global state set and get with state method'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ToggleButton } = loader.require('sdk/ui');
|
||||
|
||||
let button = ToggleButton({
|
||||
id: 'my-button-16',
|
||||
label: 'my button',
|
||||
icon: './icon.png'
|
||||
});
|
||||
|
||||
// read the button's state
|
||||
let state = button.state(button);
|
||||
|
||||
assert.equal(state.label, 'my button',
|
||||
'label is correct');
|
||||
assert.equal(state.icon, './icon.png',
|
||||
'icon is correct');
|
||||
assert.equal(state.disabled, false,
|
||||
'disabled is correct');
|
||||
|
||||
// set the new button's state
|
||||
button.state(button, {
|
||||
label: 'New label',
|
||||
icon: './new-icon.png',
|
||||
disabled: true
|
||||
});
|
||||
|
||||
assert.equal(button.label, 'New label',
|
||||
'label is updated');
|
||||
assert.equal(button.icon, './new-icon.png',
|
||||
'icon is updated');
|
||||
assert.equal(button.disabled, true,
|
||||
'disabled is updated');
|
||||
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports['test button global state updated on multiple windows'] = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
let { ToggleButton } = loader.require('sdk/ui');
|
||||
|
@ -1027,35 +1064,62 @@ exports['test buttons can have anchored panels'] = function(assert, done) {
|
|||
let { identify } = loader.require('sdk/ui/id');
|
||||
let { getActiveView } = loader.require('sdk/view/core');
|
||||
|
||||
let button = ToggleButton({
|
||||
let b1 = ToggleButton({
|
||||
id: 'my-button-22',
|
||||
label: 'my button',
|
||||
icon: './icon.png',
|
||||
onChange: ({checked}) => checked && panel.show({position: button})
|
||||
onChange: ({checked}) => checked && panel.show()
|
||||
});
|
||||
|
||||
let panel = Panel();
|
||||
let b2 = ToggleButton({
|
||||
id: 'my-button-23',
|
||||
label: 'my button',
|
||||
icon: './icon.png',
|
||||
onChange: ({checked}) => checked && panel.show({position: b2})
|
||||
});
|
||||
|
||||
let panel = Panel({
|
||||
position: b1
|
||||
});
|
||||
|
||||
let { document } = getMostRecentBrowserWindow();
|
||||
let b1Node = document.getElementById(identify(b1));
|
||||
let b2Node = document.getElementById(identify(b2));
|
||||
let panelNode = getActiveView(panel);
|
||||
|
||||
panel.once('show', () => {
|
||||
let { document } = getMostRecentBrowserWindow();
|
||||
let buttonNode = document.getElementById(identify(button));
|
||||
let panelNode = getActiveView(panel);
|
||||
|
||||
assert.ok(button.state('window').checked,
|
||||
assert.ok(b1.state('window').checked,
|
||||
'button is checked');
|
||||
|
||||
assert.equal(panelNode.getAttribute('type'), 'arrow',
|
||||
'the panel is a arrow type');
|
||||
|
||||
assert.strictEqual(buttonNode, panelNode.anchorNode,
|
||||
'the panel is anchored properly to the button');
|
||||
assert.strictEqual(b1Node, panelNode.anchorNode,
|
||||
'the panel is anchored properly to the button given in costructor');
|
||||
|
||||
loader.unload();
|
||||
panel.hide();
|
||||
|
||||
done();
|
||||
panel.once('show', () => {
|
||||
assert.ok(b2.state('window').checked,
|
||||
'button is checked');
|
||||
|
||||
assert.equal(panelNode.getAttribute('type'), 'arrow',
|
||||
'the panel is a arrow type');
|
||||
|
||||
// test also that the button passed in `show` method, takes the precedence
|
||||
// over the button set in panel's constructor.
|
||||
assert.strictEqual(b2Node, panelNode.anchorNode,
|
||||
'the panel is anchored properly to the button passed to show method');
|
||||
|
||||
loader.unload();
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
b2.click();
|
||||
});
|
||||
|
||||
button.click();
|
||||
b1.click();
|
||||
}
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
|
|
@ -9,13 +9,11 @@ module.metadata = {
|
|||
}
|
||||
};
|
||||
|
||||
const widgets = require("sdk/widget");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { LoaderWithHookedConsole } = require('sdk/test/loader');
|
||||
const url = require("sdk/url");
|
||||
const timer = require("sdk/timers");
|
||||
const self = require("sdk/self");
|
||||
const windowUtils = require("sdk/deprecated/window-utils");
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { close, open, focus } = require("sdk/window/helpers");
|
||||
const tabs = require("sdk/tabs/utils");
|
||||
|
@ -43,8 +41,24 @@ function openNewWindowTab(url, options) {
|
|||
});
|
||||
}
|
||||
|
||||
exports.testDeprecationMessage = function(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module, onMessage);
|
||||
|
||||
// Intercept all console method calls
|
||||
let calls = [];
|
||||
function onMessage(type, msg) {
|
||||
assert.equal(type, 'error', 'the only message is an error');
|
||||
assert.ok(/^DEPRECATED:/.test(msg), 'deprecated');
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
loader.require('sdk/widget');
|
||||
}
|
||||
|
||||
exports.testConstructor = function(assert, done) {
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let { loader: loader0 } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader0.require("sdk/widget");
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
let doc = browserWindow.document;
|
||||
let AddonsMgrListener;
|
||||
|
||||
|
@ -78,7 +92,7 @@ exports.testConstructor = function(assert, done) {
|
|||
assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy");
|
||||
|
||||
// Test automatic widget destroy on unload
|
||||
let loader = Loader(module);
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
let widgetsFromLoader = loader.require("sdk/widget");
|
||||
let widgetStartCount = widgetCount();
|
||||
let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
|
||||
|
@ -192,8 +206,10 @@ exports.testConstructor = function(assert, done) {
|
|||
let tests = [];
|
||||
function nextTest() {
|
||||
assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up");
|
||||
if (!tests.length)
|
||||
if (!tests.length) {
|
||||
loader0.unload();
|
||||
done();
|
||||
}
|
||||
else
|
||||
timer.setTimeout(tests.shift(), 0);
|
||||
}
|
||||
|
@ -535,7 +551,7 @@ exports.testConstructor = function(assert, done) {
|
|||
contentScript: "self.port.on('event', function () self.port.emit('event'))"
|
||||
};
|
||||
let widget = testSingleWidget(w1Opts);
|
||||
let windows = require("sdk/windows").browserWindows;
|
||||
let windows = loader0.require("sdk/windows").browserWindows;
|
||||
|
||||
// 2/ Retrieve a WidgetView for the initial browser window
|
||||
let acceptDetach = false;
|
||||
|
@ -627,16 +643,16 @@ exports.testConstructor = function(assert, done) {
|
|||
id: "text-test-width",
|
||||
label: "test widget.width",
|
||||
content: "test width",
|
||||
width: 200,
|
||||
width: 64,
|
||||
contentScript: "self.postMessage(1)",
|
||||
contentScriptWhen: "ready",
|
||||
onMessage: function(message) {
|
||||
assert.equal(this.width, 200, 'width is 200');
|
||||
assert.equal(this.width, 64, 'width is 64');
|
||||
|
||||
let node = widgetNode(0);
|
||||
assert.equal(this.width, node.style.minWidth.replace("px", ""));
|
||||
assert.equal(this.width, node.firstElementChild.style.width.replace("px", ""));
|
||||
this.width = 300;
|
||||
this.width = 48;
|
||||
assert.equal(this.width, node.style.minWidth.replace("px", ""));
|
||||
assert.equal(this.width, node.firstElementChild.style.width.replace("px", ""));
|
||||
|
||||
|
@ -677,16 +693,18 @@ exports.testConstructor = function(assert, done) {
|
|||
};
|
||||
|
||||
exports.testWidgetWithValidPanel = function(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
const { Panel } = loader.require("sdk/panel");
|
||||
|
||||
let widget1 = widgets.Widget({
|
||||
let widget1 = Widget({
|
||||
id: "testWidgetWithValidPanel",
|
||||
label: "panel widget 1",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
||||
"document.body.dispatchEvent(evt);",
|
||||
contentScriptWhen: "end",
|
||||
panel: require("sdk/panel").Panel({
|
||||
panel: Panel({
|
||||
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
|
||||
onShow: function() {
|
||||
let { document } = getMostRecentBrowserWindow();
|
||||
|
@ -697,6 +715,7 @@ exports.testWidgetWithValidPanel = function(assert, done) {
|
|||
assert.strictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget');
|
||||
|
||||
widget1.destroy();
|
||||
loader.unload();
|
||||
assert.pass("panel displayed on click");
|
||||
done();
|
||||
}
|
||||
|
@ -705,7 +724,9 @@ exports.testWidgetWithValidPanel = function(assert, done) {
|
|||
};
|
||||
|
||||
exports.testWidgetWithInvalidPanel = function(assert) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
assert.throws(
|
||||
function() {
|
||||
widgets.Widget({
|
||||
|
@ -716,10 +737,14 @@ exports.testWidgetWithInvalidPanel = function(assert) {
|
|||
},
|
||||
/^The option \"panel\" must be one of the following types: null, undefined, object$/,
|
||||
"widget.panel must be a Panel object");
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
const { Panel } = loader.require("sdk/panel");
|
||||
|
||||
let onClickCalled = false;
|
||||
let widget3 = widgets.Widget({
|
||||
id: "panel3",
|
||||
|
@ -732,13 +757,14 @@ exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
|
|||
onClickCalled = true;
|
||||
this.panel.show();
|
||||
},
|
||||
panel: require("sdk/panel").Panel({
|
||||
panel: Panel({
|
||||
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
|
||||
onShow: function() {
|
||||
assert.ok(
|
||||
onClickCalled,
|
||||
"onClick called on click for widget with both panel and onClick");
|
||||
widget3.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
})
|
||||
|
@ -747,7 +773,9 @@ exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
|
|||
|
||||
exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
|
||||
const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {});
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
const { Panel } = loader.require("sdk/panel");
|
||||
|
||||
let widget1 = widgets.Widget({
|
||||
id: "panel1",
|
||||
|
@ -760,7 +788,7 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
|
|||
});
|
||||
},
|
||||
contentScriptWhen: "end",
|
||||
panel: require("sdk/panel").Panel({
|
||||
panel: Panel({
|
||||
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
|
||||
onShow: function() {
|
||||
let { document } = getMostRecentBrowserWindow();
|
||||
|
@ -771,6 +799,7 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
|
|||
'the panel is anchored to the panel menu button instead of widget');
|
||||
|
||||
widget1.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
})
|
||||
|
@ -797,8 +826,10 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
|
|||
};
|
||||
|
||||
exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
let origMessage = "foo";
|
||||
const widgets = require("sdk/widget");
|
||||
let widget = widgets.Widget({
|
||||
id: "widget-messaging",
|
||||
label: "foo",
|
||||
|
@ -811,6 +842,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
|||
else {
|
||||
assert.equal(origMessage, message);
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
@ -818,7 +850,9 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
|||
};
|
||||
|
||||
exports.testWidgetViews = function testWidgetViews(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
let widget = widgets.Widget({
|
||||
id: "widget-views",
|
||||
label: "foo",
|
||||
|
@ -833,6 +867,7 @@ exports.testWidgetViews = function testWidgetViews(assert, done) {
|
|||
});
|
||||
view.on("detach", function () {
|
||||
assert.pass("WidgetView destroyed");
|
||||
loader.unload();
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
@ -840,7 +875,10 @@ exports.testWidgetViews = function testWidgetViews(assert, done) {
|
|||
};
|
||||
|
||||
exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
const { browserWindows } = loader.require("sdk/windows");
|
||||
|
||||
let view = null;
|
||||
let widget = widgets.Widget({
|
||||
id: "widget-view-ui-events",
|
||||
|
@ -856,17 +894,20 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
|
|||
onClick: function (eventView) {
|
||||
assert.equal(view, eventView,
|
||||
"event first argument is equal to the WidgetView");
|
||||
let view2 = widget.getView(require("sdk/windows").browserWindows.activeWindow);
|
||||
let view2 = widget.getView(browserWindows.activeWindow);
|
||||
assert.equal(view, view2,
|
||||
"widget.getView return the same WidgetView");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
let widget = widgets.Widget({
|
||||
id: "widget-view-custom-events",
|
||||
label: "foo",
|
||||
|
@ -883,33 +924,37 @@ exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(asser
|
|||
widget.port.on("event", function (data) {
|
||||
assert.equal(data, "ok", "event argument is valid on Widget");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
const { browserWindows } = loader.require("sdk/windows");
|
||||
|
||||
let widget = new widgets.Widget({
|
||||
id: "widget-views-tooltip",
|
||||
label: "foo",
|
||||
content: "foo"
|
||||
});
|
||||
let view = widget.getView(require("sdk/windows").browserWindows.activeWindow);
|
||||
let view = widget.getView(browserWindows.activeWindow);
|
||||
widget.tooltip = null;
|
||||
assert.equal(view.tooltip, "foo",
|
||||
"view tooltip defaults to base widget label");
|
||||
assert.equal(widget.tooltip, "foo",
|
||||
"tooltip defaults to base widget label");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
};
|
||||
|
||||
exports.testWidgetMove = function testWidgetMove(assert, done) {
|
||||
let windowUtils = require("sdk/deprecated/window-utils");
|
||||
let widgets = require("sdk/widget");
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
let doc = browserWindow.document;
|
||||
|
||||
let label = "unique-widget-label";
|
||||
|
@ -939,6 +984,7 @@ exports.testWidgetMove = function testWidgetMove(assert, done) {
|
|||
else {
|
||||
assert.equal(origMessage, message, "Got message after node move");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
@ -953,16 +999,17 @@ consider the content change a navigation change, so doesn't load
|
|||
the new content.
|
||||
*/
|
||||
exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
|
||||
function getWidgetContent(widget) {
|
||||
let windowUtils = require("sdk/deprecated/window-utils");
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
let doc = browserWindow.document;
|
||||
let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]');
|
||||
assert.ok(widgetNode, 'found widget node in the front-end');
|
||||
return widgetNode.firstChild.contentDocument.body.innerHTML;
|
||||
}
|
||||
|
||||
let widgets = require("sdk/widget");
|
||||
let count = 0;
|
||||
let widget = widgets.Widget({
|
||||
id: "1",
|
||||
|
@ -977,6 +1024,7 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
|
|||
else {
|
||||
assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
@ -984,7 +1032,10 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
|
|||
};
|
||||
|
||||
exports.testContentScriptOptionsOption = function(assert, done) {
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
|
||||
let widget = Widget({
|
||||
id: "widget-script-options",
|
||||
label: "fooz",
|
||||
content: "fooz",
|
||||
|
@ -998,26 +1049,34 @@ exports.testContentScriptOptionsOption = function(assert, done) {
|
|||
assert.equal( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' );
|
||||
assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' );
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testOnAttachWithoutContentScript = function(assert, done) {
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
|
||||
let widget = Widget({
|
||||
id: "onAttachNoCS",
|
||||
label: "onAttachNoCS",
|
||||
content: "onAttachNoCS",
|
||||
onAttach: function (view) {
|
||||
assert.pass("received attach event");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testPostMessageOnAttach = function(assert, done) {
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
|
||||
let widget = Widget({
|
||||
id: "onAttach",
|
||||
label: "onAttach",
|
||||
content: "onAttach",
|
||||
|
@ -1031,15 +1090,19 @@ exports.testPostMessageOnAttach = function(assert, done) {
|
|||
onMessage: function (msg) {
|
||||
assert.equal( msg, "ok", "postMessage works on `attach` event");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testPostMessageOnLocationChange = function(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
|
||||
let attachEventCount = 0;
|
||||
let messagesCount = 0;
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let widget = Widget({
|
||||
id: "onLocationChange",
|
||||
label: "onLocationChange",
|
||||
content: "onLocationChange",
|
||||
|
@ -1065,6 +1128,7 @@ exports.testPostMessageOnLocationChange = function(assert, done) {
|
|||
assert.equal(msg, "ok",
|
||||
"We receive the message sent to the 2nd document");
|
||||
widget.destroy();
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
@ -1072,10 +1136,13 @@ exports.testPostMessageOnLocationChange = function(assert, done) {
|
|||
};
|
||||
|
||||
exports.testSVGWidget = function(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
|
||||
// use of capital SVG here is intended, that was failing..
|
||||
let SVG_URL = fixtures.url("mofo_logo.SVG");
|
||||
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let widget = Widget({
|
||||
id: "mozilla-svg-logo",
|
||||
label: "moz foundation logo",
|
||||
contentURL: SVG_URL,
|
||||
|
@ -1084,16 +1151,19 @@ exports.testSVGWidget = function(assert, done) {
|
|||
widget.destroy();
|
||||
assert.equal(data.count, 1, 'only one image');
|
||||
assert.equal(data.src, SVG_URL, 'only one image');
|
||||
loader.unload();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testReinsertion = function(assert, done) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const { Widget } = loader.require("sdk/widget");
|
||||
const WIDGETID = "test-reinsertion";
|
||||
let windowUtils = require("sdk/deprecated/window-utils");
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let widget = require("sdk/widget").Widget({
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
|
||||
let widget = Widget({
|
||||
id: "test-reinsertion",
|
||||
label: "test reinsertion",
|
||||
content: "Test",
|
||||
|
@ -1105,8 +1175,39 @@ exports.testReinsertion = function(assert, done) {
|
|||
|
||||
openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) {
|
||||
assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null);
|
||||
close(e.target.defaultView).then(done);
|
||||
close(e.target.defaultView).then(_ => {
|
||||
loader.unload();
|
||||
done();
|
||||
});
|
||||
}});
|
||||
};
|
||||
|
||||
exports.testWideWidget = function testWideWidget(assert) {
|
||||
let { loader } = LoaderWithHookedConsole(module);
|
||||
const widgets = loader.require("sdk/widget");
|
||||
const { document, CustomizableUI, gCustomizeMode, setTimeout } = getMostRecentBrowserWindow();
|
||||
|
||||
let wideWidget = widgets.Widget({
|
||||
id: "my-wide-widget",
|
||||
label: "wide-wdgt",
|
||||
content: "foo",
|
||||
width: 200
|
||||
});
|
||||
|
||||
let widget = widgets.Widget({
|
||||
id: "my-regular-widget",
|
||||
label: "reg-wdgt",
|
||||
content: "foo"
|
||||
});
|
||||
|
||||
let wideWidgetNode = document.querySelector("toolbaritem[label=wide-wdgt]");
|
||||
let widgetNode = document.querySelector("toolbaritem[label=reg-wdgt]");
|
||||
|
||||
assert.equal(wideWidgetNode, null,
|
||||
"Wide Widget are not added to UI");
|
||||
|
||||
assert.notEqual(widgetNode, null,
|
||||
"regular size widget are in the UI");
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
|
|
@ -131,7 +131,7 @@ def main(platform):
|
|||
])
|
||||
|
||||
# Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi
|
||||
add_dir_to_zip(xpi_path, os.path.join(distdir, "b2g"), "b2g", ("gaia"))
|
||||
add_dir_to_zip(xpi_path, os.path.join(distdir, "b2g"), "b2g", ("gaia", "B2G.app/Contents/MacOS/gaia"))
|
||||
# Then ship our own gaia profile
|
||||
add_dir_to_zip(xpi_path, os.path.join(gaia_path, "profile"), "profile")
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ exports.SimulatorProcess = Class({
|
|||
let bin = URL.toFilename(BIN_URL);
|
||||
let executables = {
|
||||
WINNT: "b2g-bin.exe",
|
||||
Darwin: "Contents/MacOS/b2g-bin",
|
||||
Darwin: "B2G.app/Contents/MacOS/b2g-bin",
|
||||
Linux: "b2g-bin",
|
||||
};
|
||||
|
||||
|
|
|
@ -1182,15 +1182,14 @@
|
|||
<svg:svg height="0">
|
||||
#include tab-shape.inc.svg
|
||||
|
||||
#ifndef XP_UNIX
|
||||
<svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
#ifndef XP_MACOSX
|
||||
<svg:clipPath id="keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:path d="M 0,0 a 16 16 0 0 1 0,24 l 10000,0 l 0,-24 l -10000,0 z"/>
|
||||
</svg:clipPath>
|
||||
<svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:path d="M -1,1 a 16 16 0 0 1 0,24 l 10000,0 l 0,-24 l -10000,0 z"/>
|
||||
</svg:clipPath>
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
#else
|
||||
<svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:path d="M 0,0 a 16 16 0 0 1 0,24 l 10000,0 l 0,-24 l -10000,0 z"/>
|
||||
</svg:clipPath>
|
||||
|
|
|
@ -529,7 +529,12 @@ var tests = [
|
|||
this.notifyObj.addOptions({dismissed: true});
|
||||
this.notification = showNotification(this.notifyObj);
|
||||
|
||||
EventUtils.synthesizeMouse(button, 1, 1, {});
|
||||
// This test places a normal button in the notification area, which has
|
||||
// standard GTK styling and dimensions. Due to the clip-path, this button
|
||||
// gets clipped off, which makes it necessary to synthesize the mouse click
|
||||
// a little bit downward. To be safe, I adjusted the x-offset with the same
|
||||
// amount.
|
||||
EventUtils.synthesizeMouse(button, 4, 4, {});
|
||||
},
|
||||
onShown: function(popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
|
|
|
@ -49,6 +49,7 @@ const PanelUI = {
|
|||
this.menuButton.addEventListener("keypress", this);
|
||||
this._overlayScrollListenerBoundFn = this._overlayScrollListener.bind(this);
|
||||
window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn);
|
||||
CustomizableUI.addListener(this);
|
||||
this._initialized = true;
|
||||
},
|
||||
|
||||
|
@ -69,10 +70,6 @@ const PanelUI = {
|
|||
},
|
||||
|
||||
uninit: function() {
|
||||
if (!this._eventListenersAdded) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let event of this.kEvents) {
|
||||
this.panel.removeEventListener(event, this);
|
||||
}
|
||||
|
@ -80,6 +77,7 @@ const PanelUI = {
|
|||
this.menuButton.removeEventListener("mousedown", this);
|
||||
this.menuButton.removeEventListener("keypress", this);
|
||||
window.matchMedia("(-moz-overlay-scrollbars)").removeListener(this._overlayScrollListenerBoundFn);
|
||||
CustomizableUI.removeListener(this);
|
||||
this._overlayScrollListenerBoundFn = null;
|
||||
},
|
||||
|
||||
|
@ -183,6 +181,7 @@ const PanelUI = {
|
|||
handleEvent: function(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "popupshowing":
|
||||
this._adjustLabelsForAutoHyphens();
|
||||
// Fall through
|
||||
case "popupshown":
|
||||
// Fall through
|
||||
|
@ -370,6 +369,26 @@ const PanelUI = {
|
|||
"browser");
|
||||
},
|
||||
|
||||
onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer, aWasRemoval) {
|
||||
if (aContainer != this.contents) {
|
||||
return;
|
||||
}
|
||||
if (aWasRemoval) {
|
||||
aNode.removeAttribute("auto-hyphens");
|
||||
}
|
||||
},
|
||||
|
||||
onWidgetBeforeDOMChange: function(aNode, aNextNode, aContainer, aIsRemoval) {
|
||||
if (aContainer != this.contents) {
|
||||
return;
|
||||
}
|
||||
if (!aIsRemoval &&
|
||||
(this.panel.state == "open" ||
|
||||
document.documentElement.hasAttribute("customizing"))) {
|
||||
this._adjustLabelsForAutoHyphens(aNode);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Signal that we're about to make a lot of changes to the contents of the
|
||||
* panels all at once. For performance, we ignore the mutations.
|
||||
|
@ -389,6 +408,22 @@ const PanelUI = {
|
|||
this.multiView.ignoreMutations = false;
|
||||
},
|
||||
|
||||
_adjustLabelsForAutoHyphens: function(aNode) {
|
||||
let toolbarButtons = aNode ? [aNode] :
|
||||
this.contents.querySelectorAll(".toolbarbutton-1");
|
||||
for (let node of toolbarButtons) {
|
||||
let label = node.getAttribute("label");
|
||||
if (!label) {
|
||||
continue;
|
||||
}
|
||||
if (label.contains("\u00ad")) {
|
||||
node.setAttribute("auto-hyphens", "off");
|
||||
} else {
|
||||
node.removeAttribute("auto-hyphens");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the anchor node into the open or closed state, depending
|
||||
* on the state of the panel.
|
||||
|
|
|
@ -68,6 +68,7 @@ skip-if = os == "linux"
|
|||
[browser_948985_non_removable_defaultArea.js]
|
||||
[browser_952963_areaType_getter_no_area.js]
|
||||
[browser_956602_remove_special_widget.js]
|
||||
[browser_962884_opt_in_disable_hyphens.js]
|
||||
[browser_963639_customizing_attribute_non_customizable_toolbar.js]
|
||||
[browser_967000_button_charEncoding.js]
|
||||
[browser_967000_button_feeds.js]
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* 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";
|
||||
|
||||
add_task(function() {
|
||||
const kNormalLabel = "Character Encoding";
|
||||
CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
|
||||
let characterEncoding = document.getElementById("characterencoding-button");
|
||||
const kOriginalLabel = characterEncoding.getAttribute("label");
|
||||
characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
|
||||
CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_PANEL);
|
||||
|
||||
yield PanelUI.show();
|
||||
|
||||
is(characterEncoding.getAttribute("auto-hyphens"), "off",
|
||||
"Hyphens should be disabled if the ­ character is present in the label");
|
||||
let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
|
||||
let multilineTextCS = getComputedStyle(multilineText);
|
||||
is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the ­ character is present.")
|
||||
|
||||
let hiddenPanelPromise = promisePanelHidden(window);
|
||||
PanelUI.toggle();
|
||||
yield hiddenPanelPromise;
|
||||
|
||||
characterEncoding.setAttribute("label", kNormalLabel);
|
||||
|
||||
yield PanelUI.show();
|
||||
|
||||
isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
|
||||
"Hyphens should not be disabled if the ­ character is not present in the label");
|
||||
multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
|
||||
let multilineTextCS = getComputedStyle(multilineText);
|
||||
is(multilineTextCS.MozHyphens, "auto", "-moz-hyphens should be set to auto by default.")
|
||||
|
||||
hiddenPanelPromise = promisePanelHidden(window);
|
||||
PanelUI.toggle();
|
||||
yield hiddenPanelPromise;
|
||||
|
||||
characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
|
||||
CustomizableUI.removeWidgetFromArea("characterencoding-button");
|
||||
yield startCustomizing();
|
||||
|
||||
isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
|
||||
"Hyphens should not be disabled when the widget is in the palette");
|
||||
|
||||
gCustomizeMode.addToPanel(characterEncoding);
|
||||
is(characterEncoding.getAttribute("auto-hyphens"), "off",
|
||||
"Hyphens should be disabled if the ­ character is present in the label in customization mode");
|
||||
let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
|
||||
let multilineTextCS = getComputedStyle(multilineText);
|
||||
is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the ­ character is present in customization mode.")
|
||||
|
||||
yield endCustomizing();
|
||||
|
||||
CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
|
||||
ok(!characterEncoding.hasAttribute("auto-hyphens"),
|
||||
"Removing the widget from the panel should remove the auto-hyphens attribute");
|
||||
|
||||
characterEncoding.setAttribute("label", kOriginalLabel);
|
||||
});
|
||||
|
||||
add_task(function asyncCleanup() {
|
||||
yield endCustomizing();
|
||||
yield resetCustomization();
|
||||
});
|
|
@ -128,6 +128,15 @@
|
|||
#endif
|
||||
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
|
||||
|
||||
<hbox id="header-advanced"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneAdvanced">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneAdvanced.title;"/>
|
||||
</hbox>
|
||||
|
||||
<tabbox id="advancedPrefs" flex="1"
|
||||
data-category="paneAdvanced" hidden="true"
|
||||
onselect="gAdvancedPane.tabSelectionChanged();">
|
||||
|
|
|
@ -55,7 +55,19 @@
|
|||
<key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
|
||||
</keyset>
|
||||
|
||||
<vbox data-category="paneApplications" hidden="true" flex="1">
|
||||
<hbox id="header-application"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneApplications">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneApplications.title;"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="applicationsContent"
|
||||
data-category="paneApplications"
|
||||
hidden="true"
|
||||
flex="1">
|
||||
<hbox>
|
||||
<textbox id="filter" flex="1"
|
||||
type="search"
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content/content.js"/>
|
||||
|
||||
<hbox id="header-content"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneContent">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneContent.title;"/>
|
||||
</hbox>
|
||||
|
||||
<groupbox id="miscGroup" data-category="paneContent" hidden="true">
|
||||
<caption label="&popups.label;"/>
|
||||
|
||||
|
|
|
@ -85,6 +85,14 @@
|
|||
#endif
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-general"
|
||||
class="header"
|
||||
data-category="paneGeneral">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneGeneral.title;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Startup -->
|
||||
<groupbox id="startupGroup" data-category="paneGeneral">
|
||||
<caption label="&startup.label;"/>
|
||||
|
|
|
@ -32,10 +32,8 @@ function init_all() {
|
|||
|
||||
let categories = document.getElementById("categories");
|
||||
categories.addEventListener("select", event => gotoPref(event.target.value));
|
||||
window.addEventListener("popstate", event => selectCategory(event.state));
|
||||
|
||||
if (history.length > 1 && history.state) {
|
||||
updateCommands();
|
||||
selectCategory(history.state);
|
||||
} else {
|
||||
history.replaceState("paneGeneral", document.title);
|
||||
|
@ -49,38 +47,9 @@ function selectCategory(name) {
|
|||
}
|
||||
|
||||
function gotoPref(page) {
|
||||
if (history.state != page) {
|
||||
window.history.pushState(page, document.title);
|
||||
}
|
||||
|
||||
updateCommands();
|
||||
window.history.replaceState(page, document.title);
|
||||
search(page, "data-category");
|
||||
}
|
||||
|
||||
function cmd_back() {
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
function cmd_forward() {
|
||||
window.history.forward();
|
||||
}
|
||||
|
||||
function updateCommands() {
|
||||
document.getElementById("back-btn").disabled = !canGoBack();
|
||||
document.getElementById("forward-btn").disabled = !canGoForward();
|
||||
}
|
||||
|
||||
function canGoBack() {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.canGoBack;
|
||||
}
|
||||
|
||||
function canGoForward() {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.canGoForward;
|
||||
}
|
||||
|
||||
function search(aQuery, aAttribute) {
|
||||
let elements = document.getElementById("mainPrefPane").children;
|
||||
|
|
|
@ -74,15 +74,6 @@
|
|||
src="chrome://browser/locale/preferences/applicationManager.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<hbox id="header">
|
||||
<toolbarbutton id="back-btn" class="nav-button header-button"
|
||||
oncommand="cmd_back()" tooltiptext="&buttonBack.tooltip;"
|
||||
disabled="true"/>
|
||||
<toolbarbutton id="forward-btn" class="nav-button header-button"
|
||||
oncommand="cmd_forward()" tooltiptext="&buttonForward.tooltip;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
|
||||
<hbox flex="1">
|
||||
|
||||
<!-- category list -->
|
||||
|
|
|
@ -65,6 +65,15 @@
|
|||
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-privacy"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&panePrivacy.title;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Tracking -->
|
||||
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
|
||||
<caption label="&tracking.label;"/>
|
||||
|
|
|
@ -30,6 +30,15 @@
|
|||
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-security"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneSecurity">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneSecurity.title;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- addons, forgery (phishing) UI -->
|
||||
<groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true">
|
||||
<caption label="&general.label;"/>
|
||||
|
|
|
@ -28,6 +28,15 @@
|
|||
<script type="application/javascript"
|
||||
src="chrome://browser/content/sync/utils.js"/>
|
||||
|
||||
<hbox id="header-sync"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneSync">
|
||||
<image class="header-icon"/>
|
||||
<label class="header-name"
|
||||
value="&paneSync.title;"/>
|
||||
</hbox>
|
||||
|
||||
<deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
|
||||
<vbox id="noAccount" align="center">
|
||||
<spacer flex="1"/>
|
||||
|
|
|
@ -23,6 +23,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
|||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
|
||||
"resource:///modules/sessionstore/SessionFile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
// Minimal interval between two save operations (in milliseconds).
|
||||
XPCOMUtils.defineLazyGetter(this, "gInterval", function () {
|
||||
|
@ -41,14 +43,6 @@ XPCOMUtils.defineLazyGetter(this, "gInterval", function () {
|
|||
return Services.prefs.getIntPref(PREF);
|
||||
});
|
||||
|
||||
// Wrap a string as a nsISupports.
|
||||
function createSupportsString(data) {
|
||||
let string = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
string.data = data;
|
||||
return string;
|
||||
}
|
||||
|
||||
// Notify observers about a given topic with a given subject.
|
||||
function notify(subject, topic) {
|
||||
Services.obs.notifyObservers(subject, topic, "");
|
||||
|
@ -192,6 +186,14 @@ let SessionSaverInternal = {
|
|||
// Cancel any pending timeouts.
|
||||
this.cancel();
|
||||
|
||||
if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
||||
// Don't save (or even collect) anything in permanent private
|
||||
// browsing mode
|
||||
|
||||
this.updateLastSaveTime();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
stopWatchStart("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
|
||||
let state = SessionStore.getCurrentState(forceUpdateAllWindows);
|
||||
PrivacyFilter.filterPrivateWindowsAndTabs(state);
|
||||
|
@ -242,19 +244,13 @@ let SessionSaverInternal = {
|
|||
* Write the given state object to disk.
|
||||
*/
|
||||
_writeState: function (state) {
|
||||
// Inform observers
|
||||
notify(null, "sessionstore-state-write");
|
||||
|
||||
stopWatchStart("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS", "WRITE_STATE_LONGEST_OP_MS");
|
||||
let data = JSON.stringify(state);
|
||||
stopWatchFinish("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS");
|
||||
|
||||
// Give observers a chance to modify session data.
|
||||
data = this._notifyObserversBeforeStateWrite(data);
|
||||
|
||||
// Don't touch the file if an observer has deleted all state data.
|
||||
if (!data) {
|
||||
stopWatchCancel("WRITE_STATE_LONGEST_OP_MS");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// We update the time stamp before writing so that we don't write again
|
||||
// too soon, if saving is requested before the write completes. Without
|
||||
// this update we may save repeatedly if actions cause a runDelayed
|
||||
|
@ -275,14 +271,4 @@ let SessionSaverInternal = {
|
|||
|
||||
return promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify sessionstore-state-write observer and give them a
|
||||
* chance to modify session data before we'll write it to disk.
|
||||
*/
|
||||
_notifyObserversBeforeStateWrite: function (data) {
|
||||
let stateString = createSupportsString(data);
|
||||
notify(stateString, "sessionstore-state-write");
|
||||
return stateString.data;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1058,16 +1058,26 @@ let SessionStoreInternal = {
|
|||
// recently something was closed.
|
||||
winData.closedAt = Date.now();
|
||||
|
||||
// Save the window if it has multiple tabs or a single saveable tab and
|
||||
// it's not private.
|
||||
// Save non-private windows if they have at
|
||||
// least one saveable tab or are the last window.
|
||||
if (!winData.isPrivate) {
|
||||
// Remove any open private tabs the window may contain.
|
||||
PrivacyFilter.filterPrivateTabs(winData);
|
||||
|
||||
let hasSingleTabToSave =
|
||||
winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]);
|
||||
// Determine whether the window has any tabs worth saving.
|
||||
let hasSaveableTabs = winData.tabs.some(this._shouldSaveTabState);
|
||||
|
||||
if (hasSingleTabToSave || winData.tabs.length > 1) {
|
||||
// When closing windows one after the other until Firefox quits, we
|
||||
// will move those closed in series back to the "open windows" bucket
|
||||
// before writing to disk. If however there is only a single window
|
||||
// with tabs we deem not worth saving then we might end up with a
|
||||
// random closed or even a pop-up window re-opened. To prevent that
|
||||
// we explicitly allow saving an "empty" window state.
|
||||
let isLastWindow =
|
||||
Object.keys(this._windows).length == 1 &&
|
||||
!this._closedWindows.some(win => win._shouldRestore || false);
|
||||
|
||||
if (hasSaveableTabs || isLastWindow) {
|
||||
// we don't want to save the busy state
|
||||
delete winData.busy;
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ skip-if = true
|
|||
[browser_394759_purge.js]
|
||||
[browser_423132.js]
|
||||
[browser_447951.js]
|
||||
[browser_448741.js]
|
||||
[browser_454908.js]
|
||||
[browser_456342.js]
|
||||
[browser_461634.js]
|
||||
|
|
|
@ -75,15 +75,13 @@ function test() {
|
|||
// Wait for the sessionstore.js file to be written before going on.
|
||||
// Note: we don't wait for the complete event, since if asyncCopy fails we
|
||||
// would timeout.
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
info("sessionstore.js is being written");
|
||||
|
||||
waitForSaveState(function(writing) {
|
||||
ok(writing, "sessionstore.js is being written");
|
||||
closedWindowCount = ss.getClosedWindowCount();
|
||||
is(closedWindowCount, 0, "Correctly set window count");
|
||||
|
||||
executeSoon(aCallback);
|
||||
}, "sessionstore-state-write", false);
|
||||
});
|
||||
|
||||
// Remove the sessionstore.js file before setting the interval to 0
|
||||
let profilePath = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 448741 **/
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let uniqueName = "bug 448741";
|
||||
let uniqueValue = "as good as unique: " + Date.now();
|
||||
|
||||
// set a unique value on a new, blank tab
|
||||
var tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.stop();
|
||||
ss.setTabValue(tab, uniqueName, uniqueValue);
|
||||
let valueWasCleaned = false;
|
||||
|
||||
// prevent our value from being written to disk
|
||||
function cleaningObserver(aSubject, aTopic, aData) {
|
||||
ok(aTopic == "sessionstore-state-write", "observed correct topic?");
|
||||
ok(aSubject instanceof Ci.nsISupportsString, "subject is a string?");
|
||||
ok(aSubject.data.indexOf(uniqueValue) > -1, "data contains our value?");
|
||||
|
||||
// find the data for the newly added tab and delete it
|
||||
let state = JSON.parse(aSubject.data);
|
||||
state.windows.forEach(function (winData) {
|
||||
winData.tabs.forEach(function (tabData) {
|
||||
if (tabData.extData && uniqueName in tabData.extData &&
|
||||
tabData.extData[uniqueName] == uniqueValue) {
|
||||
delete tabData.extData[uniqueName];
|
||||
valueWasCleaned = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ok(valueWasCleaned, "found and removed the specific tab value");
|
||||
aSubject.data = JSON.stringify(state);
|
||||
Services.obs.removeObserver(cleaningObserver, aTopic);
|
||||
}
|
||||
|
||||
// make sure that all later observers don't see that value any longer
|
||||
function checkingObserver(aSubject, aTopic, aData) {
|
||||
ok(valueWasCleaned && aSubject instanceof Ci.nsISupportsString,
|
||||
"ready to check the cleaned state?");
|
||||
ok(aSubject.data.indexOf(uniqueValue) == -1, "data no longer contains our value?");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
Services.obs.removeObserver(checkingObserver, aTopic);
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
finish();
|
||||
}
|
||||
|
||||
// last added observers are invoked first
|
||||
Services.obs.addObserver(checkingObserver, "sessionstore-state-write", false);
|
||||
Services.obs.addObserver(cleaningObserver, "sessionstore-state-write", false);
|
||||
|
||||
// trigger an immediate save operation
|
||||
gPrefService.setIntPref("browser.sessionstore.interval", 0);
|
||||
}
|
|
@ -20,11 +20,12 @@ function testBug600545() {
|
|||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
|
||||
// This tests the following use case:
|
||||
// When multiple windows are open and browser.sessionstore.resume_from_crash
|
||||
// preference is false, tab session data for non-active window is stripped for
|
||||
// non-pinned tabs. This occurs after "sessionstore-state-write" fires which
|
||||
// will only fire in this case if there is at least one pinned tab.
|
||||
// This tests the following use case: When multiple windows are open
|
||||
// and browser.sessionstore.resume_from_crash preference is false,
|
||||
// tab session data for non-active window is stripped for non-pinned
|
||||
// tabs. This occurs after "sessionstore-state-write-complete"
|
||||
// fires which will only fire in this case if there is at least one
|
||||
// pinned tab.
|
||||
let state = { windows: [
|
||||
{
|
||||
tabs: [
|
||||
|
|
|
@ -1,125 +1,86 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let newWin;
|
||||
let newTab;
|
||||
|
||||
function test() {
|
||||
add_task(function* setup() {
|
||||
/** Test for Bug 625016 - Restore windows closed in succession to quit (non-OSX only) **/
|
||||
|
||||
// We'll test this by opening a new window, waiting for the save event, then
|
||||
// closing that window. We'll observe the "sessionstore-state-write" notification
|
||||
// and check that the state contains no _closedWindows. We'll then add a new
|
||||
// tab and make sure that the state following that was reset and the closed
|
||||
// window is now in _closedWindows.
|
||||
// We'll test this by opening a new window, waiting for the save
|
||||
// event, then closing that window. We'll observe the
|
||||
// "sessionstore-state-write-complete" notification and check that
|
||||
// the state contains no _closedWindows. We'll then add a new tab
|
||||
// and make sure that the state following that was reset and the
|
||||
// closed window is now in _closedWindows.
|
||||
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(2);
|
||||
|
||||
// We speed up the interval between session saves to ensure that the test
|
||||
// runs quickly.
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
yield forceSaveState();
|
||||
|
||||
waitForSaveState(setup);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
// We'll clear all closed windows to make sure our state is clean
|
||||
// forgetClosedWindow doesn't trigger a delayed save
|
||||
while (ss.getClosedWindowCount()) {
|
||||
ss.forgetClosedWindow(0);
|
||||
}
|
||||
is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
|
||||
});
|
||||
|
||||
// Open a new window, which should trigger a save event soon.
|
||||
waitForSaveState(onSaveState);
|
||||
newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:rights");
|
||||
}
|
||||
|
||||
function onSaveState() {
|
||||
add_task(function* new_window() {
|
||||
let newWin;
|
||||
try {
|
||||
ss.getWindowValue(newWin, "foobar");
|
||||
} catch (e) {
|
||||
// The window is untracked which means that the saveState() call isn't the
|
||||
// one we're waiting for. It's most likely been triggered by an async
|
||||
// collection running in the background.
|
||||
waitForSaveState(onSaveState);
|
||||
return;
|
||||
newWin = yield promiseNewWindowLoaded();
|
||||
let tab = newWin.gBrowser.addTab("http://example.com/browser_625016.js?" + Math.random());
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// Double check that we have no closed windows
|
||||
is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
|
||||
|
||||
yield promiseWindowClosed(newWin);
|
||||
newWin = null;
|
||||
|
||||
let state = JSON.parse((yield promiseSaveFileContents()));
|
||||
is(state.windows.length, 2,
|
||||
"observe1: 2 windows in data written to disk");
|
||||
is(state._closedWindows.length, 0,
|
||||
"observe1: no closed windows in data written to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe1: 1 closed window according to API");
|
||||
} finally {
|
||||
if (newWin) {
|
||||
yield promiseWindowClosed(newWin);
|
||||
}
|
||||
yield forceSaveState();
|
||||
}
|
||||
|
||||
// Double check that we have no closed windows
|
||||
is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
|
||||
|
||||
Services.obs.addObserver(observe1, "sessionstore-state-write", false);
|
||||
|
||||
// Now close the new window, which should trigger another save event
|
||||
newWin.close();
|
||||
}
|
||||
|
||||
function observe1(aSubject, aTopic, aData) {
|
||||
info("observe1: " + aTopic);
|
||||
switch (aTopic) {
|
||||
case "sessionstore-state-write":
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
let state = JSON.parse(aSubject.data);
|
||||
is(state.windows.length, 2,
|
||||
"observe1: 2 windows in data being writted to disk");
|
||||
is(state._closedWindows.length, 0,
|
||||
"observe1: no closed windows in data being writted to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe1: 1 closed window according to API");
|
||||
Services.obs.removeObserver(observe1, "sessionstore-state-write");
|
||||
Services.obs.addObserver(observe1, "sessionstore-state-write-complete", false);
|
||||
break;
|
||||
case "sessionstore-state-write-complete":
|
||||
Services.obs.removeObserver(observe1, "sessionstore-state-write-complete");
|
||||
openTab();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function observe2(aSubject, aTopic, aData) {
|
||||
info("observe2: " + aTopic);
|
||||
switch (aTopic) {
|
||||
case "sessionstore-state-write":
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
let state = JSON.parse(aSubject.data);
|
||||
is(state.windows.length, 1,
|
||||
"observe2: 1 window in data being writted to disk");
|
||||
is(state._closedWindows.length, 1,
|
||||
"observe2: 1 closed window in data being writted to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe2: 1 closed window according to API");
|
||||
Services.obs.removeObserver(observe2, "sessionstore-state-write");
|
||||
Services.obs.addObserver(observe2, "sessionstore-state-write-complete", false);
|
||||
break;
|
||||
case "sessionstore-state-write-complete":
|
||||
Services.obs.removeObserver(observe2, "sessionstore-state-write-complete");
|
||||
done();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We'll open a tab, which should trigger another state save which would wipe
|
||||
// the _shouldRestore attribute from the closed window
|
||||
function openTab() {
|
||||
Services.obs.addObserver(observe2, "sessionstore-state-write", false);
|
||||
newTab = gBrowser.addTab("about:mozilla");
|
||||
}
|
||||
add_task(function* new_tab() {
|
||||
let newTab;
|
||||
try {
|
||||
newTab = gBrowser.addTab("about:mozilla");
|
||||
|
||||
function done() {
|
||||
gBrowser.removeTab(newTab);
|
||||
let state = JSON.parse((yield promiseSaveFileContents()));
|
||||
is(state.windows.length, 1,
|
||||
"observe2: 1 window in data being written to disk");
|
||||
is(state._closedWindows.length, 1,
|
||||
"observe2: 1 closed window in data being written to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe2: 1 closed window according to API");
|
||||
} finally {
|
||||
gBrowser.removeTab(newTab);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
add_task(function* done() {
|
||||
// The API still represents the closed window as closed, so we can clear it
|
||||
// with the API, but just to make sure...
|
||||
is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
|
||||
ss.forgetClosedWindow(0);
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
||||
// is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
|
||||
while (ss.getClosedWindowCount()) {
|
||||
ss.forgetClosedWindow(0);
|
||||
}
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
|
|
|
@ -162,15 +162,9 @@ function waitForWindowClose(aWin, aCallback) {
|
|||
}
|
||||
|
||||
function forceWriteState(aCallback) {
|
||||
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "sessionstore-state-write") {
|
||||
Services.obs.removeObserver(observe, aTopic);
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
aCallback(JSON.parse(aSubject.data));
|
||||
}
|
||||
}, "sessionstore-state-write", false);
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 0);
|
||||
return promiseSaveFileContents().then(function(data) {
|
||||
aCallback(JSON.parse(data));
|
||||
});
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
|
|
|
@ -24,43 +24,9 @@ let gDecoder = new TextDecoder();
|
|||
let gSSData;
|
||||
let gSSBakData;
|
||||
|
||||
// Wait for a state write to complete and then execute a callback.
|
||||
function waitForSaveStateComplete(aSaveStateCallback) {
|
||||
let topic = "sessionstore-state-write-complete";
|
||||
|
||||
function observer() {
|
||||
Services.prefs.clearUserPref(PREF_SS_INTERVAL);
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
executeSoon(function taskCallback() {
|
||||
Task.spawn(aSaveStateCallback);
|
||||
});
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, topic, false);
|
||||
}
|
||||
|
||||
// Register next test callback and trigger state saving change.
|
||||
function nextTest(testFunc) {
|
||||
waitForSaveStateComplete(testFunc);
|
||||
|
||||
// We set the interval for session store state saves to be zero
|
||||
// to cause a save ASAP.
|
||||
Services.prefs.setIntPref(PREF_SS_INTERVAL, 0);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Cleaning up after the test: removing the sessionstore.bak file.
|
||||
Task.spawn(function cleanupTask() {
|
||||
yield OS.File.remove(backupPath);
|
||||
});
|
||||
});
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
nextTest(testAfterFirstWrite);
|
||||
}
|
||||
|
||||
function testAfterFirstWrite() {
|
||||
add_task(function* testAfterFirstWrite() {
|
||||
// Ensure sessionstore.bak is not created. We start with a clean
|
||||
// profile so there was nothing to move to sessionstore.bak before
|
||||
// initially writing sessionstore.js
|
||||
|
@ -78,10 +44,10 @@ function testAfterFirstWrite() {
|
|||
// and a backup would not be triggered again.
|
||||
yield OS.File.move(path, backupPath);
|
||||
|
||||
nextTest(testReadBackup);
|
||||
}
|
||||
yield forceSaveState();
|
||||
});
|
||||
|
||||
function testReadBackup() {
|
||||
add_task(function* testReadBackup() {
|
||||
// Ensure sessionstore.bak is finally created.
|
||||
let ssExists = yield OS.File.exists(path);
|
||||
let ssBackupExists = yield OS.File.exists(backupPath);
|
||||
|
@ -114,10 +80,10 @@ function testReadBackup() {
|
|||
is(ssDataRead, gSSBakData,
|
||||
"SessionFile.read read sessionstore.bak correctly.");
|
||||
|
||||
nextTest(testBackupUnchanged);
|
||||
}
|
||||
yield forceSaveState();
|
||||
});
|
||||
|
||||
function testBackupUnchanged() {
|
||||
add_task(function* testBackupUnchanged() {
|
||||
// Ensure sessionstore.bak is backed up only once.
|
||||
|
||||
// Read sessionstore.bak data.
|
||||
|
@ -125,6 +91,9 @@ function testBackupUnchanged() {
|
|||
let ssBakData = gDecoder.decode(array);
|
||||
// Ensure the sessionstore.bak did not change.
|
||||
is(ssBakData, gSSBakData, "sessionstore.bak is unchanged.");
|
||||
});
|
||||
|
||||
executeSoon(finish);
|
||||
}
|
||||
add_task(function* cleanup() {
|
||||
// Cleaning up after the test: removing the sessionstore.bak file.
|
||||
yield OS.File.remove(backupPath);
|
||||
});
|
||||
|
|
|
@ -243,12 +243,7 @@ function waitForTopic(aTopic, aTimeout, aCallback) {
|
|||
|
||||
/**
|
||||
* Wait until session restore has finished collecting its data and is
|
||||
* getting ready to write that data ("sessionstore-state-write").
|
||||
*
|
||||
* This function is meant to be called immediately after the code
|
||||
* that will trigger the saving.
|
||||
*
|
||||
* Note that this does not wait for the disk write to be complete.
|
||||
* has written that data ("sessionstore-state-write-complete").
|
||||
*
|
||||
* @param {function} aCallback If sessionstore-state-write is sent
|
||||
* within buffering interval + 100 ms, the callback is passed |true|,
|
||||
|
@ -257,7 +252,7 @@ function waitForTopic(aTopic, aTimeout, aCallback) {
|
|||
function waitForSaveState(aCallback) {
|
||||
let timeout = 100 +
|
||||
Services.prefs.getIntPref("browser.sessionstore.interval");
|
||||
return waitForTopic("sessionstore-state-write", timeout, aCallback);
|
||||
return waitForTopic("sessionstore-state-write-complete", timeout, aCallback);
|
||||
}
|
||||
function promiseSaveState() {
|
||||
let deferred = Promise.defer();
|
||||
|
@ -272,22 +267,30 @@ function promiseSaveState() {
|
|||
function forceSaveState() {
|
||||
let promise = promiseSaveState();
|
||||
const PREF = "browser.sessionstore.interval";
|
||||
let original = Services.prefs.getIntPref(PREF);
|
||||
// Set interval to an arbitrary non-0 duration
|
||||
// to ensure that setting it to 0 will notify observers
|
||||
Services.prefs.setIntPref(PREF, 1000);
|
||||
Services.prefs.setIntPref(PREF, 0);
|
||||
return promise.then(
|
||||
function onSuccess(x) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
Services.prefs.setIntPref(PREF, original);
|
||||
return x;
|
||||
},
|
||||
function onError(x) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
Services.prefs.setIntPref(PREF, original);
|
||||
throw x;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function promiseSaveFileContents() {
|
||||
let promise = forceSaveState();
|
||||
return promise.then(function() {
|
||||
return OS.File.read(OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"), { encoding: "utf-8" });
|
||||
});
|
||||
}
|
||||
|
||||
function whenBrowserLoaded(aBrowser, aCallback = next, ignoreSubFrames = true) {
|
||||
aBrowser.addEventListener("load", function onLoad(event) {
|
||||
if (!ignoreSubFrames || event.target == aBrowser.contentDocument) {
|
||||
|
@ -321,6 +324,11 @@ function whenWindowLoaded(aWindow, aCallback = next) {
|
|||
});
|
||||
}, false);
|
||||
}
|
||||
function promiseWindowLoaded(aWindow) {
|
||||
let deferred = Promise.defer();
|
||||
whenWindowLoaded(aWindow, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function whenTabRestored(aTab, aCallback = next) {
|
||||
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
|
||||
|
|
|
@ -110,6 +110,7 @@ skip-if = true # Bug 922422
|
|||
[browser_tabview_bug641802.js]
|
||||
[browser_tabview_bug642793.js]
|
||||
[browser_tabview_bug643392.js]
|
||||
skip-if = os == 'linux'&&debug # bug 989083
|
||||
[browser_tabview_bug644097.js]
|
||||
[browser_tabview_bug648882.js]
|
||||
skip-if = true # Bug 752862
|
||||
|
|
|
@ -6,13 +6,13 @@ const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionSto
|
|||
let state = {
|
||||
windows: [{
|
||||
tabs: [{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: true,
|
||||
extData: {"tabview-tab": '{"url":"about:blank","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
|
||||
extData: {"tabview-tab": '{"url":"about:robots","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
|
||||
},{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: false,
|
||||
extData: {"tabview-tab": '{"url":"about:blank","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
|
||||
extData: {"tabview-tab": '{"url":"about:robots","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
|
||||
}],
|
||||
selected: 2,
|
||||
extData: {
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
let state = {
|
||||
windows: [{
|
||||
tabs: [{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: true,
|
||||
extData: {"tabview-tab": '{"url":"about:blank","groupID":1,"bounds":{"left":120,"top":20,"width":20,"height":20}}'}
|
||||
extData: {"tabview-tab": '{"url":"about:robots","groupID":1,"bounds":{"left":120,"top":20,"width":20,"height":20}}'}
|
||||
},{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: false,
|
||||
extData: {"tabview-tab": '{"url":"about:blank","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
|
||||
extData: {"tabview-tab": '{"url":"about:robots","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
|
||||
}],
|
||||
selected: 2,
|
||||
extData: {
|
||||
|
|
|
@ -8,23 +8,23 @@ function test() {
|
|||
let newState = {
|
||||
windows: [{
|
||||
tabs: [{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: true,
|
||||
attributes: {},
|
||||
extData: {
|
||||
"tabview-tab":
|
||||
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
|
||||
'"userSize":null,"url":"about:blank","groupID":1,' +
|
||||
'"userSize":null,"url":"about:robots","groupID":1,' +
|
||||
'"imageData":null,"title":null}'
|
||||
}
|
||||
},{
|
||||
entries: [{ url: "about:blank" }],
|
||||
entries: [{ url: "about:robots" }],
|
||||
hidden: false,
|
||||
attributes: {},
|
||||
extData: {
|
||||
"tabview-tab":
|
||||
'{"bounds":{"left":315,"top":29,"width":111,"height":84},' +
|
||||
'"userSize":null,"url":"about:blank","groupID":2,' +
|
||||
'"userSize":null,"url":"about:robots","groupID":2,' +
|
||||
'"imageData":null,"title":null}'
|
||||
},
|
||||
}],
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-trace-malloc
|
||||
ac_add_options --enable-signmar
|
||||
ac_add_options --enable-metro
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --with-l10n-base=../../l10n
|
||||
ac_add_options --enable-metro
|
||||
ac_add_options --with-windows-version=601
|
||||
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --enable-metro
|
||||
if [ -f /c/builds/gapi.data ]; then
|
||||
_gapi_keyfile=/c/builds/gapi.data
|
||||
else
|
||||
|
|
|
@ -6,7 +6,6 @@ ac_add_options --host=x86_64-pc-mingw32
|
|||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-trace-malloc
|
||||
ac_add_options --enable-signmar
|
||||
ac_add_options --enable-metro
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
|
|
@ -2175,22 +2175,6 @@ Object.defineProperties(window, {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper method for parsing a resource URI, like
|
||||
* `resource://gre/modules/commonjs/sdk/tabs.js`, and pulling out `sdk/tabs.js`
|
||||
* if it's in the SDK, or `null` otherwise.
|
||||
*
|
||||
* @param string url
|
||||
* @return string|null
|
||||
*/
|
||||
function getSDKModuleName(url) {
|
||||
let match = (url || "").match(/^resource:\/\/gre\/modules\/commonjs\/(.*)/);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for debugging.
|
||||
* @param string
|
||||
|
|
|
@ -11,6 +11,11 @@ const SAMPLE_SIZE = 50; // no of lines
|
|||
const INDENT_COUNT_THRESHOLD = 5; // percentage
|
||||
const CHARACTER_LIMIT = 250; // line character limit
|
||||
|
||||
// Maps known URLs to friendly source group names
|
||||
const KNOWN_SOURCE_GROUPS = {
|
||||
"Add-on SDK": "resource://gre/modules/commonjs/",
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling the sources UI.
|
||||
*/
|
||||
|
@ -49,6 +54,15 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
showArrows: true
|
||||
});
|
||||
|
||||
// Sort known source groups towards the end of the list
|
||||
this.widget.groupSortPredicate = function(a, b) {
|
||||
if ((a in KNOWN_SOURCE_GROUPS) == (b in KNOWN_SOURCE_GROUPS)) {
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
return (a in KNOWN_SOURCE_GROUPS) ? 1 : -1;
|
||||
};
|
||||
|
||||
this.emptyText = L10N.getStr("noSourcesText");
|
||||
this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip");
|
||||
|
||||
|
@ -132,12 +146,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
let group = SourceUtils.getSourceGroup(url);
|
||||
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(fullUrl));
|
||||
|
||||
let sdkModuleName = getSDKModuleName(url);
|
||||
if (sdkModuleName) {
|
||||
label = sdkModuleName;
|
||||
group = "Add-on SDK";
|
||||
}
|
||||
|
||||
let contents = document.createElement("label");
|
||||
contents.className = "plain dbg-source-item";
|
||||
contents.setAttribute("value", label);
|
||||
|
@ -1560,7 +1568,17 @@ let SourceUtils = {
|
|||
return cachedLabel;
|
||||
}
|
||||
|
||||
let sourceLabel = this.trimUrl(aUrl);
|
||||
let sourceLabel = null;
|
||||
|
||||
for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
|
||||
if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
|
||||
sourceLabel = aUrl.substring(KNOWN_SOURCE_GROUPS[name].length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceLabel) {
|
||||
sourceLabel = this.trimUrl(aUrl);
|
||||
}
|
||||
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
|
||||
this._labelsCache.set(aUrl, unicodeLabel);
|
||||
return unicodeLabel;
|
||||
|
@ -1583,14 +1601,20 @@ let SourceUtils = {
|
|||
|
||||
try {
|
||||
// Use an nsIURL to parse all the url path parts.
|
||||
let url = aUrl.split(" -> ").pop();
|
||||
var uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL);
|
||||
var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
||||
} catch (e) {
|
||||
// This doesn't look like a url, or nsIURL can't handle it.
|
||||
return "";
|
||||
}
|
||||
|
||||
let groupLabel = uri.prePath;
|
||||
|
||||
for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
|
||||
if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
|
||||
groupLabel = name;
|
||||
}
|
||||
}
|
||||
|
||||
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
|
||||
this._groupsCache.set(aUrl, unicodeLabel)
|
||||
return unicodeLabel;
|
||||
|
|
|
@ -5,7 +5,18 @@
|
|||
|
||||
const ADDON4_URL = EXAMPLE_URL + "addon4.xpi";
|
||||
|
||||
let gAddon, gClient, gThreadClient, gDebugger, gSources;
|
||||
let gAddon, gClient, gThreadClient, gDebugger, gSources, gTitle;
|
||||
|
||||
function onMessage(event) {
|
||||
try {
|
||||
let json = JSON.parse(event.data);
|
||||
switch (json.name) {
|
||||
case "toolbox-title":
|
||||
gTitle = json.data.value;
|
||||
break;
|
||||
}
|
||||
} catch(e) { Cu.reportError(e); }
|
||||
}
|
||||
|
||||
function test() {
|
||||
Task.spawn(function () {
|
||||
|
@ -18,6 +29,8 @@ function test() {
|
|||
let iframe = document.createElement("iframe");
|
||||
document.documentElement.appendChild(iframe);
|
||||
|
||||
window.addEventListener("message", onMessage);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
|
||||
|
@ -43,6 +56,7 @@ function test() {
|
|||
yield closeConnection();
|
||||
yield debuggerPanel._toolbox.destroy();
|
||||
iframe.remove();
|
||||
window.removeEventListener("message", onMessage);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
@ -62,7 +76,7 @@ function testSources(expectSecondModule) {
|
|||
gThreadClient.getSources(({sources}) => {
|
||||
ok(sources.length, "retrieved sources");
|
||||
|
||||
sources.forEach(source => {
|
||||
for (let source of sources) {
|
||||
let url = source.url.split(" -> ").pop();
|
||||
let { label, group } = gSources.getItemByValue(source.url).attachment;
|
||||
|
||||
|
@ -81,12 +95,19 @@ function testSources(expectSecondModule) {
|
|||
} else {
|
||||
ok(false, "Saw an unexpected source: " + url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ok(foundAddonModule, "found JS module for the addon in the list");
|
||||
is(foundAddonModule2, expectSecondModule, "saw the second addon module");
|
||||
ok(foundAddonBootstrap, "found bootstrap script for the addon in the list");
|
||||
|
||||
is(gTitle, "Debugger - Test add-on with JS Modules", "Saw the right toolbox title.");
|
||||
|
||||
let groups = gDebugger.document.querySelectorAll(".side-menu-widget-group-title .name");
|
||||
is(groups[0].value, "jar:", "Add-on bootstrap should be the first group");
|
||||
is(groups[1].value, "resource://browser_dbg_addon4", "Add-on code should be the second group");
|
||||
is(groups.length, 2, "Should be only two groups.");
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,18 @@
|
|||
|
||||
const ADDON3_URL = EXAMPLE_URL + "addon3.xpi";
|
||||
|
||||
let gAddon, gClient, gThreadClient, gDebugger, gSources;
|
||||
let gAddon, gClient, gThreadClient, gDebugger, gSources, gTitle;
|
||||
|
||||
function onMessage(event) {
|
||||
try {
|
||||
let json = JSON.parse(event.data);
|
||||
switch (json.name) {
|
||||
case "toolbox-title":
|
||||
gTitle = json.data.value;
|
||||
break;
|
||||
}
|
||||
} catch(e) { Cu.reportError(e); }
|
||||
}
|
||||
|
||||
function test() {
|
||||
Task.spawn(function () {
|
||||
|
@ -19,6 +30,8 @@ function test() {
|
|||
let iframe = document.createElement("iframe");
|
||||
document.documentElement.appendChild(iframe);
|
||||
|
||||
window.addEventListener("message", onMessage);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
|
||||
|
@ -37,6 +50,7 @@ function test() {
|
|||
yield closeConnection();
|
||||
yield debuggerPanel._toolbox.destroy();
|
||||
iframe.remove();
|
||||
window.removeEventListener("message", onMessage);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
@ -56,7 +70,7 @@ function testSources() {
|
|||
gThreadClient.getSources(({sources}) => {
|
||||
ok(sources.length, "retrieved sources");
|
||||
|
||||
sources.forEach(source => {
|
||||
for (let source of sources) {
|
||||
let url = source.url.split(" -> ").pop();
|
||||
info(source.url + "\n\n\n" + url);
|
||||
let { label, group } = gSources.getItemByValue(source.url).attachment;
|
||||
|
@ -80,7 +94,7 @@ function testSources() {
|
|||
} else {
|
||||
ok(false, "Saw an unexpected source: " + url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ok(foundAddonModule, "found code for the addon in the list");
|
||||
ok(foundAddonBootstrap, "found bootstrap for the addon in the list");
|
||||
|
@ -88,6 +102,14 @@ function testSources() {
|
|||
// built-in browser SDK modules
|
||||
ok(foundSDKModule > 10, "SDK modules are listed");
|
||||
|
||||
is(gTitle, "Debugger - browser_dbg_addon3", "Saw the right toolbox title.");
|
||||
|
||||
let groups = gDebugger.document.querySelectorAll(".side-menu-widget-group-title .name");
|
||||
is(groups[0].value, "jar:", "Add-on bootstrap should be the first group");
|
||||
is(groups[1].value, "resource://jid1-ami3akps3baaeg-at-jetpack", "Add-on code should be the second group");
|
||||
is(groups[2].value, "Add-on SDK", "Add-on SDK should be the third group");
|
||||
is(groups.length, 3, "Should be only three groups.");
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
|
|
|
@ -504,9 +504,9 @@ function initDebugger(aTarget, aWindow) {
|
|||
function initAddonDebugger(aClient, aUrl, aFrame) {
|
||||
info("Initializing an addon debugger panel.");
|
||||
|
||||
return getAddonActorForUrl(aClient, aUrl).then(({actor}) => {
|
||||
return getAddonActorForUrl(aClient, aUrl).then((addonActor) => {
|
||||
let targetOptions = {
|
||||
form: { addonActor: actor },
|
||||
form: { addonActor: addonActor.actor, title: addonActor.name },
|
||||
client: aClient,
|
||||
chrome: true
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ function connect() {
|
|||
if (addonID) {
|
||||
gClient.listAddons(({addons}) => {
|
||||
let addonActor = addons.filter(addon => addon.id === addonID).pop();
|
||||
openToolbox({ addonActor: addonActor.actor });
|
||||
openToolbox({ addonActor: addonActor.actor, title: addonActor.name });
|
||||
});
|
||||
} else {
|
||||
gClient.listTabs(openToolbox);
|
||||
|
|
|
@ -878,7 +878,9 @@ Toolbox.prototype = {
|
|||
*/
|
||||
focusConsoleInput: function() {
|
||||
let hud = this.getPanel("webconsole").hud;
|
||||
hud.jsterm.inputNode.focus();
|
||||
if (hud && hud.jsterm) {
|
||||
hud.jsterm.inputNode.focus();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -964,7 +966,7 @@ Toolbox.prototype = {
|
|||
toolName = toolboxStrings("toolbox.defaultTitle");
|
||||
}
|
||||
let title = toolboxStrings("toolbox.titleTemplate",
|
||||
toolName, this.target.url);
|
||||
toolName, this.target.url || this.target.name);
|
||||
this._host.setTitle(title);
|
||||
},
|
||||
|
||||
|
|
|
@ -299,6 +299,9 @@ MarkupView.prototype = {
|
|||
this.markNodeAsSelected(selection.nodeFront);
|
||||
}
|
||||
done();
|
||||
}, (e) => {
|
||||
console.error(e);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
this.unmarkSelectedNode();
|
||||
|
@ -863,8 +866,10 @@ MarkupView.prototype = {
|
|||
let parent = node.parentNode();
|
||||
if (!container.elt.parentNode) {
|
||||
let parentContainer = this._containers.get(parent);
|
||||
parentContainer.childrenDirty = true;
|
||||
this._updateChildren(parentContainer, {expand: node});
|
||||
if (parentContainer) {
|
||||
parentContainer.childrenDirty = true;
|
||||
this._updateChildren(parentContainer, {expand: node});
|
||||
}
|
||||
}
|
||||
|
||||
node = parent;
|
||||
|
|
|
@ -66,10 +66,15 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aOptions={}) {
|
|||
|
||||
SideMenuWidget.prototype = {
|
||||
/**
|
||||
* Specifies if groups in this container should be sorted alphabetically.
|
||||
* Specifies if groups in this container should be sorted.
|
||||
*/
|
||||
sortedGroups: true,
|
||||
|
||||
/**
|
||||
* The comparator used to sort groups.
|
||||
*/
|
||||
groupSortPredicate: function(a, b) a.localeCompare(b),
|
||||
|
||||
/**
|
||||
* Specifies that the container viewport should be "stuck" to the
|
||||
* bottom. That is, the container is automatically scrolled down to
|
||||
|
@ -342,7 +347,7 @@ SideMenuWidget.prototype = {
|
|||
});
|
||||
|
||||
this._groupsByName.set(aName, group);
|
||||
group.insertSelfAt(this.sortedGroups ? group.findExpectedIndexForSelf() : -1);
|
||||
group.insertSelfAt(this.sortedGroups ? group.findExpectedIndexForSelf(this.groupSortPredicate) : -1);
|
||||
|
||||
return group;
|
||||
},
|
||||
|
@ -484,14 +489,14 @@ SideMenuGroup.prototype = {
|
|||
* @return number
|
||||
* The expected index.
|
||||
*/
|
||||
findExpectedIndexForSelf: function() {
|
||||
findExpectedIndexForSelf: function(sortPredicate) {
|
||||
let identifier = this.identifier;
|
||||
let groupsArray = this._orderedGroupElementsArray;
|
||||
|
||||
for (let group of groupsArray) {
|
||||
let name = group.getAttribute("name");
|
||||
if (name > identifier && // Insertion sort at its best :)
|
||||
!name.contains(identifier)) { // Least significat group should be last.
|
||||
if (sortPredicate(name, identifier) > 0 && // Insertion sort at its best :)
|
||||
!name.contains(identifier)) { // Least significant group should be last.
|
||||
return groupsArray.indexOf(group);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ function testMenuFilterButton(aCategory) {
|
|||
// Turn all the filters off, if they were on.
|
||||
let menuItem = firstMenuItem;
|
||||
while (menuItem != null) {
|
||||
if (isChecked(menuItem)) {
|
||||
if (menuItem.hasAttribute("prefKey") && isChecked(menuItem)) {
|
||||
chooseMenuItem(menuItem);
|
||||
}
|
||||
menuItem = menuItem.nextSibling;
|
||||
|
@ -89,10 +89,12 @@ function testMenuFilterButton(aCategory) {
|
|||
menuItem = firstMenuItem;
|
||||
while (menuItem) {
|
||||
let prefKey = menuItem.getAttribute("prefKey");
|
||||
ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
|
||||
aCategory + " is no longer checked after clicking the button");
|
||||
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
|
||||
"off after clicking the button");
|
||||
if (prefKey) {
|
||||
ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
|
||||
aCategory + " is no longer checked after clicking the button");
|
||||
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
|
||||
"off after clicking the button");
|
||||
}
|
||||
menuItem = menuItem.nextSibling;
|
||||
}
|
||||
|
||||
|
@ -127,7 +129,8 @@ function testMenuFilterButton(aCategory) {
|
|||
while (menuItem) {
|
||||
// The csslog menu item is already unchecked at this point.
|
||||
// Make sure it is not selected. See bug 971798.
|
||||
if (menuItem.getAttribute("prefKey") != "csslog") {
|
||||
prefKey = menuItem.getAttribute("prefKey");
|
||||
if (prefKey && prefKey != "csslog") {
|
||||
chooseMenuItem(menuItem);
|
||||
}
|
||||
menuItem = menuItem.nextSibling;
|
||||
|
@ -164,7 +167,7 @@ function testIsolateFilterButton(aCategory) {
|
|||
aCategory + " should not be checked after isolating for " + aCategory);
|
||||
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages should be " +
|
||||
"turned off after isolating for " + aCategory);
|
||||
} else {
|
||||
} else if (prefKey) {
|
||||
ok(isChecked(item), "menu item " + prefKey + " for category " +
|
||||
aCategory + " is checked after isolating for " + aCategory);
|
||||
ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
|
||||
|
@ -184,10 +187,12 @@ function testIsolateFilterButton(aCategory) {
|
|||
menuItems = filterButton.querySelectorAll("menuitem");
|
||||
Array.forEach(menuItems, (item) => {
|
||||
let prefKey = item.getAttribute("prefKey");
|
||||
ok(!isChecked(item), "menu item " + prefKey + " for category " +
|
||||
aCategory + " is unchecked after isolating for " + aCategory);
|
||||
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
|
||||
"turned off after isolating for " + aCategory);
|
||||
if (prefKey) {
|
||||
ok(!isChecked(item), "menu item " + prefKey + " for category " +
|
||||
aCategory + " is unchecked after isolating for " + aCategory);
|
||||
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
|
||||
"turned off after isolating for " + aCategory);
|
||||
}
|
||||
});
|
||||
|
||||
// Turn all the filters on again by clicking the button.
|
||||
|
|
|
@ -53,6 +53,7 @@ function runSelectionTests(aInspector) {
|
|||
inspector.toolbox.once("picker-started", () => {
|
||||
info("Picker mode started, now clicking on H1 to select that node");
|
||||
executeSoon(() => {
|
||||
h1.scrollIntoView();
|
||||
EventUtils.synthesizeMouseAtCenter(h1, {}, content);
|
||||
inspector.toolbox.once("picker-stopped", () => {
|
||||
info("Picker mode stopped, H1 selected, now switching to the console");
|
||||
|
|
|
@ -401,6 +401,11 @@ WebConsoleFrame.prototype = {
|
|||
*/
|
||||
setSaveRequestAndResponseBodies:
|
||||
function WCF_setSaveRequestAndResponseBodies(aValue) {
|
||||
if (!this.webConsoleClient) {
|
||||
// Don't continue if the webconsole disconnected.
|
||||
return promise.resolve(null);
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
let newValue = !!aValue;
|
||||
let toSet = {
|
||||
|
|
|
@ -104,7 +104,7 @@ function configureLogging() {
|
|||
gLogger = Log.repository.getLogger("Browser.Experiments");
|
||||
gLogger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
|
||||
}
|
||||
gLogger.level = gPrefs.get(PREF_LOGGING_LEVEL, 50);
|
||||
gLogger.level = gPrefs.get(PREF_LOGGING_LEVEL, Log.Level.Warn);
|
||||
|
||||
let logDumping = gPrefs.get(PREF_LOGGING_DUMP, false);
|
||||
if (logDumping != gLogDumping) {
|
||||
|
@ -226,6 +226,11 @@ Experiments.Policy.prototype = {
|
|||
return UpdateChannel.get();
|
||||
},
|
||||
|
||||
locale: function () {
|
||||
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
|
||||
return chrome.getSelectedLocale("global");
|
||||
},
|
||||
|
||||
/*
|
||||
* @return Promise<> Resolved with the payload data.
|
||||
*/
|
||||
|
@ -304,8 +309,10 @@ Experiments.Experiments.prototype = {
|
|||
|
||||
AddonManager.addAddonListener(this);
|
||||
|
||||
this._loadTask = Task.spawn(this._loadFromCache.bind(this)).then(
|
||||
this._loadTask = Task.spawn(this._loadFromCache.bind(this));
|
||||
this._loadTask.then(
|
||||
() => {
|
||||
gLogger.trace("Experiments::_loadTask finished ok");
|
||||
this._loadTask = null;
|
||||
this._run();
|
||||
},
|
||||
|
@ -386,7 +393,7 @@ Experiments.Experiments.prototype = {
|
|||
},
|
||||
|
||||
_telemetryStatusChanged: function () {
|
||||
_toggleExperimentsEnabled(gExperimentsEnabled);
|
||||
this._toggleExperimentsEnabled(gExperimentsEnabled);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -473,10 +480,16 @@ Experiments.Experiments.prototype = {
|
|||
},
|
||||
|
||||
_run: function() {
|
||||
gLogger.trace("Experiments::_run");
|
||||
this._checkForShutdown();
|
||||
if (!this._mainTask) {
|
||||
this._mainTask = Task.spawn(this._main.bind(this)).then(
|
||||
null,
|
||||
this._mainTask = Task.spawn(this._main.bind(this));
|
||||
this._mainTask.then(
|
||||
() => {
|
||||
gLogger.trace("Experiments::_main finished, scheduling next run");
|
||||
this._mainTask = null;
|
||||
this._scheduleNextRun();
|
||||
},
|
||||
(e) => {
|
||||
gLogger.error("Experiments::_main caught error: " + e);
|
||||
this._mainTask = null;
|
||||
|
@ -488,6 +501,7 @@ Experiments.Experiments.prototype = {
|
|||
|
||||
_main: function*() {
|
||||
do {
|
||||
gLogger.trace("Experiments::_main iteration");
|
||||
yield this._loadTask;
|
||||
if (this._refresh) {
|
||||
yield this._loadManifest();
|
||||
|
@ -500,11 +514,10 @@ Experiments.Experiments.prototype = {
|
|||
// while we were running, go again right now.
|
||||
}
|
||||
while (this._refresh || this._terminateReason);
|
||||
this._mainTask = null;
|
||||
this._scheduleNextRun();
|
||||
},
|
||||
|
||||
_loadManifest: function*() {
|
||||
gLogger.trace("Experiments::_loadManifest");
|
||||
let uri = Services.urlFormatter.formatURLPref(PREF_BRANCH + PREF_MANIFEST_URI);
|
||||
|
||||
this._checkForShutdown();
|
||||
|
@ -652,6 +665,7 @@ Experiments.Experiments.prototype = {
|
|||
* Part of the main task to save the cache to disk, called from _main.
|
||||
*/
|
||||
_saveToCache: function* () {
|
||||
gLogger.trace("Experiments::_saveToCache");
|
||||
let path = this._cacheFilePath;
|
||||
let textData = JSON.stringify({
|
||||
version: CACHE_VERSION,
|
||||
|
@ -670,6 +684,7 @@ Experiments.Experiments.prototype = {
|
|||
* Task function, load the cached experiments manifest file from disk.
|
||||
*/
|
||||
_loadFromCache: function*() {
|
||||
gLogger.trace("Experiments::_loadFromCache");
|
||||
let path = this._cacheFilePath;
|
||||
try {
|
||||
let result = yield loadJSONAsync(path, { compression: "lz4" });
|
||||
|
@ -706,7 +721,7 @@ Experiments.Experiments.prototype = {
|
|||
* array in the manifest
|
||||
*/
|
||||
_updateExperiments: function (manifestObject) {
|
||||
gLogger.trace("Experiments::updateExperiments() - experiments: " + JSON.stringify(manifestObject));
|
||||
gLogger.trace("Experiments::_updateExperiments() - experiments: " + JSON.stringify(manifestObject));
|
||||
|
||||
if (manifestObject.version !== MANIFEST_VERSION) {
|
||||
gLogger.warning("Experiments::updateExperiments() - unsupported version " + manifestObject.version);
|
||||
|
@ -1149,9 +1164,8 @@ Experiments.ExperimentEntry.prototype = {
|
|||
let app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
|
||||
let runtime = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime);
|
||||
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
|
||||
|
||||
let locale = chrome.getSelectedLocale("global");
|
||||
let locale = this._policy.locale();
|
||||
let channel = this._policy.updatechannel();
|
||||
let data = this._manifestData;
|
||||
|
||||
|
@ -1161,6 +1175,7 @@ Experiments.ExperimentEntry.prototype = {
|
|||
let startSec = (this.startDate || 0) / 1000;
|
||||
|
||||
gLogger.trace("ExperimentEntry::isApplicable() - now=" + now
|
||||
+ ", randomValue=" + this._randomValue
|
||||
+ ", data=" + JSON.stringify(this._manifestData));
|
||||
|
||||
// Not applicable if it already ran.
|
||||
|
@ -1183,11 +1198,11 @@ Experiments.ExperimentEntry.prototype = {
|
|||
{ name: "endTime",
|
||||
condition: () => now < data.endTime },
|
||||
{ name: "maxStartTime",
|
||||
condition: () => !data.maxStartTime || now <= (data.maxStartTime - minActive) },
|
||||
condition: () => !data.maxStartTime || now <= data.maxStartTime },
|
||||
{ name: "maxActiveSeconds",
|
||||
condition: () => !this._startDate || now <= (startSec + maxActive) },
|
||||
{ name: "appName",
|
||||
condition: () => !data.name || data.appName.indexOf(app.name) != -1 },
|
||||
condition: () => !data.appName || data.appName.indexOf(app.name) != -1 },
|
||||
{ name: "minBuildID",
|
||||
condition: () => !data.minBuildID || app.platformBuildID >= data.minBuildID },
|
||||
{ name: "maxBuildID",
|
||||
|
@ -1201,9 +1216,9 @@ Experiments.ExperimentEntry.prototype = {
|
|||
{ name: "locale",
|
||||
condition: () => !data.locale || data.locale.indexOf(locale) != -1 },
|
||||
{ name: "sample",
|
||||
condition: () => !data.sample || this._randomValue <= data.sample },
|
||||
condition: () => data.sample === undefined || this._randomValue <= data.sample },
|
||||
{ name: "version",
|
||||
condition: () => !data.version || data.appVersion.indexOf(app.version) != -1 },
|
||||
condition: () => !data.version || data.version.indexOf(app.version) != -1 },
|
||||
{ name: "minVersion",
|
||||
condition: () => !data.minVersion || versionCmp.compare(app.version, data.minVersion) >= 0 },
|
||||
{ name: "maxVersion",
|
||||
|
|
|
@ -3,6 +3,6 @@ contract @mozilla.org/browser/experiments-service;1 {f7800463-3b97-47f9-9341-b76
|
|||
category update-timer ExperimentsService @mozilla.org/browser/experiments-service;1,getService,experiments-update-timer,experiments.manifest.fetchIntervalSeconds,86400
|
||||
category profile-after-change ExperimentsService @mozilla.org/browser/experiments-service;1
|
||||
|
||||
category healthreport-js-provider-default ExperimentsProvider resource://gre/browser/modules/Experiments/Experiments.jsm
|
||||
category healthreport-js-provider-default ExperimentsProvider resource:///modules/experiments/Experiments.jsm
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ const EXPERIMENT2_XPI_NAME = "experiment-2.xpi";
|
|||
const EXPERIMENT3_ID = "test-experiment-3@tests.mozilla.org";
|
||||
const EXPERIMENT4_ID = "test-experiment-4@tests.mozilla.org";
|
||||
|
||||
const DEFAULT_BUILDID = "2014060601";
|
||||
|
||||
const FAKE_EXPERIMENTS_1 = [
|
||||
{
|
||||
id: "id1",
|
||||
|
@ -169,7 +171,7 @@ function createAppInfo(options) {
|
|||
let platformVersion = options.platformVersion || "1.0";
|
||||
let date = options.date || new Date();
|
||||
|
||||
let buildID = "" + date.getYear() + date.getMonth() + date.getDate() + "01";
|
||||
let buildID = options.buildID || DEFAULT_BUILDID;
|
||||
|
||||
gAppInfo = {
|
||||
// nsIXULAppInfo
|
||||
|
|
|
@ -63,6 +63,7 @@ add_task(function* test_setup() {
|
|||
gReporter = yield getReporter("json_payload_simple");
|
||||
yield gReporter.collectMeasurements();
|
||||
let payload = yield gReporter.getJSONPayload(true);
|
||||
do_register_cleanup(() => gReporter._shutdown());
|
||||
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
|
@ -131,8 +132,3 @@ add_task(function* test_startStop() {
|
|||
Assert.equal(maybeStop, true, "Experiment should have been stopped.");
|
||||
Assert.equal(experiment.enabled, false, "Experiment should be disabled.");
|
||||
});
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield gReporter._shutdown();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -75,6 +75,7 @@ add_task(function* test_setup() {
|
|||
gReporter = yield getReporter("json_payload_simple");
|
||||
yield gReporter.collectMeasurements();
|
||||
let payload = yield gReporter.getJSONPayload(true);
|
||||
do_register_cleanup(() => gReporter._shutdown());
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
patchPolicy(gPolicy, {
|
||||
|
@ -1278,9 +1279,3 @@ add_task(function* test_unexpectedUninstall() {
|
|||
yield experiments.uninit();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield gReporter._shutdown();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -76,6 +76,7 @@ add_task(function* test_setup() {
|
|||
gReporter = yield getReporter("json_payload_simple");
|
||||
yield gReporter.collectMeasurements();
|
||||
let payload = yield gReporter.getJSONPayload(true);
|
||||
do_register_cleanup(() => gReporter._shutdown());
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
patchPolicy(gPolicy, {
|
||||
|
@ -264,8 +265,3 @@ add_task(function* test_cache() {
|
|||
yield experiments.uninit();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield gReporter._shutdown();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -61,10 +61,13 @@ add_task(function* test_setup() {
|
|||
gReporter = yield getReporter("json_payload_simple");
|
||||
yield gReporter.collectMeasurements();
|
||||
let payload = yield gReporter.getJSONPayload(true);
|
||||
do_register_cleanup(() => gReporter._shutdown());
|
||||
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
locale: () => "en-US",
|
||||
healthReportPayload: () => Promise.resolve(payload),
|
||||
random: () => 0.5,
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
|
@ -108,10 +111,81 @@ const sanityFilter = function filter(c) {
|
|||
add_task(function* test_simpleFields() {
|
||||
let testData = [
|
||||
// "expected applicable?", failure reason or null, manifest data
|
||||
|
||||
// misc. environment
|
||||
|
||||
[false, ["appName"], {appName: []}],
|
||||
[false, ["appName"], {appName: ["foo", gAppInfo.name + "-invalid"]}],
|
||||
[true, null, {appName: ["not-an-app-name", gAppInfo.name]}],
|
||||
|
||||
[false, ["os"], {os: []}],
|
||||
[false, ["os"], {os: ["42", "abcdef"]}],
|
||||
[true, null, {os: [gAppInfo.OS, "plan9"]}],
|
||||
[true, null, {os: [gAppInfo.OS, "plan9"]}],
|
||||
|
||||
[false, ["channel"], {channel: []}],
|
||||
[false, ["channel"], {channel: ["foo", gPolicy.updatechannel() + "-invalid"]}],
|
||||
[true, null, {channel: ["not-a-channel", gPolicy.updatechannel()]}],
|
||||
|
||||
[false, ["locale"], {locale: []}],
|
||||
[false, ["locale"], {locale: ["foo", gPolicy.locale + "-invalid"]}],
|
||||
[true, null, {locale: ["not-a-locale", gPolicy.locale()]}],
|
||||
|
||||
// version
|
||||
|
||||
[false, ["version"], {version: []}],
|
||||
[false, ["version"], {version: ["-1", gAppInfo.version + "-invalid", "asdf", "0,4", "99.99", "0.1.1.1"]}],
|
||||
[true, null, {version: ["99999999.999", "-1", gAppInfo.version]}],
|
||||
|
||||
[false, ["minVersion"], {minVersion: "1.0.1"}],
|
||||
[true, null, {minVersion: "1.0b1"}],
|
||||
[true, null, {minVersion: "1.0"}],
|
||||
[true, null, {minVersion: "0.9"}],
|
||||
|
||||
[false, ["maxVersion"], {maxVersion: "0.1"}],
|
||||
[false, ["maxVersion"], {maxVersion: "0.9.9"}],
|
||||
[false, ["maxVersion"], {maxVersion: "1.0b1"}],
|
||||
[true, ["maxVersion"], {maxVersion: "1.0"}],
|
||||
[true, ["maxVersion"], {maxVersion: "1.7pre"}],
|
||||
|
||||
// build id
|
||||
|
||||
[false, ["buildIDs"], {buildIDs: []}],
|
||||
[false, ["buildIDs"], {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}],
|
||||
[true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
|
||||
[true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
|
||||
|
||||
[true, null, {minBuildID: "2014060501"}],
|
||||
[true, null, {minBuildID: "2014060601"}],
|
||||
[false, ["minBuildID"], {minBuildID: "2014060701"}],
|
||||
|
||||
[false, ["maxBuildID"], {maxBuildID: "2014010101"}],
|
||||
[true, null, {maxBuildID: "2014060601"}],
|
||||
[true, null, {maxBuildID: "2014060901"}],
|
||||
|
||||
// sample
|
||||
|
||||
[false, ["sample"], {sample: -1 }],
|
||||
[false, ["sample"], {sample: 0.0}],
|
||||
[false, ["sample"], {sample: 0.1}],
|
||||
[true, null, {sample: 0.5}],
|
||||
[true, null, {sample: 0.6}],
|
||||
[true, null, {sample: 1.0}],
|
||||
[true, null, {sample: 0.5}],
|
||||
|
||||
// experiment control
|
||||
|
||||
[false, ["disabled"], {disabled: true}],
|
||||
[true, null, {disabled: false}],
|
||||
|
||||
[false, ["frozen"], {frozen: true}],
|
||||
[true, null, {frozen: false}],
|
||||
|
||||
[false, null, {frozen: true, disabled: true}],
|
||||
[false, null, {frozen: true, disabled: false}],
|
||||
[false, null, {frozen: false, disabled: true}],
|
||||
[true, null, {frozen: false, disabled: false}],
|
||||
|
||||
// jsfilter
|
||||
|
||||
[true, null, {jsfilter: "function filter(c) { return true; }"}],
|
||||
[false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}],
|
||||
[true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy
|
||||
|
@ -150,18 +224,73 @@ add_task(function* test_simpleFields() {
|
|||
});
|
||||
|
||||
add_task(function* test_times() {
|
||||
let baseDate = new Date(2014, 5, 6, 12);
|
||||
let baseTimeSec = baseDate.getTime() / 1000;
|
||||
let now = new Date(2014, 5, 6, 12);
|
||||
let nowSec = now.getTime() / 1000;
|
||||
let testData = [
|
||||
// "expected applicable?", rejection reason or null, fake now date, manifest data
|
||||
[false, "maxStartTime", baseDate,
|
||||
{maxStartTime: baseTimeSec - 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "endTime", baseDate,
|
||||
{startTime: baseTimeSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: baseTimeSec - 5 * SEC_IN_ONE_DAY}],
|
||||
[true, null, baseDate,
|
||||
{startTime: baseTimeSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: baseTimeSec + 10 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// start time
|
||||
|
||||
[true, null, now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{startTime: nowSec ,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "startTime", now,
|
||||
{startTime: nowSec + 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// end time
|
||||
|
||||
[false, "endTime", now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec - 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "endTime", now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec - 5 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// max start time
|
||||
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 15 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 1 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxStartTime: nowSec,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxStartTime: nowSec + 1 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// max active seconds
|
||||
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 5 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 15 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 20 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
];
|
||||
|
||||
for (let i=0; i<testData.length; ++i) {
|
||||
|
@ -186,8 +315,3 @@ add_task(function* test_times() {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield gReporter._shutdown();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -77,6 +77,3 @@ add_task(function* test_fetchInvalid() {
|
|||
yield ex.uninit();
|
||||
});
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -114,6 +114,7 @@ add_task(function* test_setup() {
|
|||
gReporter = yield getReporter("json_payload_simple");
|
||||
yield gReporter.collectMeasurements();
|
||||
let payload = yield gReporter.getJSONPayload(true);
|
||||
do_register_cleanup(() => gReporter._shutdown());
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
let dummyTimer = { cancel: () => {}, clear: () => {} };
|
||||
|
@ -353,8 +354,3 @@ add_task(function* test_telemetryBasics() {
|
|||
yield experiments.uninit();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
add_task(function* shutdown() {
|
||||
yield gReporter._shutdown();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
%define forwardTransitionLength 150ms
|
||||
%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
|
||||
%define conditionalForwardWithUrlbarWidth 40
|
||||
%define conditionalForwardWithUrlbarWidth 30
|
||||
|
||||
#menubar-items {
|
||||
-moz-box-orient: vertical; /* for flex hack */
|
||||
|
@ -676,23 +676,98 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-margin-start: -4px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
#forward-button[disabled] {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
#back-button {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
-moz-padding-start: 5px;
|
||||
-moz-padding-end: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-radius: 0 10000px 10000px 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
|
||||
transition: @forwardTransitionLength@ ease-out;
|
||||
#back-button:-moz-locale-dir(rtl) {
|
||||
border-radius: 10000px 0 0 10000px;
|
||||
}
|
||||
|
||||
#back-button > menupopup {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
#back-button > .toolbarbutton-icon {
|
||||
border-radius: 10000px;
|
||||
background-clip: padding-box;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.25),
|
||||
0 1px 0 hsla(210,54%,20%,.35);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
transition-property: background-color, box-shadow;
|
||||
transition-duration: 250ms;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: hsla(210,48%,96%,.75);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.3),
|
||||
0 1px 0 hsla(210,54%,20%,.4),
|
||||
0 0 4px hsla(210,54%,20%,.2);
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
|
||||
#back-button[open="true"] > .toolbarbutton-icon {
|
||||
background-color: hsla(210,54%,20%,.15);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.4),
|
||||
0 1px 0 hsla(210,54%,20%,.2);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
|
||||
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
|
||||
0 1px 0 hsla(210,54%,20%,.65) !important;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
#forward-button:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
|
||||
transition: opacity @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#forward-button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#forward-button > .toolbarbutton-icon {
|
||||
background-clip: padding-box;
|
||||
clip-path: url("chrome://browser/content/browser.xul#keyhole-forward-clip-path");
|
||||
margin-left: -6px;
|
||||
border-left-style: none;
|
||||
border-radius: 0;
|
||||
padding: 2px 3px 2px 9px;
|
||||
border: 1px solid #9a9a9a;
|
||||
}
|
||||
|
||||
/* tabview menu item */
|
||||
|
||||
#menu_tabview {
|
||||
|
@ -801,9 +876,21 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
/* Location bar */
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
-moz-appearance: none;
|
||||
padding: 1px;
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#urlbar[focused],
|
||||
.searchbar-textbox[focused] {
|
||||
border-color: Highlight;
|
||||
}
|
||||
|
||||
#urlbar {
|
||||
-moz-appearance: textfield;
|
||||
padding: 0;
|
||||
background-color: -moz-field;
|
||||
}
|
||||
|
||||
.urlbar-textbox-container {
|
||||
|
@ -825,26 +912,59 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
|
||||
-moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
|
||||
padding-left: @conditionalForwardWithUrlbarWidth@px;
|
||||
-moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
|
||||
-moz-border-start: none;
|
||||
margin-left: 0;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
|
||||
transition: margin-left @forwardTransitionLength@ ease-out,
|
||||
margin-right @forwardTransitionLength@ ease-out;
|
||||
transition: margin-left @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
|
||||
/* Work with margin-top to align the clip-path correctly. */
|
||||
margin-top: 5px;
|
||||
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
|
||||
margin-top: -4px;
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@px;
|
||||
}
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
margin-right: -@conditionalForwardWithUrlbarWidth@px;
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
|
||||
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
|
||||
transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
|
||||
/* when switching tabs, or when not hovered anymore, trigger a new transition
|
||||
* to hide the forward button immediately */
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
/* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#urlbar-icons {
|
||||
|
@ -884,41 +1004,66 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
min-width: calc(54px + 11ch);
|
||||
}
|
||||
|
||||
%include ../shared/identity-block.inc.css
|
||||
/* identity box */
|
||||
|
||||
#page-proxy-favicon {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
-moz-margin-start: 4px;
|
||||
-moz-margin-end: 3px;
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#identity-box:hover > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#identity-box:hover:active > #page-proxy-favicon,
|
||||
#identity-box[open=true] > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
/* Identity indicator */
|
||||
#identity-box {
|
||||
padding: 1px;
|
||||
margin: -1px;
|
||||
-moz-margin-end: 0;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
#identity-box:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 2.5px;
|
||||
border-bottom-left-radius: 2.5px;
|
||||
border-top-left-radius: 1.5px;
|
||||
border-bottom-left-radius: 1.5px;
|
||||
}
|
||||
|
||||
#identity-box:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 2.5px;
|
||||
border-bottom-right-radius: 2.5px;
|
||||
border-top-right-radius: 1.5px;
|
||||
border-bottom-right-radius: 1.5px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
padding-left: 5px;
|
||||
transition: padding-left;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
padding-right: 5px;
|
||||
transition: padding-right;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
|
||||
/* forward button hiding is delayed when hovered */
|
||||
transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
|
||||
padding-left: 5.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
|
||||
padding-right: 5.01px;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
|
||||
-moz-margin-end: 4px;
|
||||
}
|
||||
|
||||
#identity-box.verifiedIdentity:not(:-moz-lwtheme) {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#identity-box:-moz-focusring {
|
||||
|
@ -931,10 +1076,27 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
|
||||
background-color: #fff;
|
||||
-moz-margin-end: 4px;
|
||||
%include ../shared/identity-block.inc.css
|
||||
|
||||
#page-proxy-favicon {
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
-moz-margin-start: 3px;
|
||||
-moz-margin-end: 2px;
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
#identity-box:hover > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#identity-box:hover:active > #page-proxy-favicon,
|
||||
#identity-box[open=true] > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
/* Identity popup icons */
|
||||
|
|
|
@ -105,6 +105,7 @@ browser.jar:
|
|||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||
|
@ -134,6 +135,12 @@ browser.jar:
|
|||
#endif
|
||||
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (preferences/in-content/check.png)
|
||||
skin/classic/browser/preferences/in-content/icons.png (preferences/in-content/icons.png)
|
||||
skin/classic/browser/preferences/in-content/header.png (preferences/in-content/header.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown.png (preferences/in-content/dropdown.png)
|
||||
skin/classic/browser/preferences/in-content/sorter.png (preferences/in-content/sorter.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown-disabled.png (preferences/in-content/dropdown-disabled.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 593 B |
После Ширина: | Высота: | Размер: 250 B |
После Ширина: | Высота: | Размер: 250 B |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
|
@ -2,174 +2,89 @@
|
|||
- 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/. */
|
||||
|
||||
@import url("chrome://global/skin/inContentUI.css");
|
||||
%include ../../../shared/in-content/preferences.css
|
||||
|
||||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
|
||||
#header {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
caption {
|
||||
font-size: 1.667rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Category List */
|
||||
|
||||
#categories {
|
||||
button > .button-box,
|
||||
menulist > .menulist-label-box {
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
-moz-margin-end: -1px;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
margin-top: 41px;
|
||||
}
|
||||
|
||||
.category {
|
||||
button[type="menu"] > .button-box > .button-menu-dropmarker {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
menulist:not([editable="true"]) > .menulist-dropmarker {
|
||||
display: -moz-box;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
checkbox {
|
||||
-moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox");
|
||||
}
|
||||
|
||||
.checkbox-check {
|
||||
max-height: 23px;
|
||||
}
|
||||
|
||||
checkbox:hover::before,
|
||||
checkbox[checked]::before {
|
||||
max-height: 10px;
|
||||
margin-top: 7px;
|
||||
margin-bottom: 6px;
|
||||
-moz-margin-end: -19px;
|
||||
-moz-margin-start: 4px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
radio {
|
||||
-moz-binding: url("chrome://global/content/bindings/radio.xml#radio");
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.radio-check {
|
||||
max-height: 23px;
|
||||
}
|
||||
|
||||
.radio-label-box {
|
||||
-moz-appearance: none;
|
||||
border-width: 1px;
|
||||
-moz-border-end-width: 0;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
padding: 9px 4px 10px;
|
||||
-moz-padding-end: 8px;
|
||||
-moz-box-align: center;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
color: WindowText;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.category:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.category:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.category[selected] {
|
||||
background-color: -moz-Field;
|
||||
color: -moz-FieldText;
|
||||
border-color: ThreeDShadow;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 1.5rem;
|
||||
-moz-padding-end: 24px;
|
||||
}
|
||||
|
||||
/* Maximize the size of the viewport when the window is small */
|
||||
@media (max-width: 800px) {
|
||||
.category-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 0 6px;
|
||||
radio:hover::before,
|
||||
radio[selected]::before {
|
||||
max-height: 11px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
-moz-margin-end: -17px;
|
||||
-moz-margin-start: 6px;
|
||||
-moz-margin-end: 5px;
|
||||
list-style-image: url("chrome://browser/skin/preferences/Options.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px)
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px)
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 160px, 32px, 128px)
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 192px, 32px, 160px)
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 224px, 32px, 192px)
|
||||
}
|
||||
|
||||
%ifdef MOZ_SERVICES_SYNC
|
||||
#category-sync > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/Options-sync.png");
|
||||
}
|
||||
%endif
|
||||
|
||||
/* Applications Pane Styles */
|
||||
|
||||
#applications-content {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#handlersView {
|
||||
.numberbox-input-box {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid ThreeDShadow;
|
||||
overflow-y: auto;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
/* XXX This style is for bug 740213 and should be removed once that
|
||||
bug has a solution. */
|
||||
description > html|a {
|
||||
cursor: pointer;
|
||||
spinbuttons {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
/* XXX Styles Below can be removed once bug 660726 lands */
|
||||
.nav-button {
|
||||
min-width: 0;
|
||||
.actionsMenu {
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
#back-btn:-moz-locale-dir(ltr) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar");
|
||||
.actionsMenu > .menulist-label-box > .menulist-icon {
|
||||
margin-top: 1px;
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 6px;
|
||||
}
|
||||
|
||||
#forward-btn:-moz-locale-dir(ltr) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar");
|
||||
.actionsMenu > .menulist-label-box > .menulist-label {
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
|
||||
#back-btn:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar");
|
||||
}
|
||||
|
||||
#forward-btn:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar");
|
||||
}
|
||||
|
||||
#back-btn[disabled="true"]:-moz-locale-dir(ltr) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
#forward-btn[disabled="true"]:-moz-locale-dir(ltr) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
#back-btn[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
#forward-btn[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
.header-button .toolbarbutton-text {
|
||||
display: none;
|
||||
menulist.actionsMenu > .menulist-dropmarker {
|
||||
margin-top: 11px;
|
||||
margin-bottom: 11px;
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 154 B |
|
@ -502,7 +502,7 @@ toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[bu
|
|||
toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],#back-button,#forward-button)):-moz-any(:hover:active,[open],[checked]),
|
||||
toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover]:active > .toolbarbutton-menubutton-button,
|
||||
toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover:active > .toolbarbutton-menubutton-dropmarker,
|
||||
toolbar .toolbarbutton-1[type="menu-button"][open] > .toolbarbutton-menubutton-dropmarker {
|
||||
toolbar .toolbarbutton-1[type="menu-button"][open]:not([disabled]) > .toolbarbutton-menubutton-dropmarker {
|
||||
background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), hsla(0,0%,0%,0)) border-box;
|
||||
border-color: hsla(0,0%,0%,.3);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.5),
|
||||
|
|
|
@ -168,6 +168,7 @@ browser.jar:
|
|||
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/newtab/controls@2x.png (newtab/controls@2x.png)
|
||||
|
@ -223,6 +224,14 @@ browser.jar:
|
|||
skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png)
|
||||
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (preferences/in-content/check.png)
|
||||
skin/classic/browser/preferences/in-content/check@2x.png (preferences/in-content/check@2x.png)
|
||||
skin/classic/browser/preferences/in-content/icons.png (preferences/in-content/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/header.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/sorter.png (preferences/in-content/sorter.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown.png (preferences/in-content/dropdown.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown-disabled.png (preferences/in-content/dropdown-disabled.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 593 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 250 B |
После Ширина: | Высота: | Размер: 250 B |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 30 KiB |
|
@ -2,182 +2,134 @@
|
|||
- 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/. */
|
||||
|
||||
%include ../../shared.inc
|
||||
%include ../../../shared/in-content/preferences.css
|
||||
|
||||
@import url("chrome://global/skin/inContentUI.css");
|
||||
|
||||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
|
||||
#header {
|
||||
margin-bottom: 18px;
|
||||
menulist:not([editable="true"]) > .menulist-dropmarker {
|
||||
display: -moz-box;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
caption {
|
||||
font-size: 1.667rem;
|
||||
checkbox:hover::before,
|
||||
checkbox[checked]::before {
|
||||
margin-bottom: -2px;
|
||||
-moz-margin-end: -20px;
|
||||
-moz-margin-start: 5px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
max-width: 800px;
|
||||
radio:hover::before,
|
||||
radio[selected]::before {
|
||||
-moz-margin-end: -18px;
|
||||
-moz-margin-start: 7px;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Category List */
|
||||
|
||||
#categories {
|
||||
.numberbox-input-box {
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
-moz-margin-end: -1px;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
margin-top: 31px;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.category {
|
||||
spinbuttons {
|
||||
-moz-appearance: none;
|
||||
color: #252F3B;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
padding: 10px 4px;
|
||||
-moz-padding-end: 8px;
|
||||
-moz-box-align: center;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.category:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
.spinbuttons-up {
|
||||
margin-top: 0 !important;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.category:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
.spinbuttons-down {
|
||||
margin-bottom: 0 !important;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.category[selected] {
|
||||
background-color: rgba(255, 255, 255, 0.35);
|
||||
color: -moz-dialogtext;
|
||||
border-color: rgba(50, 65, 92, 0.4);
|
||||
-moz-border-end-color: #C9CFD7;
|
||||
.spinbuttons-button > .button-box {
|
||||
-moz-padding-start: 2px !important;
|
||||
-moz-padding-end: 3px !important;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 1.5rem;
|
||||
-moz-padding-end: 24px;
|
||||
}
|
||||
|
||||
/* Maximize the size of the viewport when the window is small */
|
||||
@media (max-width: 800px) {
|
||||
.category-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
-moz-margin-start: 6px;
|
||||
list-style-image: url("chrome://browser/skin/preferences/Options.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px)
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px)
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 160px, 32px, 128px)
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 192px, 32px, 160px)
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 224px, 32px, 192px)
|
||||
}
|
||||
|
||||
%ifdef MOZ_SERVICES_SYNC
|
||||
#category-sync > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/Options-sync.png");
|
||||
}
|
||||
%endif
|
||||
|
||||
/* Applications Pane Styles */
|
||||
|
||||
#applications-content {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#handlersView {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid rgba(60,73,97,0.5);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* XXX This style is for bug 740213 and should be removed once that
|
||||
bug has a solution. */
|
||||
description > html|a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* XXX Styles Below can be removed once bug 660726 lands */
|
||||
.nav-button {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/navigation.png);
|
||||
}
|
||||
|
||||
#back-btn:-moz-locale-dir(ltr),
|
||||
#forward-btn:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right: none;
|
||||
-moz-image-region: rect(0, 20px, 20px, 0);
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
#back-btn:-moz-locale-dir(rtl),
|
||||
#forward-btn:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
-moz-image-region: rect(0, 40px, 20px, 20px);
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
.header-button {
|
||||
-moz-appearance: none;
|
||||
padding: 0 4px;
|
||||
margin: 0;
|
||||
height: 22px;
|
||||
border: 1px solid rgba(60,73,97,0.5);
|
||||
border-radius: @toolbarbuttonCornerRadius@;
|
||||
box-shadow: inset 0 1px rgba(255,255,255,0.25), 0 1px rgba(255,255,255,0.25);
|
||||
background: linear-gradient(rgba(255,255,255,0.45), rgba(255,255,255,0));
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.header-button .toolbarbutton-text {
|
||||
.spinbuttons-button > .button-box > .button-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-button[disabled="true"] .toolbarbutton-icon {
|
||||
opacity: 0.4;
|
||||
.actionsMenu > .menulist-label-box > .menulist-icon {
|
||||
margin-top: 2px;
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 8px !important;
|
||||
}
|
||||
|
||||
.header-button:not([disabled="true"]):active:hover,
|
||||
.header-button[open="true"] {
|
||||
border-color: rgba(45,54,71,0.7);
|
||||
box-shadow: inset 0 0 4px rgb(45,54,71), 0 1px rgba(255,255,255,0.25);
|
||||
background-image: linear-gradient(rgba(45,54,71,0.6), rgba(45,54,71,0));
|
||||
description {
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
checkbox:hover::before,
|
||||
checkbox[checked]::before {
|
||||
background-size: cover;
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/preferences/in-content/check@2x.png"), 0, 30, 30, 0);
|
||||
}
|
||||
|
||||
checkbox[checked]::before {
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/preferences/in-content/check@2x.png"), 0, 60, 30, 30);
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons@2x.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 48px, 48px, 0);
|
||||
}
|
||||
|
||||
#category-general[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 48px, 96px, 0);
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 48px, 48px);
|
||||
}
|
||||
|
||||
#category-content[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 96px, 96px, 48px);
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 144px, 48px, 96px);
|
||||
}
|
||||
|
||||
#category-application[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 144px, 96px, 96px);
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 192px, 48px, 144px);
|
||||
}
|
||||
|
||||
#category-privacy[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 192px, 96px, 144px);
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 240px, 48px, 192px);
|
||||
}
|
||||
|
||||
#category-security[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 240px, 96px, 192px);
|
||||
}
|
||||
|
||||
#category-sync > .category-icon {
|
||||
-moz-image-region: rect(0, 288px, 48px, 240px);
|
||||
}
|
||||
|
||||
#category-sync[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 288px, 96px, 240px);
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 336px, 48px, 288px);
|
||||
}
|
||||
|
||||
#category-advanced[selected] > .category-icon {
|
||||
-moz-image-region: rect(48px, 336px, 96px, 288px);
|
||||
}
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 154 B |
|
@ -163,11 +163,15 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan
|
|||
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
|
||||
-moz-hyphens: auto;
|
||||
line-height: 1.1;
|
||||
max-height: 2.2em;
|
||||
}
|
||||
|
||||
.panelUI-grid .toolbarbutton-1:not([auto-hyphens="off"]) > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
|
||||
.panelUI-grid .toolbarbutton-1:not([auto-hyphens="off"]) > .toolbarbutton-multiline-text {
|
||||
-moz-hyphens: auto;
|
||||
}
|
||||
|
||||
.panelUI-grid:not([customize-transitioning]) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
|
||||
.panelUI-grid:not([customize-transitioning]) .toolbarbutton-1 > .toolbarbutton-multiline-text {
|
||||
position: absolute;
|
||||
|
|
|
@ -0,0 +1,751 @@
|
|||
%if 0
|
||||
/* - 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/. */
|
||||
%endif
|
||||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("chrome://browser/skin/fonts/ClearSans-Regular.ttf");
|
||||
}
|
||||
|
||||
page {
|
||||
-moz-appearance: none;
|
||||
background-image: linear-gradient(#FFFFFF, #EDEDED 100px);
|
||||
}
|
||||
|
||||
caption {
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.caption-text {
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
line-height: 22px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
padding: 40px 48px 48px;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
color: #424E5A;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* groupboxes */
|
||||
|
||||
groupbox {
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
-moz-margin-start: 60px;
|
||||
-moz-padding-start: 0;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
groupbox label {
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
/* tabpanels and tabs */
|
||||
|
||||
tabpanels {
|
||||
-moz-appearance: none;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
color: #424E5A;
|
||||
border: none;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tabs {
|
||||
-moz-margin-start: 60px;
|
||||
margin-bottom: 15px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
-moz-border-top-colors: #BBBBBB #F9F9F9;
|
||||
-moz-border-bottom-colors: #F9F9F9 #BBBBBB;
|
||||
}
|
||||
|
||||
.tabs-left,
|
||||
.tabs-right {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tab {
|
||||
-moz-appearance: none;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
-moz-margin-end: 30px;
|
||||
min-height: 60px;
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
tab[selected] {
|
||||
border-bottom-color: #FF9500;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 1.3rem;
|
||||
line-height: 22px;
|
||||
color: #737980;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
tab:not([selected]):hover > .tab-middle > .tab-text {
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
border-color: #FFFFFF;
|
||||
}
|
||||
|
||||
tab:not([selected]):hover:active > .tab-middle > .tab-text {
|
||||
background-color: rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
tab[selected] > .tab-middle > .tab-text {
|
||||
font-weight: bold;
|
||||
color: #424E5A;
|
||||
}
|
||||
|
||||
/* buttons and menulists */
|
||||
|
||||
button,
|
||||
menulist {
|
||||
-moz-appearance: none;
|
||||
height: 30px;
|
||||
max-height: 30px;
|
||||
color: #737980;
|
||||
line-height: 20px;
|
||||
text-shadow: 0 1px 1px #FEFFFE;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
-moz-border-top-colors: none !important;
|
||||
-moz-border-right-colors: none !important;
|
||||
-moz-border-bottom-colors: none !important;
|
||||
-moz-border-left-colors: none !important;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 1px 0 #FFFFFF, inset 0 2px 2px 0 #FFFFFF;
|
||||
background-color: #F1F1F1;
|
||||
background-image: linear-gradient(#FFFFFF, rgba(255,255,255,0.1));
|
||||
}
|
||||
|
||||
button:not([disabled]):hover,
|
||||
menulist:not([disabled]):hover {
|
||||
background-image: linear-gradient(#FFFFFF, rgba(255,255,255,0.6));
|
||||
}
|
||||
|
||||
button:not([disabled]):hover:active,
|
||||
menulist[open="true"]:not([disabled]) {
|
||||
background-image: linear-gradient(rgba(255,255,255,0.1),
|
||||
rgba(255,255,255,0.6));
|
||||
}
|
||||
|
||||
button[disabled],
|
||||
menulist[disabled] {
|
||||
background-image: linear-gradient(rgba(255,255,255,0.5),
|
||||
rgba(255,255,255,0.1));
|
||||
border-color: rgba(23,50,77,0.25);
|
||||
color: rgba(115,121,128,0.5);
|
||||
text-shadow: 0 1px 1px #FFFFFF;
|
||||
}
|
||||
|
||||
button > .button-box,
|
||||
menulist > .menulist-label-box {
|
||||
padding-right: 10px !important;
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
|
||||
button[type="menu"] > .button-box > .button-menu-dropmarker {
|
||||
-moz-appearance: none;
|
||||
margin: 1px 0;
|
||||
-moz-margin-start: 10px;
|
||||
padding: 0;
|
||||
width: 10px;
|
||||
height: 15px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/dropdown.png")
|
||||
}
|
||||
|
||||
.spinbuttons-button {
|
||||
-moz-margin-start: 10px !important;
|
||||
-moz-margin-end: 2px !important;
|
||||
}
|
||||
|
||||
.spinbuttons-up {
|
||||
margin-top: 2px !important;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.spinbuttons-down {
|
||||
margin-bottom: 2px !important;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.spinbuttons-button > .button-box {
|
||||
padding: 1px 5px 2px !important;
|
||||
}
|
||||
|
||||
.spinbuttons-up > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
|
||||
}
|
||||
|
||||
.spinbuttons-up[disabled] > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif");
|
||||
}
|
||||
|
||||
.spinbuttons-down > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
|
||||
}
|
||||
|
||||
.spinbuttons-down[disabled] > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif");
|
||||
}
|
||||
|
||||
menulist:not([editable="true"]) > .menulist-dropmarker {
|
||||
-moz-appearance: none;
|
||||
-moz-margin-end: 10px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/dropdown.png")
|
||||
}
|
||||
|
||||
menulist[disabled]:not([editable="true"]) > .menulist-dropmarker {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/dropdown-disabled.png")
|
||||
}
|
||||
|
||||
menulist > menupopup,
|
||||
button[type="menu"] > menupopup {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
border-radius: 5px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
menulist > menupopup menu,
|
||||
menulist > menupopup menuitem,
|
||||
button[type="menu"] > menupopup menu,
|
||||
button[type="menu"] > menupopup menuitem {
|
||||
-moz-appearance: none;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
height: 40px;
|
||||
color: #737980;
|
||||
}
|
||||
|
||||
menulist > menupopup > menu[_moz-menuactive="true"],
|
||||
menulist > menupopup > menuitem[_moz-menuactive="true"],
|
||||
button[type="menu"] > menupopup > menu[_moz-menuactive="true"],
|
||||
button[type="menu"] > menupopup > menuitem[_moz-menuactive="true"] {
|
||||
color: #FFFFFF;
|
||||
background-image: linear-gradient(#4CB1FF, #1792E5);
|
||||
}
|
||||
|
||||
menulist > menupopup menuseparator,
|
||||
button[type="menu"] > menupopup menuseparator {
|
||||
-moz-appearance: none;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
padding: 0;
|
||||
border-top: 1px solid rgba(23,50,77,0.4);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* textboxes */
|
||||
|
||||
textbox {
|
||||
-moz-appearance: none;
|
||||
height: 30px;
|
||||
color: #737980;
|
||||
line-height: 20px;
|
||||
text-shadow: 0 1px 1px #FEFFFE;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
-moz-border-top-colors: none !important;
|
||||
-moz-border-right-colors: none !important;
|
||||
-moz-border-bottom-colors: none !important;
|
||||
-moz-border-left-colors: none !important;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 1px 0 #FFFFFF, inset 0 2px 2px 0 rgba(0,0,0,0.03);
|
||||
background-color: #F1F1F1;
|
||||
background-image: linear-gradient(#FFFFFF, rgba(255,255,255,0.8));
|
||||
}
|
||||
|
||||
textbox[focused] {
|
||||
color: #424E5A;
|
||||
border-color: #0096DC;
|
||||
box-shadow: 0 0 2px 2px rgba(0,150,220,0.35), inset 0 0 2px 0 #0096DC;
|
||||
}
|
||||
|
||||
textbox[disabled] {
|
||||
color: rgba(115,121,128,0.5);
|
||||
border-color: rgba(23,50,77,0.25);
|
||||
background-image: linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0.4));
|
||||
}
|
||||
|
||||
/* Links */
|
||||
|
||||
.text-link,
|
||||
.inline-link,
|
||||
html|a.inline-link {
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
color: #0096DC;
|
||||
}
|
||||
|
||||
.text-link:hover,
|
||||
.inline-link:hover {
|
||||
color: #4CB1FF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.text-link:hover:active,
|
||||
.inline-link:hover:active {
|
||||
color: #FF9500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Checkboxes and radio buttons */
|
||||
|
||||
checkbox {
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.checkbox-check {
|
||||
-moz-appearance: none;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(23,50,77,0.40);
|
||||
-moz-margin-end: 10px;
|
||||
background-color: #f1f1f1;
|
||||
background-image: linear-gradient(#ffffff 0%, rgba(255,255,255,0.80) 100%);
|
||||
box-shadow: 0 1px 1px 0 #ffffff, inset 0 2px 0 0 rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.checkbox-check[checked] {
|
||||
border-color: #0096dc;
|
||||
box-shadow: 0 0 2px 2px rgba(0,150,220,0.35), inset 0 0 2px 0 #0096dc;
|
||||
}
|
||||
|
||||
.checkbox-label-box {
|
||||
-moz-margin-start: -1px; /* negative margin for the transparent border */
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
checkbox:hover::before,
|
||||
checkbox[checked]::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 15px;
|
||||
height: 10px;
|
||||
background-image: url("chrome://browser/skin/preferences/in-content/check.png");
|
||||
}
|
||||
|
||||
checkbox[checked]::before {
|
||||
background-position: -15px 0;
|
||||
}
|
||||
|
||||
.radio-check {
|
||||
-moz-appearance: none;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
border: 1px solid rgba(23,50,77,0.40);
|
||||
border-radius: 50%;
|
||||
-moz-margin-end: 10px;
|
||||
background-color: #f1f1f1;
|
||||
background-image: linear-gradient(#ffffff 0%, rgba(255,255,255,0.80) 100%);
|
||||
box-shadow: 0 1px 1px 0 #ffffff, inset 0 2px 0 0 rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.radio-check[selected] {
|
||||
border-color: #0096dc;
|
||||
box-shadow: 0 0 2px 2px rgba(0,150,220,0.35), inset 0 0 2px 0 #0096dc;
|
||||
}
|
||||
|
||||
.radio-label-box {
|
||||
-moz-margin-start: -1px; /* negative margin for the transparent border */
|
||||
-moz-margin-end: 10px;
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
radio:hover::before,
|
||||
radio[selected]::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 1px;
|
||||
background-image: linear-gradient(rgba(76,177,255,0.25) 0%, rgba(23,146,229,0.25) 100%);
|
||||
}
|
||||
|
||||
radio[selected]::before {
|
||||
background-image: linear-gradient(#4cb1ff 0%, #1792e5 100%);
|
||||
}
|
||||
|
||||
/* Category List */
|
||||
|
||||
#categories {
|
||||
-moz-appearance: none;
|
||||
background-color: #424e5a;
|
||||
-moz-border-end: 1px solid rgba(0,0,0,0.20);
|
||||
padding-top: 39px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.category {
|
||||
-moz-appearance: none;
|
||||
color: rgba(241,241,241,0.70);
|
||||
border: 1px solid transparent;
|
||||
-moz-border-end-width: 0;
|
||||
-moz-padding-start: 14px;
|
||||
-moz-padding-end: 21px;
|
||||
margin-bottom: -1px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.category:hover {
|
||||
background-color: rgba(255,255,255,0.15);
|
||||
border-color: rgba(255,255,255,0.20);
|
||||
}
|
||||
|
||||
.category[selected] {
|
||||
background-color: rgba(0,0,0,0.20);
|
||||
border-color: rgba(255,255,255,0.20);
|
||||
-moz-border-start-width: 3px;
|
||||
-moz-border-start-color: #ff9500;
|
||||
-moz-padding-start: 12px;
|
||||
color: #f1f1f1;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
line-height: 22px;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font-size: 1.25rem;
|
||||
padding-bottom: 2px;
|
||||
-moz-padding-start: 9px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 24px, 24px, 0);
|
||||
}
|
||||
|
||||
#category-general[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 24px, 48px, 0);
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 48px, 24px, 24px);
|
||||
}
|
||||
|
||||
#category-content[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 48px, 48px, 24px);
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 72px, 24px, 48px);
|
||||
}
|
||||
|
||||
#category-application[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 72px, 48px, 48px);
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 24px, 72px);
|
||||
}
|
||||
|
||||
#category-privacy[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 96px, 48px, 72px);
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 120px, 24px, 96px);
|
||||
}
|
||||
|
||||
#category-security[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 120px, 48px, 96px);
|
||||
}
|
||||
|
||||
#category-sync > .category-icon {
|
||||
-moz-image-region: rect(0, 144px, 24px, 120px);
|
||||
}
|
||||
|
||||
#category-sync[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 144px, 48px, 120px);
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 168px, 24px, 144px);
|
||||
}
|
||||
|
||||
#category-advanced[selected] > .category-icon {
|
||||
-moz-image-region: rect(24px, 168px, 48px, 144px);
|
||||
}
|
||||
|
||||
/* header */
|
||||
|
||||
.header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
width: 40px;
|
||||
max-height: 40px;
|
||||
-moz-margin-end: 20px;
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/header.png");
|
||||
}
|
||||
|
||||
.header-name {
|
||||
font-size: 2.5rem;
|
||||
font-weight: normal;
|
||||
line-height: 40px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#header-general > .header-icon {
|
||||
-moz-image-region: rect(3px, 45px, 45px, 3px);
|
||||
}
|
||||
|
||||
#header-content > .header-icon {
|
||||
-moz-image-region: rect(3px, 93px, 45px, 51px);
|
||||
}
|
||||
|
||||
#header-application > .header-icon {
|
||||
-moz-image-region: rect(3px, 141px, 45px, 99px);
|
||||
}
|
||||
|
||||
#header-privacy > .header-icon {
|
||||
-moz-image-region: rect(3px, 189px, 45px, 147px);
|
||||
}
|
||||
|
||||
#header-security > .header-icon {
|
||||
-moz-image-region: rect(3px, 237px, 45px, 195px);
|
||||
}
|
||||
|
||||
#header-sync > .header-icon {
|
||||
-moz-image-region: rect(3px, 285px, 45px, 243px);
|
||||
}
|
||||
|
||||
#header-advanced > .header-icon {
|
||||
-moz-image-region: rect(3px, 333px, 45px, 291px);
|
||||
}
|
||||
|
||||
.indent {
|
||||
margin-top: 7px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
/* General Pane */
|
||||
|
||||
filefield {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.fileFieldContentBox {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.fileFieldIcon {
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.fileFieldLabel {
|
||||
-moz-margin-start: -26px;
|
||||
-moz-padding-start: 36px;
|
||||
}
|
||||
|
||||
#chooseFolder {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Applications Pane Styles */
|
||||
|
||||
#applications-content {
|
||||
-moz-margin-start: 60px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#handlersView {
|
||||
-moz-appearance: none;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
color: #737980;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
border-radius: 5px;
|
||||
background-color: #F1F1F1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#typeColumn,
|
||||
#actionColumn {
|
||||
-moz-appearance: none;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
line-height: 20px;
|
||||
color: #737980;
|
||||
height: 36px;
|
||||
padding: 0 10px;
|
||||
background-color: #F7F7F7;
|
||||
border: 1px solid #CCCCCC;
|
||||
-moz-border-top-colors: none;
|
||||
-moz-border-right-colors: none;
|
||||
-moz-border-bottom-colors: none;
|
||||
-moz-border-left-colors: none;
|
||||
text-shadow: 0 1px 1px #FFFFFF;
|
||||
}
|
||||
|
||||
#typeColumn:-moz-locale-dir(ltr),
|
||||
#actionColumn:-moz-locale-dir(rtl) {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
|
||||
#typeColumn:-moz-locale-dir(rtl),
|
||||
#actionColumn:-moz-locale-dir(ltr) {
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
|
||||
#typeColumn:hover,
|
||||
#actionColumn:hover {
|
||||
border-color: #737980;
|
||||
}
|
||||
|
||||
#typeColumn:hover:active,
|
||||
#actionColumn:hover:active {
|
||||
padding: 0 10px;
|
||||
border-color: #0096DC;
|
||||
box-shadow: 0 0 2px 2px rgba(0,150,220,0.35), inset 0 0 2px 0 #0096DC;
|
||||
}
|
||||
|
||||
#typeColumn > .treecol-sortdirection[sortDirection=ascending],
|
||||
#actionColumn > .treecol-sortdirection[sortDirection=ascending],
|
||||
#typeColumn > .treecol-sortdirection[sortDirection=descending],
|
||||
#actionColumn > .treecol-sortdirection[sortDirection=descending] {
|
||||
-moz-appearance: none;
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/sorter.png");
|
||||
}
|
||||
|
||||
#typeColumn > .treecol-sortdirection[sortDirection=descending],
|
||||
#actionColumn > .treecol-sortdirection[sortDirection=descending] {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
#handlersView > richlistitem {
|
||||
min-height: 40px !important;
|
||||
}
|
||||
|
||||
.typeIcon {
|
||||
-moz-margin-start: 10px !important;
|
||||
-moz-margin-end: 9px !important;
|
||||
}
|
||||
|
||||
.actionIcon {
|
||||
-moz-margin-start: 11px !important;
|
||||
-moz-margin-end: 8px !important;
|
||||
}
|
||||
|
||||
.actionsMenu {
|
||||
height: 40px;
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
.actionsMenu > menupopup > menuitem {
|
||||
-moz-padding-start: 10px !important;
|
||||
}
|
||||
|
||||
.actionsMenu > menupopup > menuitem > .menu-iconic-left {
|
||||
-moz-margin-end: 8px !important;
|
||||
}
|
||||
|
||||
/* XXX This style is for bug 740213 and should be removed once that
|
||||
bug has a solution. */
|
||||
description > html|a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Content Pane */
|
||||
|
||||
#defaultFontSize {
|
||||
min-width: 5.5em;
|
||||
}
|
||||
|
||||
/* Security Pane */
|
||||
|
||||
/* Add margins to this buttons to unsqueeze the checkboxed in same hbox */
|
||||
#addonExceptions,
|
||||
#cookieExceptions,
|
||||
#passwordExceptions,
|
||||
#changeMasterPassword {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Sync Pane */
|
||||
|
||||
#syncEnginesList {
|
||||
-moz-appearance: none;
|
||||
color: #737980;
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
border-radius: 5px;
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
/* Advanced Pane */
|
||||
|
||||
#advancedPrefs {
|
||||
padding-bottom: 0; /* no padding needed in inContent prefs */
|
||||
}
|
||||
|
||||
#encryptionPanel {
|
||||
margin-top: 15px;
|
||||
-moz-margin-start: 60px;
|
||||
}
|
||||
|
||||
#offlineAppsList {
|
||||
-moz-appearance: none;
|
||||
color: #737980;
|
||||
padding: 2px;
|
||||
border: 1px solid rgba(23,50,77,0.4);
|
||||
border-radius: 5px;
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
#telemetryLearnMore,
|
||||
#FHRLearnMore,
|
||||
#crashReporterLearnMore {
|
||||
/* center the links */
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
|
@ -799,7 +799,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
/* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
/* allows keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
0 1px 0 hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
text-shadow: none;
|
||||
|
@ -853,7 +853,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
#forward-button > .toolbarbutton-icon {
|
||||
background-clip: padding-box !important;
|
||||
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
|
||||
clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
|
||||
clip-path: url(chrome://browser/content/browser.xul#keyhole-forward-clip-path) !important;
|
||||
margin-left: -6px !important;
|
||||
border-left-style: none !important;
|
||||
border-radius: 0 !important;
|
||||
|
@ -1156,7 +1156,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
|
||||
clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path");
|
||||
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
|
||||
|
|
|
@ -126,6 +126,7 @@ browser.jar:
|
|||
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
|
@ -159,6 +160,14 @@ browser.jar:
|
|||
skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png)
|
||||
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (preferences/in-content/check.png)
|
||||
skin/classic/browser/preferences/in-content/check@2x.png (preferences/in-content/check@2x.png)
|
||||
skin/classic/browser/preferences/in-content/icons.png (preferences/in-content/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/header.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/sorter.png (preferences/in-content/sorter.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown.png (preferences/in-content/dropdown.png)
|
||||
skin/classic/browser/preferences/in-content/dropdown-disabled.png (preferences/in-content/dropdown-disabled.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
|
@ -465,6 +474,7 @@ browser.jar:
|
|||
skin/classic/aero/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16-aero.png)
|
||||
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/aero/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
|
||||
skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/aero/browser/newtab/controls.png (newtab/controls.png)
|
||||
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
|
||||
|
@ -498,6 +508,14 @@ browser.jar:
|
|||
skin/classic/aero/browser/preferences/saveFile.png (preferences/saveFile-aero.png)
|
||||
* skin/classic/aero/browser/preferences/preferences.css (preferences/preferences.css)
|
||||
* skin/classic/aero/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
skin/classic/aero/browser/preferences/in-content/check.png (preferences/in-content/check.png)
|
||||
skin/classic/aero/browser/preferences/in-content/check@2x.png (preferences/in-content/check@2x.png)
|
||||
skin/classic/aero/browser/preferences/in-content/icons.png (preferences/in-content/icons.png)
|
||||
skin/classic/aero/browser/preferences/in-content/icons@2x.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/aero/browser/preferences/in-content/header.png (preferences/in-content/icons@2x.png)
|
||||
skin/classic/aero/browser/preferences/in-content/sorter.png (preferences/in-content/sorter.png)
|
||||
skin/classic/aero/browser/preferences/in-content/dropdown.png (preferences/in-content/dropdown.png)
|
||||
skin/classic/aero/browser/preferences/in-content/dropdown-disabled.png (preferences/in-content/dropdown-disabled.png)
|
||||
skin/classic/aero/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/aero/browser/social/services-16.png (social/services-16.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 593 B |
После Ширина: | Высота: | Размер: 1.2 KiB |