This commit is contained in:
Wes Kocher 2014-03-27 20:07:56 -07:00
Родитель 3d817ab8e1 8bc0da49a1
Коммит 3948825ebe
128 изменённых файлов: 3373 добавлений и 1157 удалений

Просмотреть файл

@ -1,7 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * 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 m = require("main");
var self = require("sdk/self"); var self = require("sdk/self");
@ -22,3 +26,4 @@ exports.testID = function(test) {
test.assertEqual(self.data.url("sample.html"), test.assertEqual(self.data.url("sample.html"),
"resource://reading-data-example-at-jetpack-dot-mozillalabs-dot-com/reading-data/data/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 /* 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 * 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/. */ * 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 m = require("main");
var self = require("sdk/self"); var self = require("sdk/self");
@ -19,3 +23,4 @@ exports.testMain = function(test) {
exports.testData = function(test) { exports.testData = function(test) {
test.assert(self.data.load("panel.js").length > 0); test.assert(self.data.load("panel.js").length > 0);
}; };
*/

Просмотреть файл

@ -9,66 +9,124 @@ module.metadata = {
}; };
let { Class } = require("./heritage"); const { Class } = require("./heritage");
let { on, off } = require('../system/events'); const { Observer, subscribe, unsubscribe, observe } = require("./observer");
let unloadSubject = require('@loader/unload'); 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) { const uninstall = method("disposable/uninstall");
// Disposes given instance by removing it from weak map so that handler can exports.uninstall = uninstall;
// be GC-ed even if references to instance are kept. Also unregister unload
// handler.
let handler = disposables.get(instance);
if (handler) off("sdk:loader:destroy", handler); const shutdown = method("disposable/shutdown");
disposables.delete(instance); 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; 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. // 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. // Also makes sure to remove unload listener if it's already being disposed.
let Disposable = Class({ const Disposable = Class({
initialize: function setupDisposable() { implements: [Observer],
initialize: function(...args) {
// First setup instance before initializing it's disposal. If instance // First setup instance before initializing it's disposal. If instance
// fails to initialize then there is no instance to be disposed at the // fails to initialize then there is no instance to be disposed at the
// unload. // unload.
this.setup.apply(this, arguments); setup(this, ...args);
initialize(this); setupDisposable(this);
}, },
setup: function setup() { destroy: function(reason) {
// Implement your initialize logic here.
},
dispose: function dispose() {
// Implement your cleanup logic here.
},
destroy: function destroy() {
// Destroying disposable removes unload handler so that attempt to dispose // Destroying disposable removes unload handler so that attempt to dispose
// won't be made at unload & delegates to dispose. // won't be made at unload & delegates to dispose.
if (disposables.has(this)) { disposeDisposable(this);
dispose(this); unload(this, reason);
this.dispose(); },
} setup: function() {
// Implement your initialize logic here.
},
dispose: function() {
// Implement your cleanup logic here.
} }
}); });
exports.Disposable = Disposable; 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 { getAttachEventType, WorkerHost } = require('./content/utils');
const { Class } = require('./core/heritage'); const { Class } = require('./core/heritage');
const { Disposable } = require('./core/disposable'); const { Disposable } = require('./core/disposable');
const { WeakReference } = require('./core/reference');
const { Worker } = require('./content/worker'); const { Worker } = require('./content/worker');
const { EventTarget } = require('./event/target'); const { EventTarget } = require('./event/target');
const { on, emit, once, setListeners } = require('./event/core'); const { on, emit, once, setListeners } = require('./event/core');
@ -97,7 +98,8 @@ const PageMod = Class({
implements: [ implements: [
modContract.properties(modelFor), modContract.properties(modelFor),
EventTarget, EventTarget,
Disposable Disposable,
WeakReference
], ],
extends: WorkerHost(workerFor), extends: WorkerHost(workerFor),
setup: function PageMod(options) { setup: function PageMod(options) {
@ -128,7 +130,7 @@ const PageMod = Class({
applyOnExistingDocuments(mod); applyOnExistingDocuments(mod);
}, },
destroy: function destroy() { dispose: function() {
let style = styleFor(this); let style = styleFor(this);
if (style) if (style)
detach(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 { detach, attach, destroy, WorkerHost } = require('./content/utils');
const { Worker } = require('./content/worker'); const { Worker } = require('./content/worker');
const { Disposable } = require('./core/disposable'); const { Disposable } = require('./core/disposable');
const { WeakReference } = require('./core/reference');
const { EventTarget } = require('./event/target'); const { EventTarget } = require('./event/target');
const { unload } = require('./system/unload'); const { unload } = require('./system/unload');
const { events, streamEventsFrom } = require('./content/events'); const { events, streamEventsFrom } = require('./content/events');
@ -84,7 +85,8 @@ function isValidURL(page, url) !page.rules || page.rules.matchesAny(url)
const Page = Class({ const Page = Class({
implements: [ implements: [
EventTarget, EventTarget,
Disposable Disposable,
WeakReference
], ],
extends: WorkerHost(workerFor), extends: WorkerHost(workerFor),
setup: function Page(options) { setup: function Page(options) {

Просмотреть файл

@ -21,6 +21,7 @@ const { merge } = require("./util/object");
const { WorkerHost, detach, attach, destroy } = require("./content/utils"); const { WorkerHost, detach, attach, destroy } = require("./content/utils");
const { Worker } = require("./content/worker"); const { Worker } = require("./content/worker");
const { Disposable } = require("./core/disposable"); const { Disposable } = require("./core/disposable");
const { WeakReference } = require('./core/reference');
const { contract: loaderContract } = require("./content/loader"); const { contract: loaderContract } = require("./content/loader");
const { contract } = require("./util/contract"); const { contract } = require("./util/contract");
const { on, off, emit, setListeners } = require("./event/core"); const { on, off, emit, setListeners } = require("./event/core");
@ -111,7 +112,8 @@ const Panel = Class({
// set and return values from model on get. // set and return values from model on get.
panelContract.properties(modelFor), panelContract.properties(modelFor),
EventTarget, EventTarget,
Disposable Disposable,
WeakReference
], ],
extends: WorkerHost(workerFor), extends: WorkerHost(workerFor),
setup: function setup(options) { setup: function setup(options) {
@ -197,7 +199,7 @@ const Panel = Class({
let model = modelFor(this); let model = modelFor(this);
let view = viewFor(this); let view = viewFor(this);
let anchorView = getNodeView(anchor || options.position); let anchorView = getNodeView(anchor || options.position || model.position);
options = merge({ options = merge({
position: model.position, position: model.position,

Просмотреть файл

@ -174,10 +174,11 @@ function state(contract) {
state: function state(target, state) { state: function state(target, state) {
let nativeTarget = target === 'window' ? getFocusedBrowser() let nativeTarget = target === 'window' ? getFocusedBrowser()
: target === 'tab' ? getMostRecentTab() : target === 'tab' ? getMostRecentTab()
: target === this ? null
: viewFor(target); : viewFor(target);
if (!nativeTarget && target !== this && !isNil(target)) if (!nativeTarget && target !== this && !isNil(target))
throw new Error('target not allowed.'); throw new Error(ERR_INVALID_TARGET);
target = nativeTarget || target; target = nativeTarget || target;

Просмотреть файл

@ -1,13 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
// The widget module currently supports only Firefox. // The widget module currently supports only Firefox.
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=560716 // See: https://bugzilla.mozilla.org/show_bug.cgi?id=560716
module.metadata = { module.metadata = {
"stability": "stable", "stability": "deprecated",
"engines": { "engines": {
"Firefox": "*" "Firefox": "*"
} }
@ -39,6 +38,7 @@ const EVENTS = {
// normal toolbarbuttons. If they're any wider than this margin, we'll // 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: // 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_WIDGET_CUTOFF = 70;
const AUSTRALIS_PANEL_WIDE_CLASSNAME = "panel-wide-item";
const { validateOptions } = require("./deprecated/api-utils"); const { validateOptions } = require("./deprecated/api-utils");
const panels = require("./panel"); const panels = require("./panel");
@ -55,6 +55,11 @@ const unload = require("./system/unload");
const { getNodeView } = require("./view/core"); const { getNodeView } = require("./view/core");
const prefs = require('./preferences/service'); 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 // Data types definition
const valid = { const valid = {
number: { is: ["null", "undefined", "number"] }, number: { is: ["null", "undefined", "number"] },
@ -230,6 +235,8 @@ function haveInserted(widgetId) {
return prefs.has(INSERTION_PREF_ROOT + 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 * Main Widget class: entry point of the widget API
* *
@ -626,7 +633,7 @@ BrowserWindow.prototype = {
let placement = CustomizableUI.getPlacementOfWidget(id); let placement = CustomizableUI.getPlacementOfWidget(id);
if (!placement) { if (!placement) {
if (haveInserted(id)) if (haveInserted(id) || isWide(node))
return; return;
placement = {area: 'nav-bar', position: undefined}; placement = {area: 'nav-bar', position: undefined};
@ -703,7 +710,7 @@ WidgetChrome.prototype._createNode = function WC__createNode() {
node.setAttribute("sdkstylewidget", "true"); node.setAttribute("sdkstylewidget", "true");
if (this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) { 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. // TODO move into a stylesheet, configurable by consumers.

Просмотреть файл

@ -11,8 +11,8 @@ const app = require("sdk/system/xul-app");
// module.metadata.engines // module.metadata.engines
if (app.is('Firefox')) { if (app.is('Firefox')) {
merge(module.exports, merge(module.exports,
require('./tests/test-places-bookmarks'),
require('./tests/test-places-events'), require('./tests/test-places-events'),
require('./tests/test-places-bookmarks'),
require('./tests/test-places-favicon'), require('./tests/test-places-favicon'),
require('./tests/test-places-history'), require('./tests/test-places-history'),
require('./tests/test-places-host'), require('./tests/test-places-host'),

Просмотреть файл

@ -18,6 +18,13 @@ const { setTimeout } = require('sdk/timers');
const { before, after } = require('sdk/test/utils'); const { before, after } = require('sdk/test/utils');
const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1']. const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
getService(Ci.nsINavBookmarksService); 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 { const {
search search
} = require('sdk/places/history'); } = require('sdk/places/history');
@ -51,6 +58,14 @@ exports['test bookmark-item-added'] = function (assert, done) {
exports['test bookmark-item-changed'] = function (assert, done) { exports['test bookmark-item-changed'] = function (assert, done) {
let id; let id;
let complete = makeCompleted(done); 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}) { function handler ({type, data}) {
if (type !== 'bookmark-item-changed') return; if (type !== 'bookmark-item-changed') return;
if (data.id !== id) return; if (data.id !== id) return;
@ -87,6 +102,13 @@ exports['test bookmark-item-moved'] = function (assert, done) {
let complete = makeCompleted(done); let complete = makeCompleted(done);
let previousIndex, previousParentId; 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}) { function handler ({type, data}) {
if (type !== 'bookmark-item-moved') return; if (type !== 'bookmark-item-moved') return;
if (data.id !== id) return; if (data.id !== id) return;

Просмотреть файл

@ -5,9 +5,150 @@
const { Loader } = require("sdk/test/loader"); const { Loader } = require("sdk/test/loader");
const { Class } = require("sdk/core/heritage"); const { Class } = require("sdk/core/heritage");
const { Disposable } = require("sdk/core/disposable");
const { Cc, Ci, Cu } = require("chrome"); const { Cc, Ci, Cu } = require("chrome");
const { setTimeout } = require("sdk/timers"); 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) { exports["test disposables are desposed on unload"] = function(assert) {
let loader = Loader(module); let loader = Loader(module);
let { Disposable } = loader.require("sdk/core/disposable"); 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) { exports["test disposables are GC-able"] = function(assert, done) {
let loader = Loader(module); let loader = Loader(module);
let { Disposable } = loader.require("sdk/core/disposable"); let { Disposable } = loader.require("sdk/core/disposable");
let { WeakReference } = loader.require("sdk/core/reference");
let arg1 = {} let arg1 = {}
let arg2 = 2 let arg2 = 2
@ -91,6 +233,7 @@ exports["test disposables are GC-able"] = function(assert, done) {
let Foo = Class({ let Foo = Class({
extends: Disposable, extends: Disposable,
implements: [WeakReference],
setup: function setup(a, b) { setup: function setup(a, b) {
assert.equal(a, arg1, assert.equal(a, arg1,
"arguments passed to constructur is passed to setup"); "arguments passed to constructur is passed to setup");
@ -106,7 +249,7 @@ exports["test disposables are GC-able"] = function(assert, done) {
this.fooed = false this.fooed = false
disposals = disposals + 1 disposals = disposals + 1
} }
}) });
let foo1 = Foo(arg1, arg2) let foo1 = Foo(arg1, arg2)
let foo2 = 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(); let shown = defer();
function onMessage(type, message) { function onMessage(type, message) {
if (type != 'warn') return;
let warning = 'Passing a DOM node to Panel.show() method is an unsupported ' + let warning = 'Passing a DOM node to Panel.show() method is an unsupported ' +
'feature that will be soon replaced. ' + 'feature that will be soon replaced. ' +
'See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877'; '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(); 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) { exports['test button global state updated on multiple windows'] = function(assert, done) {
let loader = Loader(module); let loader = Loader(module);
let { ActionButton } = loader.require('sdk/ui'); let { ActionButton } = loader.require('sdk/ui');

Просмотреть файл

@ -298,6 +298,43 @@ exports['test button global state updated'] = function(assert) {
loader.unload(); 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) { exports['test button global state updated on multiple windows'] = function(assert, done) {
let loader = Loader(module); let loader = Loader(module);
let { ToggleButton } = loader.require('sdk/ui'); 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 { identify } = loader.require('sdk/ui/id');
let { getActiveView } = loader.require('sdk/view/core'); let { getActiveView } = loader.require('sdk/view/core');
let button = ToggleButton({ let b1 = ToggleButton({
id: 'my-button-22', id: 'my-button-22',
label: 'my button', label: 'my button',
icon: './icon.png', 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
});
panel.once('show', () => {
let { document } = getMostRecentBrowserWindow(); let { document } = getMostRecentBrowserWindow();
let buttonNode = document.getElementById(identify(button)); let b1Node = document.getElementById(identify(b1));
let b2Node = document.getElementById(identify(b2));
let panelNode = getActiveView(panel); let panelNode = getActiveView(panel);
assert.ok(button.state('window').checked, panel.once('show', () => {
assert.ok(b1.state('window').checked,
'button is checked'); 'button is checked');
assert.equal(panelNode.getAttribute('type'), 'arrow', assert.equal(panelNode.getAttribute('type'), 'arrow',
'the panel is a arrow type'); 'the panel is a arrow type');
assert.strictEqual(buttonNode, panelNode.anchorNode, assert.strictEqual(b1Node, panelNode.anchorNode,
'the panel is anchored properly to the button'); 'the panel is anchored properly to the button given in costructor');
panel.hide();
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(); loader.unload();
done(); done();
}); });
button.click(); b2.click();
});
b1.click();
} }
require('sdk/test').run(exports); require('sdk/test').run(exports);

Просмотреть файл

@ -9,13 +9,11 @@ module.metadata = {
} }
}; };
const widgets = require("sdk/widget");
const { Cc, Ci, Cu } = require("chrome"); const { Cc, Ci, Cu } = require("chrome");
const { Loader } = require('sdk/test/loader'); const { LoaderWithHookedConsole } = require('sdk/test/loader');
const url = require("sdk/url"); const url = require("sdk/url");
const timer = require("sdk/timers"); const timer = require("sdk/timers");
const self = require("sdk/self"); const self = require("sdk/self");
const windowUtils = require("sdk/deprecated/window-utils");
const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { getMostRecentBrowserWindow } = require('sdk/window/utils');
const { close, open, focus } = require("sdk/window/helpers"); const { close, open, focus } = require("sdk/window/helpers");
const tabs = require("sdk/tabs/utils"); 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) { 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 doc = browserWindow.document;
let AddonsMgrListener; let AddonsMgrListener;
@ -78,7 +92,7 @@ exports.testConstructor = function(assert, done) {
assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy"); assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy");
// Test automatic widget destroy on unload // Test automatic widget destroy on unload
let loader = Loader(module); let { loader } = LoaderWithHookedConsole(module);
let widgetsFromLoader = loader.require("sdk/widget"); let widgetsFromLoader = loader.require("sdk/widget");
let widgetStartCount = widgetCount(); let widgetStartCount = widgetCount();
let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" }); let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
@ -192,8 +206,10 @@ exports.testConstructor = function(assert, done) {
let tests = []; let tests = [];
function nextTest() { function nextTest() {
assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up"); assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up");
if (!tests.length) if (!tests.length) {
loader0.unload();
done(); done();
}
else else
timer.setTimeout(tests.shift(), 0); timer.setTimeout(tests.shift(), 0);
} }
@ -535,7 +551,7 @@ exports.testConstructor = function(assert, done) {
contentScript: "self.port.on('event', function () self.port.emit('event'))" contentScript: "self.port.on('event', function () self.port.emit('event'))"
}; };
let widget = testSingleWidget(w1Opts); 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 // 2/ Retrieve a WidgetView for the initial browser window
let acceptDetach = false; let acceptDetach = false;
@ -627,16 +643,16 @@ exports.testConstructor = function(assert, done) {
id: "text-test-width", id: "text-test-width",
label: "test widget.width", label: "test widget.width",
content: "test width", content: "test width",
width: 200, width: 64,
contentScript: "self.postMessage(1)", contentScript: "self.postMessage(1)",
contentScriptWhen: "ready", contentScriptWhen: "ready",
onMessage: function(message) { onMessage: function(message) {
assert.equal(this.width, 200, 'width is 200'); assert.equal(this.width, 64, 'width is 64');
let node = widgetNode(0); let node = widgetNode(0);
assert.equal(this.width, node.style.minWidth.replace("px", "")); assert.equal(this.width, node.style.minWidth.replace("px", ""));
assert.equal(this.width, node.firstElementChild.style.width.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.style.minWidth.replace("px", ""));
assert.equal(this.width, node.firstElementChild.style.width.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) { 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", id: "testWidgetWithValidPanel",
label: "panel widget 1", label: "panel widget 1",
content: "<div id='me'>foo</div>", content: "<div id='me'>foo</div>",
contentScript: "var evt = new MouseEvent('click', {button: 0});" + contentScript: "var evt = new MouseEvent('click', {button: 0});" +
"document.body.dispatchEvent(evt);", "document.body.dispatchEvent(evt);",
contentScriptWhen: "end", contentScriptWhen: "end",
panel: require("sdk/panel").Panel({ panel: Panel({
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
onShow: function() { onShow: function() {
let { document } = getMostRecentBrowserWindow(); 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'); assert.strictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget');
widget1.destroy(); widget1.destroy();
loader.unload();
assert.pass("panel displayed on click"); assert.pass("panel displayed on click");
done(); done();
} }
@ -705,7 +724,9 @@ exports.testWidgetWithValidPanel = function(assert, done) {
}; };
exports.testWidgetWithInvalidPanel = function(assert) { exports.testWidgetWithInvalidPanel = function(assert) {
const widgets = require("sdk/widget"); let { loader } = LoaderWithHookedConsole(module);
const widgets = loader.require("sdk/widget");
assert.throws( assert.throws(
function() { function() {
widgets.Widget({ widgets.Widget({
@ -716,10 +737,14 @@ exports.testWidgetWithInvalidPanel = function(assert) {
}, },
/^The option \"panel\" must be one of the following types: null, undefined, object$/, /^The option \"panel\" must be one of the following types: null, undefined, object$/,
"widget.panel must be a Panel object"); "widget.panel must be a Panel object");
loader.unload();
}; };
exports.testPanelWidget3 = function testPanelWidget3(assert, done) { 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 onClickCalled = false;
let widget3 = widgets.Widget({ let widget3 = widgets.Widget({
id: "panel3", id: "panel3",
@ -732,13 +757,14 @@ exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
onClickCalled = true; onClickCalled = true;
this.panel.show(); this.panel.show();
}, },
panel: require("sdk/panel").Panel({ panel: Panel({
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
onShow: function() { onShow: function() {
assert.ok( assert.ok(
onClickCalled, onClickCalled,
"onClick called on click for widget with both panel and onClick"); "onClick called on click for widget with both panel and onClick");
widget3.destroy(); widget3.destroy();
loader.unload();
done(); done();
} }
}) })
@ -747,7 +773,9 @@ exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
exports.testWidgetWithPanelInMenuPanel = function(assert, done) { exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {}); 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({ let widget1 = widgets.Widget({
id: "panel1", id: "panel1",
@ -760,7 +788,7 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
}); });
}, },
contentScriptWhen: "end", contentScriptWhen: "end",
panel: require("sdk/panel").Panel({ panel: Panel({
contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
onShow: function() { onShow: function() {
let { document } = getMostRecentBrowserWindow(); let { document } = getMostRecentBrowserWindow();
@ -771,6 +799,7 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
'the panel is anchored to the panel menu button instead of widget'); 'the panel is anchored to the panel menu button instead of widget');
widget1.destroy(); widget1.destroy();
loader.unload();
done(); done();
} }
}) })
@ -797,8 +826,10 @@ exports.testWidgetWithPanelInMenuPanel = function(assert, done) {
}; };
exports.testWidgetMessaging = function testWidgetMessaging(assert, done) { exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
const widgets = loader.require("sdk/widget");
let origMessage = "foo"; let origMessage = "foo";
const widgets = require("sdk/widget");
let widget = widgets.Widget({ let widget = widgets.Widget({
id: "widget-messaging", id: "widget-messaging",
label: "foo", label: "foo",
@ -811,6 +842,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
else { else {
assert.equal(origMessage, message); assert.equal(origMessage, message);
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
} }
@ -818,7 +850,9 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
}; };
exports.testWidgetViews = function testWidgetViews(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({ let widget = widgets.Widget({
id: "widget-views", id: "widget-views",
label: "foo", label: "foo",
@ -833,6 +867,7 @@ exports.testWidgetViews = function testWidgetViews(assert, done) {
}); });
view.on("detach", function () { view.on("detach", function () {
assert.pass("WidgetView destroyed"); assert.pass("WidgetView destroyed");
loader.unload();
done(); done();
}); });
} }
@ -840,7 +875,10 @@ exports.testWidgetViews = function testWidgetViews(assert, done) {
}; };
exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(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 view = null;
let widget = widgets.Widget({ let widget = widgets.Widget({
id: "widget-view-ui-events", id: "widget-view-ui-events",
@ -856,17 +894,20 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
onClick: function (eventView) { onClick: function (eventView) {
assert.equal(view, eventView, assert.equal(view, eventView,
"event first argument is equal to the WidgetView"); "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, assert.equal(view, view2,
"widget.getView return the same WidgetView"); "widget.getView return the same WidgetView");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
}); });
}; };
exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, 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({ let widget = widgets.Widget({
id: "widget-view-custom-events", id: "widget-view-custom-events",
label: "foo", label: "foo",
@ -883,33 +924,37 @@ exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(asser
widget.port.on("event", function (data) { widget.port.on("event", function (data) {
assert.equal(data, "ok", "event argument is valid on Widget"); assert.equal(data, "ok", "event argument is valid on Widget");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
}); });
}; };
exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, 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({ let widget = new widgets.Widget({
id: "widget-views-tooltip", id: "widget-views-tooltip",
label: "foo", label: "foo",
content: "foo" content: "foo"
}); });
let view = widget.getView(require("sdk/windows").browserWindows.activeWindow); let view = widget.getView(browserWindows.activeWindow);
widget.tooltip = null; widget.tooltip = null;
assert.equal(view.tooltip, "foo", assert.equal(view.tooltip, "foo",
"view tooltip defaults to base widget label"); "view tooltip defaults to base widget label");
assert.equal(widget.tooltip, "foo", assert.equal(widget.tooltip, "foo",
"tooltip defaults to base widget label"); "tooltip defaults to base widget label");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
}; };
exports.testWidgetMove = function testWidgetMove(assert, done) { exports.testWidgetMove = function testWidgetMove(assert, done) {
let windowUtils = require("sdk/deprecated/window-utils"); let { loader } = LoaderWithHookedConsole(module);
let widgets = require("sdk/widget"); const widgets = loader.require("sdk/widget");
let browserWindow = windowUtils.activeBrowserWindow; let browserWindow = getMostRecentBrowserWindow();
let doc = browserWindow.document; let doc = browserWindow.document;
let label = "unique-widget-label"; let label = "unique-widget-label";
@ -939,6 +984,7 @@ exports.testWidgetMove = function testWidgetMove(assert, done) {
else { else {
assert.equal(origMessage, message, "Got message after node move"); assert.equal(origMessage, message, "Got message after node move");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
} }
@ -953,16 +999,17 @@ consider the content change a navigation change, so doesn't load
the new content. the new content.
*/ */
exports.testWidgetWithPound = function testWidgetWithPound(assert, done) { exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
const widgets = loader.require("sdk/widget");
function getWidgetContent(widget) { function getWidgetContent(widget) {
let windowUtils = require("sdk/deprecated/window-utils"); let browserWindow = getMostRecentBrowserWindow();
let browserWindow = windowUtils.activeBrowserWindow;
let doc = browserWindow.document; let doc = browserWindow.document;
let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]'); let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]');
assert.ok(widgetNode, 'found widget node in the front-end'); assert.ok(widgetNode, 'found widget node in the front-end');
return widgetNode.firstChild.contentDocument.body.innerHTML; return widgetNode.firstChild.contentDocument.body.innerHTML;
} }
let widgets = require("sdk/widget");
let count = 0; let count = 0;
let widget = widgets.Widget({ let widget = widgets.Widget({
id: "1", id: "1",
@ -977,6 +1024,7 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
else { else {
assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?"); assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
} }
@ -984,7 +1032,10 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
}; };
exports.testContentScriptOptionsOption = function(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", id: "widget-script-options",
label: "fooz", label: "fooz",
content: "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].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' );
assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' ); assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' );
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
}); });
}; };
exports.testOnAttachWithoutContentScript = function(assert, 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", id: "onAttachNoCS",
label: "onAttachNoCS", label: "onAttachNoCS",
content: "onAttachNoCS", content: "onAttachNoCS",
onAttach: function (view) { onAttach: function (view) {
assert.pass("received attach event"); assert.pass("received attach event");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
}); });
}; };
exports.testPostMessageOnAttach = function(assert, 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", id: "onAttach",
label: "onAttach", label: "onAttach",
content: "onAttach", content: "onAttach",
@ -1031,15 +1090,19 @@ exports.testPostMessageOnAttach = function(assert, done) {
onMessage: function (msg) { onMessage: function (msg) {
assert.equal( msg, "ok", "postMessage works on `attach` event"); assert.equal( msg, "ok", "postMessage works on `attach` event");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
}); });
}; };
exports.testPostMessageOnLocationChange = function(assert, done) { exports.testPostMessageOnLocationChange = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
const { Widget } = loader.require("sdk/widget");
let attachEventCount = 0; let attachEventCount = 0;
let messagesCount = 0; let messagesCount = 0;
let widget = require("sdk/widget").Widget({ let widget = Widget({
id: "onLocationChange", id: "onLocationChange",
label: "onLocationChange", label: "onLocationChange",
content: "onLocationChange", content: "onLocationChange",
@ -1065,6 +1128,7 @@ exports.testPostMessageOnLocationChange = function(assert, done) {
assert.equal(msg, "ok", assert.equal(msg, "ok",
"We receive the message sent to the 2nd document"); "We receive the message sent to the 2nd document");
widget.destroy(); widget.destroy();
loader.unload();
done(); done();
} }
} }
@ -1072,10 +1136,13 @@ exports.testPostMessageOnLocationChange = function(assert, done) {
}; };
exports.testSVGWidget = 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.. // use of capital SVG here is intended, that was failing..
let SVG_URL = fixtures.url("mofo_logo.SVG"); let SVG_URL = fixtures.url("mofo_logo.SVG");
let widget = require("sdk/widget").Widget({ let widget = Widget({
id: "mozilla-svg-logo", id: "mozilla-svg-logo",
label: "moz foundation logo", label: "moz foundation logo",
contentURL: SVG_URL, contentURL: SVG_URL,
@ -1084,16 +1151,19 @@ exports.testSVGWidget = function(assert, done) {
widget.destroy(); widget.destroy();
assert.equal(data.count, 1, 'only one image'); assert.equal(data.count, 1, 'only one image');
assert.equal(data.src, SVG_URL, 'only one image'); assert.equal(data.src, SVG_URL, 'only one image');
loader.unload();
done(); done();
} }
}); });
}; };
exports.testReinsertion = function(assert, done) { exports.testReinsertion = function(assert, done) {
let { loader } = LoaderWithHookedConsole(module);
const { Widget } = loader.require("sdk/widget");
const WIDGETID = "test-reinsertion"; const WIDGETID = "test-reinsertion";
let windowUtils = require("sdk/deprecated/window-utils"); let browserWindow = getMostRecentBrowserWindow();
let browserWindow = windowUtils.activeBrowserWindow;
let widget = require("sdk/widget").Widget({ let widget = Widget({
id: "test-reinsertion", id: "test-reinsertion",
label: "test reinsertion", label: "test reinsertion",
content: "Test", content: "Test",
@ -1105,8 +1175,39 @@ exports.testReinsertion = function(assert, done) {
openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) {
assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null); 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); 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 # 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 # Then ship our own gaia profile
add_dir_to_zip(xpi_path, os.path.join(gaia_path, "profile"), "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 bin = URL.toFilename(BIN_URL);
let executables = { let executables = {
WINNT: "b2g-bin.exe", WINNT: "b2g-bin.exe",
Darwin: "Contents/MacOS/b2g-bin", Darwin: "B2G.app/Contents/MacOS/b2g-bin",
Linux: "b2g-bin", Linux: "b2g-bin",
}; };

Просмотреть файл

@ -1182,15 +1182,14 @@
<svg:svg height="0"> <svg:svg height="0">
#include tab-shape.inc.svg #include tab-shape.inc.svg
#ifndef XP_UNIX #ifndef XP_MACOSX
<svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse"> <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: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>
<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: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> </svg:clipPath>
#endif #else
#ifdef XP_MACOSX
<svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse"> <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: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>

Просмотреть файл

@ -529,7 +529,12 @@ var tests = [
this.notifyObj.addOptions({dismissed: true}); this.notifyObj.addOptions({dismissed: true});
this.notification = showNotification(this.notifyObj); 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) { onShown: function(popup) {
checkPopup(popup, this.notifyObj); checkPopup(popup, this.notifyObj);

Просмотреть файл

@ -49,6 +49,7 @@ const PanelUI = {
this.menuButton.addEventListener("keypress", this); this.menuButton.addEventListener("keypress", this);
this._overlayScrollListenerBoundFn = this._overlayScrollListener.bind(this); this._overlayScrollListenerBoundFn = this._overlayScrollListener.bind(this);
window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn); window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn);
CustomizableUI.addListener(this);
this._initialized = true; this._initialized = true;
}, },
@ -69,10 +70,6 @@ const PanelUI = {
}, },
uninit: function() { uninit: function() {
if (!this._eventListenersAdded) {
return;
}
for (let event of this.kEvents) { for (let event of this.kEvents) {
this.panel.removeEventListener(event, this); this.panel.removeEventListener(event, this);
} }
@ -80,6 +77,7 @@ const PanelUI = {
this.menuButton.removeEventListener("mousedown", this); this.menuButton.removeEventListener("mousedown", this);
this.menuButton.removeEventListener("keypress", this); this.menuButton.removeEventListener("keypress", this);
window.matchMedia("(-moz-overlay-scrollbars)").removeListener(this._overlayScrollListenerBoundFn); window.matchMedia("(-moz-overlay-scrollbars)").removeListener(this._overlayScrollListenerBoundFn);
CustomizableUI.removeListener(this);
this._overlayScrollListenerBoundFn = null; this._overlayScrollListenerBoundFn = null;
}, },
@ -183,6 +181,7 @@ const PanelUI = {
handleEvent: function(aEvent) { handleEvent: function(aEvent) {
switch (aEvent.type) { switch (aEvent.type) {
case "popupshowing": case "popupshowing":
this._adjustLabelsForAutoHyphens();
// Fall through // Fall through
case "popupshown": case "popupshown":
// Fall through // Fall through
@ -370,6 +369,26 @@ const PanelUI = {
"browser"); "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 * 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. * panels all at once. For performance, we ignore the mutations.
@ -389,6 +408,22 @@ const PanelUI = {
this.multiView.ignoreMutations = false; 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 * Sets the anchor node into the open or closed state, depending
* on the state of the panel. * on the state of the panel.

Просмотреть файл

@ -68,6 +68,7 @@ skip-if = os == "linux"
[browser_948985_non_removable_defaultArea.js] [browser_948985_non_removable_defaultArea.js]
[browser_952963_areaType_getter_no_area.js] [browser_952963_areaType_getter_no_area.js]
[browser_956602_remove_special_widget.js] [browser_956602_remove_special_widget.js]
[browser_962884_opt_in_disable_hyphens.js]
[browser_963639_customizing_attribute_non_customizable_toolbar.js] [browser_963639_customizing_attribute_non_customizable_toolbar.js]
[browser_967000_button_charEncoding.js] [browser_967000_button_charEncoding.js]
[browser_967000_button_feeds.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 &shy; 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 &shy; 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 &shy; 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 &shy; 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 &shy; 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 #endif
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/> <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" <tabbox id="advancedPrefs" flex="1"
data-category="paneAdvanced" hidden="true" data-category="paneAdvanced" hidden="true"
onselect="gAdvancedPane.tabSelectionChanged();"> onselect="gAdvancedPane.tabSelectionChanged();">

Просмотреть файл

@ -55,7 +55,19 @@
<key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/> <key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
</keyset> </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> <hbox>
<textbox id="filter" flex="1" <textbox id="filter" flex="1"
type="search" type="search"

Просмотреть файл

@ -21,6 +21,15 @@
<script type="application/javascript" <script type="application/javascript"
src="chrome://browser/content/preferences/in-content/content.js"/> 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"> <groupbox id="miscGroup" data-category="paneContent" hidden="true">
<caption label="&popups.label;"/> <caption label="&popups.label;"/>

Просмотреть файл

@ -85,6 +85,14 @@
#endif #endif
</preferences> </preferences>
<hbox id="header-general"
class="header"
data-category="paneGeneral">
<image class="header-icon"/>
<label class="header-name"
value="&paneGeneral.title;"/>
</hbox>
<!-- Startup --> <!-- Startup -->
<groupbox id="startupGroup" data-category="paneGeneral"> <groupbox id="startupGroup" data-category="paneGeneral">
<caption label="&startup.label;"/> <caption label="&startup.label;"/>

Просмотреть файл

@ -32,10 +32,8 @@ function init_all() {
let categories = document.getElementById("categories"); let categories = document.getElementById("categories");
categories.addEventListener("select", event => gotoPref(event.target.value)); categories.addEventListener("select", event => gotoPref(event.target.value));
window.addEventListener("popstate", event => selectCategory(event.state));
if (history.length > 1 && history.state) { if (history.length > 1 && history.state) {
updateCommands();
selectCategory(history.state); selectCategory(history.state);
} else { } else {
history.replaceState("paneGeneral", document.title); history.replaceState("paneGeneral", document.title);
@ -49,39 +47,10 @@ function selectCategory(name) {
} }
function gotoPref(page) { function gotoPref(page) {
if (history.state != page) { window.history.replaceState(page, document.title);
window.history.pushState(page, document.title);
}
updateCommands();
search(page, "data-category"); 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) { function search(aQuery, aAttribute) {
let elements = document.getElementById("mainPrefPane").children; let elements = document.getElementById("mainPrefPane").children;
for (let element of elements) { for (let element of elements) {

Просмотреть файл

@ -74,15 +74,6 @@
src="chrome://browser/locale/preferences/applicationManager.properties"/> src="chrome://browser/locale/preferences/applicationManager.properties"/>
</stringbundleset> </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"> <hbox flex="1">
<!-- category list --> <!-- category list -->

Просмотреть файл

@ -65,6 +65,15 @@
</preferences> </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 --> <!-- Tracking -->
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start"> <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
<caption label="&tracking.label;"/> <caption label="&tracking.label;"/>

Просмотреть файл

@ -30,6 +30,15 @@
</preferences> </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 --> <!-- addons, forgery (phishing) UI -->
<groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true"> <groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true">
<caption label="&general.label;"/> <caption label="&general.label;"/>

Просмотреть файл

@ -28,6 +28,15 @@
<script type="application/javascript" <script type="application/javascript"
src="chrome://browser/content/sync/utils.js"/> 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"> <deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
<vbox id="noAccount" align="center"> <vbox id="noAccount" align="center">
<spacer flex="1"/> <spacer flex="1"/>

Просмотреть файл

@ -23,6 +23,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm"); "resource:///modules/sessionstore/SessionStore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionFile", XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
"resource:///modules/sessionstore/SessionFile.jsm"); "resource:///modules/sessionstore/SessionFile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
// Minimal interval between two save operations (in milliseconds). // Minimal interval between two save operations (in milliseconds).
XPCOMUtils.defineLazyGetter(this, "gInterval", function () { XPCOMUtils.defineLazyGetter(this, "gInterval", function () {
@ -41,14 +43,6 @@ XPCOMUtils.defineLazyGetter(this, "gInterval", function () {
return Services.prefs.getIntPref(PREF); 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. // Notify observers about a given topic with a given subject.
function notify(subject, topic) { function notify(subject, topic) {
Services.obs.notifyObservers(subject, topic, ""); Services.obs.notifyObservers(subject, topic, "");
@ -192,6 +186,14 @@ let SessionSaverInternal = {
// Cancel any pending timeouts. // Cancel any pending timeouts.
this.cancel(); 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"); stopWatchStart("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
let state = SessionStore.getCurrentState(forceUpdateAllWindows); let state = SessionStore.getCurrentState(forceUpdateAllWindows);
PrivacyFilter.filterPrivateWindowsAndTabs(state); PrivacyFilter.filterPrivateWindowsAndTabs(state);
@ -242,19 +244,13 @@ let SessionSaverInternal = {
* Write the given state object to disk. * Write the given state object to disk.
*/ */
_writeState: function (state) { _writeState: function (state) {
// Inform observers
notify(null, "sessionstore-state-write");
stopWatchStart("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS", "WRITE_STATE_LONGEST_OP_MS"); stopWatchStart("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS", "WRITE_STATE_LONGEST_OP_MS");
let data = JSON.stringify(state); let data = JSON.stringify(state);
stopWatchFinish("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS"); 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 // 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 // too soon, if saving is requested before the write completes. Without
// this update we may save repeatedly if actions cause a runDelayed // this update we may save repeatedly if actions cause a runDelayed
@ -275,14 +271,4 @@ let SessionSaverInternal = {
return promise; 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. // recently something was closed.
winData.closedAt = Date.now(); winData.closedAt = Date.now();
// Save the window if it has multiple tabs or a single saveable tab and // Save non-private windows if they have at
// it's not private. // least one saveable tab or are the last window.
if (!winData.isPrivate) { if (!winData.isPrivate) {
// Remove any open private tabs the window may contain. // Remove any open private tabs the window may contain.
PrivacyFilter.filterPrivateTabs(winData); PrivacyFilter.filterPrivateTabs(winData);
let hasSingleTabToSave = // Determine whether the window has any tabs worth saving.
winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]); 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 // we don't want to save the busy state
delete winData.busy; delete winData.busy;

Просмотреть файл

@ -98,7 +98,6 @@ skip-if = true
[browser_394759_purge.js] [browser_394759_purge.js]
[browser_423132.js] [browser_423132.js]
[browser_447951.js] [browser_447951.js]
[browser_448741.js]
[browser_454908.js] [browser_454908.js]
[browser_456342.js] [browser_456342.js]
[browser_461634.js] [browser_461634.js]

Просмотреть файл

@ -75,15 +75,13 @@ function test() {
// Wait for the sessionstore.js file to be written before going on. // 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 // Note: we don't wait for the complete event, since if asyncCopy fails we
// would timeout. // would timeout.
Services.obs.addObserver(function (aSubject, aTopic, aData) { waitForSaveState(function(writing) {
Services.obs.removeObserver(arguments.callee, aTopic); ok(writing, "sessionstore.js is being written");
info("sessionstore.js is being written");
closedWindowCount = ss.getClosedWindowCount(); closedWindowCount = ss.getClosedWindowCount();
is(closedWindowCount, 0, "Correctly set window count"); is(closedWindowCount, 0, "Correctly set window count");
executeSoon(aCallback); executeSoon(aCallback);
}, "sessionstore-state-write", false); });
// Remove the sessionstore.js file before setting the interval to 0 // Remove the sessionstore.js file before setting the interval to 0
let profilePath = Services.dirsvc.get("ProfD", Ci.nsIFile); 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"); Services.prefs.clearUserPref("browser.sessionstore.interval");
}); });
// This tests the following use case: // This tests the following use case: When multiple windows are open
// When multiple windows are open and browser.sessionstore.resume_from_crash // and browser.sessionstore.resume_from_crash preference is false,
// preference is false, tab session data for non-active window is stripped for // tab session data for non-active window is stripped for non-pinned
// non-pinned tabs. This occurs after "sessionstore-state-write" fires which // tabs. This occurs after "sessionstore-state-write-complete"
// will only fire in this case if there is at least one pinned tab. // fires which will only fire in this case if there is at least one
// pinned tab.
let state = { windows: [ let state = { windows: [
{ {
tabs: [ tabs: [

Просмотреть файл

@ -1,125 +1,86 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */ http://creativecommons.org/publicdomain/zero/1.0/ */
let newWin; add_task(function* setup() {
let newTab;
function test() {
/** Test for Bug 625016 - Restore windows closed in succession to quit (non-OSX only) **/ /** 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 // We'll test this by opening a new window, waiting for the save
// closing that window. We'll observe the "sessionstore-state-write" notification // event, then closing that window. We'll observe the
// and check that the state contains no _closedWindows. We'll then add a new // "sessionstore-state-write-complete" notification and check that
// tab and make sure that the state following that was reset and the closed // the state contains no _closedWindows. We'll then add a new tab
// window is now in _closedWindows. // and make sure that the state following that was reset and the
// closed window is now in _closedWindows.
waitForExplicitFinish();
requestLongerTimeout(2); requestLongerTimeout(2);
// We speed up the interval between session saves to ensure that the test yield forceSaveState();
// runs quickly.
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.sessionstore.interval");
});
waitForSaveState(setup);
}
function setup() {
// We'll clear all closed windows to make sure our state is clean // We'll clear all closed windows to make sure our state is clean
// forgetClosedWindow doesn't trigger a delayed save // forgetClosedWindow doesn't trigger a delayed save
while (ss.getClosedWindowCount()) { while (ss.getClosedWindowCount()) {
ss.forgetClosedWindow(0); ss.forgetClosedWindow(0);
} }
is(ss.getClosedWindowCount(), 0, "starting with no closed windows"); is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
});
// Open a new window, which should trigger a save event soon. add_task(function* new_window() {
waitForSaveState(onSaveState); let newWin;
newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:rights");
}
function onSaveState() {
try { try {
ss.getWindowValue(newWin, "foobar"); newWin = yield promiseNewWindowLoaded();
} catch (e) { let tab = newWin.gBrowser.addTab("http://example.com/browser_625016.js?" + Math.random());
// The window is untracked which means that the saveState() call isn't the yield promiseBrowserLoaded(tab.linkedBrowser);
// one we're waiting for. It's most likely been triggered by an async
// collection running in the background.
waitForSaveState(onSaveState);
return;
}
// Double check that we have no closed windows // Double check that we have no closed windows
is(ss.getClosedWindowCount(), 0, "no closed windows on first save"); is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
Services.obs.addObserver(observe1, "sessionstore-state-write", false); yield promiseWindowClosed(newWin);
newWin = null;
// Now close the new window, which should trigger another save event let state = JSON.parse((yield promiseSaveFileContents()));
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, is(state.windows.length, 2,
"observe1: 2 windows in data being writted to disk"); "observe1: 2 windows in data written to disk");
is(state._closedWindows.length, 0, is(state._closedWindows.length, 0,
"observe1: no closed windows in data being writted to disk"); "observe1: no closed windows in data written to disk");
// The API still treats the closed window as closed, so ensure that window is there // The API still treats the closed window as closed, so ensure that window is there
is(ss.getClosedWindowCount(), 1, is(ss.getClosedWindowCount(), 1,
"observe1: 1 closed window according to API"); "observe1: 1 closed window according to API");
Services.obs.removeObserver(observe1, "sessionstore-state-write"); } finally {
Services.obs.addObserver(observe1, "sessionstore-state-write-complete", false); if (newWin) {
break; yield promiseWindowClosed(newWin);
case "sessionstore-state-write-complete":
Services.obs.removeObserver(observe1, "sessionstore-state-write-complete");
openTab();
break;
} }
yield forceSaveState();
} }
});
function observe2(aSubject, aTopic, aData) { // We'll open a tab, which should trigger another state save which would wipe
info("observe2: " + aTopic); // the _shouldRestore attribute from the closed window
switch (aTopic) { add_task(function* new_tab() {
case "sessionstore-state-write": let newTab;
aSubject.QueryInterface(Ci.nsISupportsString); try {
let state = JSON.parse(aSubject.data); newTab = gBrowser.addTab("about:mozilla");
let state = JSON.parse((yield promiseSaveFileContents()));
is(state.windows.length, 1, is(state.windows.length, 1,
"observe2: 1 window in data being writted to disk"); "observe2: 1 window in data being written to disk");
is(state._closedWindows.length, 1, is(state._closedWindows.length, 1,
"observe2: 1 closed window in data being writted to disk"); "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 // The API still treats the closed window as closed, so ensure that window is there
is(ss.getClosedWindowCount(), 1, is(ss.getClosedWindowCount(), 1,
"observe2: 1 closed window according to API"); "observe2: 1 closed window according to API");
Services.obs.removeObserver(observe2, "sessionstore-state-write"); } finally {
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");
}
function done() {
gBrowser.removeTab(newTab); gBrowser.removeTab(newTab);
}
});
add_task(function* done() {
// The API still represents the closed window as closed, so we can clear it // The API still represents the closed window as closed, so we can clear it
// with the API, but just to make sure... // with the API, but just to make sure...
is(ss.getClosedWindowCount(), 1, "1 closed window according to API"); // is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
while (ss.getClosedWindowCount()) {
ss.forgetClosedWindow(0); ss.forgetClosedWindow(0);
executeSoon(finish);
} }
Services.prefs.clearUserPref("browser.sessionstore.interval");
});

Просмотреть файл

@ -162,15 +162,9 @@ function waitForWindowClose(aWin, aCallback) {
} }
function forceWriteState(aCallback) { function forceWriteState(aCallback) {
Services.obs.addObserver(function observe(aSubject, aTopic, aData) { return promiseSaveFileContents().then(function(data) {
if (aTopic == "sessionstore-state-write") { aCallback(JSON.parse(data));
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);
} }
function testOnWindow(aIsPrivate, aCallback) { function testOnWindow(aIsPrivate, aCallback) {

Просмотреть файл

@ -24,43 +24,9 @@ let gDecoder = new TextDecoder();
let gSSData; let gSSData;
let gSSBakData; 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); add_task(function* testAfterFirstWrite() {
}
// 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() {
// Ensure sessionstore.bak is not created. We start with a clean // Ensure sessionstore.bak is not created. We start with a clean
// profile so there was nothing to move to sessionstore.bak before // profile so there was nothing to move to sessionstore.bak before
// initially writing sessionstore.js // initially writing sessionstore.js
@ -78,10 +44,10 @@ function testAfterFirstWrite() {
// and a backup would not be triggered again. // and a backup would not be triggered again.
yield OS.File.move(path, backupPath); yield OS.File.move(path, backupPath);
nextTest(testReadBackup); yield forceSaveState();
} });
function testReadBackup() { add_task(function* testReadBackup() {
// Ensure sessionstore.bak is finally created. // Ensure sessionstore.bak is finally created.
let ssExists = yield OS.File.exists(path); let ssExists = yield OS.File.exists(path);
let ssBackupExists = yield OS.File.exists(backupPath); let ssBackupExists = yield OS.File.exists(backupPath);
@ -114,10 +80,10 @@ function testReadBackup() {
is(ssDataRead, gSSBakData, is(ssDataRead, gSSBakData,
"SessionFile.read read sessionstore.bak correctly."); "SessionFile.read read sessionstore.bak correctly.");
nextTest(testBackupUnchanged); yield forceSaveState();
} });
function testBackupUnchanged() { add_task(function* testBackupUnchanged() {
// Ensure sessionstore.bak is backed up only once. // Ensure sessionstore.bak is backed up only once.
// Read sessionstore.bak data. // Read sessionstore.bak data.
@ -125,6 +91,9 @@ function testBackupUnchanged() {
let ssBakData = gDecoder.decode(array); let ssBakData = gDecoder.decode(array);
// Ensure the sessionstore.bak did not change. // Ensure the sessionstore.bak did not change.
is(ssBakData, gSSBakData, "sessionstore.bak is unchanged."); 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 * Wait until session restore has finished collecting its data and is
* getting ready to write that data ("sessionstore-state-write"). * has written that data ("sessionstore-state-write-complete").
*
* 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.
* *
* @param {function} aCallback If sessionstore-state-write is sent * @param {function} aCallback If sessionstore-state-write is sent
* within buffering interval + 100 ms, the callback is passed |true|, * within buffering interval + 100 ms, the callback is passed |true|,
@ -257,7 +252,7 @@ function waitForTopic(aTopic, aTimeout, aCallback) {
function waitForSaveState(aCallback) { function waitForSaveState(aCallback) {
let timeout = 100 + let timeout = 100 +
Services.prefs.getIntPref("browser.sessionstore.interval"); Services.prefs.getIntPref("browser.sessionstore.interval");
return waitForTopic("sessionstore-state-write", timeout, aCallback); return waitForTopic("sessionstore-state-write-complete", timeout, aCallback);
} }
function promiseSaveState() { function promiseSaveState() {
let deferred = Promise.defer(); let deferred = Promise.defer();
@ -272,22 +267,30 @@ function promiseSaveState() {
function forceSaveState() { function forceSaveState() {
let promise = promiseSaveState(); let promise = promiseSaveState();
const PREF = "browser.sessionstore.interval"; const PREF = "browser.sessionstore.interval";
let original = Services.prefs.getIntPref(PREF);
// Set interval to an arbitrary non-0 duration // Set interval to an arbitrary non-0 duration
// to ensure that setting it to 0 will notify observers // to ensure that setting it to 0 will notify observers
Services.prefs.setIntPref(PREF, 1000); Services.prefs.setIntPref(PREF, 1000);
Services.prefs.setIntPref(PREF, 0); Services.prefs.setIntPref(PREF, 0);
return promise.then( return promise.then(
function onSuccess(x) { function onSuccess(x) {
Services.prefs.clearUserPref(PREF); Services.prefs.setIntPref(PREF, original);
return x; return x;
}, },
function onError(x) { function onError(x) {
Services.prefs.clearUserPref(PREF); Services.prefs.setIntPref(PREF, original);
throw x; 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) { function whenBrowserLoaded(aBrowser, aCallback = next, ignoreSubFrames = true) {
aBrowser.addEventListener("load", function onLoad(event) { aBrowser.addEventListener("load", function onLoad(event) {
if (!ignoreSubFrames || event.target == aBrowser.contentDocument) { if (!ignoreSubFrames || event.target == aBrowser.contentDocument) {
@ -321,6 +324,11 @@ function whenWindowLoaded(aWindow, aCallback = next) {
}); });
}, false); }, false);
} }
function promiseWindowLoaded(aWindow) {
let deferred = Promise.defer();
whenWindowLoaded(aWindow, deferred.resolve);
return deferred.promise;
}
function whenTabRestored(aTab, aCallback = next) { function whenTabRestored(aTab, aCallback = next) {
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) { aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {

Просмотреть файл

@ -110,6 +110,7 @@ skip-if = true # Bug 922422
[browser_tabview_bug641802.js] [browser_tabview_bug641802.js]
[browser_tabview_bug642793.js] [browser_tabview_bug642793.js]
[browser_tabview_bug643392.js] [browser_tabview_bug643392.js]
skip-if = os == 'linux'&&debug # bug 989083
[browser_tabview_bug644097.js] [browser_tabview_bug644097.js]
[browser_tabview_bug648882.js] [browser_tabview_bug648882.js]
skip-if = true # Bug 752862 skip-if = true # Bug 752862

Просмотреть файл

@ -6,13 +6,13 @@ const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionSto
let state = { let state = {
windows: [{ windows: [{
tabs: [{ tabs: [{
entries: [{ url: "about:blank" }], entries: [{ url: "about:robots" }],
hidden: true, 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, 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, selected: 2,
extData: { extData: {

Просмотреть файл

@ -4,13 +4,13 @@
let state = { let state = {
windows: [{ windows: [{
tabs: [{ tabs: [{
entries: [{ url: "about:blank" }], entries: [{ url: "about:robots" }],
hidden: true, 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, 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, selected: 2,
extData: { extData: {

Просмотреть файл

@ -8,23 +8,23 @@ function test() {
let newState = { let newState = {
windows: [{ windows: [{
tabs: [{ tabs: [{
entries: [{ url: "about:blank" }], entries: [{ url: "about:robots" }],
hidden: true, hidden: true,
attributes: {}, attributes: {},
extData: { extData: {
"tabview-tab": "tabview-tab":
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' + '{"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}' '"imageData":null,"title":null}'
} }
},{ },{
entries: [{ url: "about:blank" }], entries: [{ url: "about:robots" }],
hidden: false, hidden: false,
attributes: {}, attributes: {},
extData: { extData: {
"tabview-tab": "tabview-tab":
'{"bounds":{"left":315,"top":29,"width":111,"height":84},' + '{"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}' '"imageData":null,"title":null}'
}, },
}], }],

Просмотреть файл

@ -3,7 +3,6 @@
ac_add_options --enable-debug ac_add_options --enable-debug
ac_add_options --enable-trace-malloc ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar ac_add_options --enable-signmar
ac_add_options --enable-metro
# Needed to enable breakpad in application.ini # Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1 export MOZILLA_OFFICIAL=1

Просмотреть файл

@ -3,7 +3,6 @@
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging ac_add_options --enable-update-packaging
ac_add_options --with-l10n-base=../../l10n ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-metro
ac_add_options --with-windows-version=601 ac_add_options --with-windows-version=601
export MOZILLA_OFFICIAL=1 export MOZILLA_OFFICIAL=1

Просмотреть файл

@ -5,7 +5,6 @@
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging ac_add_options --enable-update-packaging
ac_add_options --enable-jemalloc ac_add_options --enable-jemalloc
ac_add_options --enable-metro
if [ -f /c/builds/gapi.data ]; then if [ -f /c/builds/gapi.data ]; then
_gapi_keyfile=/c/builds/gapi.data _gapi_keyfile=/c/builds/gapi.data
else else

Просмотреть файл

@ -6,7 +6,6 @@ ac_add_options --host=x86_64-pc-mingw32
ac_add_options --enable-debug ac_add_options --enable-debug
ac_add_options --enable-trace-malloc ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar ac_add_options --enable-signmar
ac_add_options --enable-metro
# Needed to enable breakpad in application.ini # Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1 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. * Helper method for debugging.
* @param string * @param string

Просмотреть файл

@ -11,6 +11,11 @@ const SAMPLE_SIZE = 50; // no of lines
const INDENT_COUNT_THRESHOLD = 5; // percentage const INDENT_COUNT_THRESHOLD = 5; // percentage
const CHARACTER_LIMIT = 250; // line character limit 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. * Functions handling the sources UI.
*/ */
@ -49,6 +54,15 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
showArrows: true 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.emptyText = L10N.getStr("noSourcesText");
this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip"); this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip");
@ -132,12 +146,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let group = SourceUtils.getSourceGroup(url); let group = SourceUtils.getSourceGroup(url);
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(fullUrl)); let unicodeUrl = NetworkHelper.convertToUnicode(unescape(fullUrl));
let sdkModuleName = getSDKModuleName(url);
if (sdkModuleName) {
label = sdkModuleName;
group = "Add-on SDK";
}
let contents = document.createElement("label"); let contents = document.createElement("label");
contents.className = "plain dbg-source-item"; contents.className = "plain dbg-source-item";
contents.setAttribute("value", label); contents.setAttribute("value", label);
@ -1560,7 +1568,17 @@ let SourceUtils = {
return cachedLabel; 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)); let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
this._labelsCache.set(aUrl, unicodeLabel); this._labelsCache.set(aUrl, unicodeLabel);
return unicodeLabel; return unicodeLabel;
@ -1583,14 +1601,20 @@ let SourceUtils = {
try { try {
// Use an nsIURL to parse all the url path parts. // Use an nsIURL to parse all the url path parts.
let url = aUrl.split(" -> ").pop(); var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
var uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL);
} catch (e) { } catch (e) {
// This doesn't look like a url, or nsIURL can't handle it. // This doesn't look like a url, or nsIURL can't handle it.
return ""; return "";
} }
let groupLabel = uri.prePath; 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)); let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
this._groupsCache.set(aUrl, unicodeLabel) this._groupsCache.set(aUrl, unicodeLabel)
return unicodeLabel; return unicodeLabel;

Просмотреть файл

@ -5,7 +5,18 @@
const ADDON4_URL = EXAMPLE_URL + "addon4.xpi"; 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() { function test() {
Task.spawn(function () { Task.spawn(function () {
@ -18,6 +29,8 @@ function test() {
let iframe = document.createElement("iframe"); let iframe = document.createElement("iframe");
document.documentElement.appendChild(iframe); document.documentElement.appendChild(iframe);
window.addEventListener("message", onMessage);
let transport = DebuggerServer.connectPipe(); let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport); gClient = new DebuggerClient(transport);
@ -43,6 +56,7 @@ function test() {
yield closeConnection(); yield closeConnection();
yield debuggerPanel._toolbox.destroy(); yield debuggerPanel._toolbox.destroy();
iframe.remove(); iframe.remove();
window.removeEventListener("message", onMessage);
finish(); finish();
}); });
} }
@ -62,7 +76,7 @@ function testSources(expectSecondModule) {
gThreadClient.getSources(({sources}) => { gThreadClient.getSources(({sources}) => {
ok(sources.length, "retrieved sources"); ok(sources.length, "retrieved sources");
sources.forEach(source => { for (let source of sources) {
let url = source.url.split(" -> ").pop(); let url = source.url.split(" -> ").pop();
let { label, group } = gSources.getItemByValue(source.url).attachment; let { label, group } = gSources.getItemByValue(source.url).attachment;
@ -81,12 +95,19 @@ function testSources(expectSecondModule) {
} else { } else {
ok(false, "Saw an unexpected source: " + url); ok(false, "Saw an unexpected source: " + url);
} }
}); }
ok(foundAddonModule, "found JS module for the addon in the list"); ok(foundAddonModule, "found JS module for the addon in the list");
is(foundAddonModule2, expectSecondModule, "saw the second addon module"); is(foundAddonModule2, expectSecondModule, "saw the second addon module");
ok(foundAddonBootstrap, "found bootstrap script for the addon in the list"); 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(); deferred.resolve();
}); });

Просмотреть файл

@ -6,7 +6,18 @@
const ADDON3_URL = EXAMPLE_URL + "addon3.xpi"; 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() { function test() {
Task.spawn(function () { Task.spawn(function () {
@ -19,6 +30,8 @@ function test() {
let iframe = document.createElement("iframe"); let iframe = document.createElement("iframe");
document.documentElement.appendChild(iframe); document.documentElement.appendChild(iframe);
window.addEventListener("message", onMessage);
let transport = DebuggerServer.connectPipe(); let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport); gClient = new DebuggerClient(transport);
@ -37,6 +50,7 @@ function test() {
yield closeConnection(); yield closeConnection();
yield debuggerPanel._toolbox.destroy(); yield debuggerPanel._toolbox.destroy();
iframe.remove(); iframe.remove();
window.removeEventListener("message", onMessage);
finish(); finish();
}); });
} }
@ -56,7 +70,7 @@ function testSources() {
gThreadClient.getSources(({sources}) => { gThreadClient.getSources(({sources}) => {
ok(sources.length, "retrieved sources"); ok(sources.length, "retrieved sources");
sources.forEach(source => { for (let source of sources) {
let url = source.url.split(" -> ").pop(); let url = source.url.split(" -> ").pop();
info(source.url + "\n\n\n" + url); info(source.url + "\n\n\n" + url);
let { label, group } = gSources.getItemByValue(source.url).attachment; let { label, group } = gSources.getItemByValue(source.url).attachment;
@ -80,7 +94,7 @@ function testSources() {
} else { } else {
ok(false, "Saw an unexpected source: " + url); ok(false, "Saw an unexpected source: " + url);
} }
}); }
ok(foundAddonModule, "found code for the addon in the list"); ok(foundAddonModule, "found code for the addon in the list");
ok(foundAddonBootstrap, "found bootstrap 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 // built-in browser SDK modules
ok(foundSDKModule > 10, "SDK modules are listed"); 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(); deferred.resolve();
}); });

Просмотреть файл

@ -504,9 +504,9 @@ function initDebugger(aTarget, aWindow) {
function initAddonDebugger(aClient, aUrl, aFrame) { function initAddonDebugger(aClient, aUrl, aFrame) {
info("Initializing an addon debugger panel."); info("Initializing an addon debugger panel.");
return getAddonActorForUrl(aClient, aUrl).then(({actor}) => { return getAddonActorForUrl(aClient, aUrl).then((addonActor) => {
let targetOptions = { let targetOptions = {
form: { addonActor: actor }, form: { addonActor: addonActor.actor, title: addonActor.name },
client: aClient, client: aClient,
chrome: true chrome: true
}; };

Просмотреть файл

@ -37,7 +37,7 @@ function connect() {
if (addonID) { if (addonID) {
gClient.listAddons(({addons}) => { gClient.listAddons(({addons}) => {
let addonActor = addons.filter(addon => addon.id === addonID).pop(); let addonActor = addons.filter(addon => addon.id === addonID).pop();
openToolbox({ addonActor: addonActor.actor }); openToolbox({ addonActor: addonActor.actor, title: addonActor.name });
}); });
} else { } else {
gClient.listTabs(openToolbox); gClient.listTabs(openToolbox);

Просмотреть файл

@ -878,7 +878,9 @@ Toolbox.prototype = {
*/ */
focusConsoleInput: function() { focusConsoleInput: function() {
let hud = this.getPanel("webconsole").hud; let hud = this.getPanel("webconsole").hud;
if (hud && hud.jsterm) {
hud.jsterm.inputNode.focus(); hud.jsterm.inputNode.focus();
}
}, },
/** /**
@ -964,7 +966,7 @@ Toolbox.prototype = {
toolName = toolboxStrings("toolbox.defaultTitle"); toolName = toolboxStrings("toolbox.defaultTitle");
} }
let title = toolboxStrings("toolbox.titleTemplate", let title = toolboxStrings("toolbox.titleTemplate",
toolName, this.target.url); toolName, this.target.url || this.target.name);
this._host.setTitle(title); this._host.setTitle(title);
}, },

Просмотреть файл

@ -299,6 +299,9 @@ MarkupView.prototype = {
this.markNodeAsSelected(selection.nodeFront); this.markNodeAsSelected(selection.nodeFront);
} }
done(); done();
}, (e) => {
console.error(e);
done();
}); });
} else { } else {
this.unmarkSelectedNode(); this.unmarkSelectedNode();
@ -863,9 +866,11 @@ MarkupView.prototype = {
let parent = node.parentNode(); let parent = node.parentNode();
if (!container.elt.parentNode) { if (!container.elt.parentNode) {
let parentContainer = this._containers.get(parent); let parentContainer = this._containers.get(parent);
if (parentContainer) {
parentContainer.childrenDirty = true; parentContainer.childrenDirty = true;
this._updateChildren(parentContainer, {expand: node}); this._updateChildren(parentContainer, {expand: node});
} }
}
node = parent; node = parent;
} }

Просмотреть файл

@ -66,10 +66,15 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aOptions={}) {
SideMenuWidget.prototype = { SideMenuWidget.prototype = {
/** /**
* Specifies if groups in this container should be sorted alphabetically. * Specifies if groups in this container should be sorted.
*/ */
sortedGroups: true, 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 * Specifies that the container viewport should be "stuck" to the
* bottom. That is, the container is automatically scrolled down to * bottom. That is, the container is automatically scrolled down to
@ -342,7 +347,7 @@ SideMenuWidget.prototype = {
}); });
this._groupsByName.set(aName, group); this._groupsByName.set(aName, group);
group.insertSelfAt(this.sortedGroups ? group.findExpectedIndexForSelf() : -1); group.insertSelfAt(this.sortedGroups ? group.findExpectedIndexForSelf(this.groupSortPredicate) : -1);
return group; return group;
}, },
@ -484,14 +489,14 @@ SideMenuGroup.prototype = {
* @return number * @return number
* The expected index. * The expected index.
*/ */
findExpectedIndexForSelf: function() { findExpectedIndexForSelf: function(sortPredicate) {
let identifier = this.identifier; let identifier = this.identifier;
let groupsArray = this._orderedGroupElementsArray; let groupsArray = this._orderedGroupElementsArray;
for (let group of groupsArray) { for (let group of groupsArray) {
let name = group.getAttribute("name"); let name = group.getAttribute("name");
if (name > identifier && // Insertion sort at its best :) if (sortPredicate(name, identifier) > 0 && // Insertion sort at its best :)
!name.contains(identifier)) { // Least significat group should be last. !name.contains(identifier)) { // Least significant group should be last.
return groupsArray.indexOf(group); return groupsArray.indexOf(group);
} }
} }

Просмотреть файл

@ -45,7 +45,7 @@ function testMenuFilterButton(aCategory) {
// Turn all the filters off, if they were on. // Turn all the filters off, if they were on.
let menuItem = firstMenuItem; let menuItem = firstMenuItem;
while (menuItem != null) { while (menuItem != null) {
if (isChecked(menuItem)) { if (menuItem.hasAttribute("prefKey") && isChecked(menuItem)) {
chooseMenuItem(menuItem); chooseMenuItem(menuItem);
} }
menuItem = menuItem.nextSibling; menuItem = menuItem.nextSibling;
@ -89,10 +89,12 @@ function testMenuFilterButton(aCategory) {
menuItem = firstMenuItem; menuItem = firstMenuItem;
while (menuItem) { while (menuItem) {
let prefKey = menuItem.getAttribute("prefKey"); let prefKey = menuItem.getAttribute("prefKey");
if (prefKey) {
ok(!isChecked(menuItem), "menu item " + prefKey + " for category " + ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
aCategory + " is no longer checked after clicking the button"); aCategory + " is no longer checked after clicking the button");
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " + ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"off after clicking the button"); "off after clicking the button");
}
menuItem = menuItem.nextSibling; menuItem = menuItem.nextSibling;
} }
@ -127,7 +129,8 @@ function testMenuFilterButton(aCategory) {
while (menuItem) { while (menuItem) {
// The csslog menu item is already unchecked at this point. // The csslog menu item is already unchecked at this point.
// Make sure it is not selected. See bug 971798. // Make sure it is not selected. See bug 971798.
if (menuItem.getAttribute("prefKey") != "csslog") { prefKey = menuItem.getAttribute("prefKey");
if (prefKey && prefKey != "csslog") {
chooseMenuItem(menuItem); chooseMenuItem(menuItem);
} }
menuItem = menuItem.nextSibling; menuItem = menuItem.nextSibling;
@ -164,7 +167,7 @@ function testIsolateFilterButton(aCategory) {
aCategory + " should not be checked after isolating for " + aCategory); aCategory + " should not be checked after isolating for " + aCategory);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages should be " + ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages should be " +
"turned off after isolating for " + aCategory); "turned off after isolating for " + aCategory);
} else { } else if (prefKey) {
ok(isChecked(item), "menu item " + prefKey + " for category " + ok(isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is checked after isolating for " + aCategory); aCategory + " is checked after isolating for " + aCategory);
ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " + ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
@ -184,10 +187,12 @@ function testIsolateFilterButton(aCategory) {
menuItems = filterButton.querySelectorAll("menuitem"); menuItems = filterButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => { Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey"); let prefKey = item.getAttribute("prefKey");
if (prefKey) {
ok(!isChecked(item), "menu item " + prefKey + " for category " + ok(!isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is unchecked after isolating for " + aCategory); aCategory + " is unchecked after isolating for " + aCategory);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " + ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned off after isolating for " + aCategory); "turned off after isolating for " + aCategory);
}
}); });
// Turn all the filters on again by clicking the button. // Turn all the filters on again by clicking the button.

Просмотреть файл

@ -53,6 +53,7 @@ function runSelectionTests(aInspector) {
inspector.toolbox.once("picker-started", () => { inspector.toolbox.once("picker-started", () => {
info("Picker mode started, now clicking on H1 to select that node"); info("Picker mode started, now clicking on H1 to select that node");
executeSoon(() => { executeSoon(() => {
h1.scrollIntoView();
EventUtils.synthesizeMouseAtCenter(h1, {}, content); EventUtils.synthesizeMouseAtCenter(h1, {}, content);
inspector.toolbox.once("picker-stopped", () => { inspector.toolbox.once("picker-stopped", () => {
info("Picker mode stopped, H1 selected, now switching to the console"); info("Picker mode stopped, H1 selected, now switching to the console");

Просмотреть файл

@ -401,6 +401,11 @@ WebConsoleFrame.prototype = {
*/ */
setSaveRequestAndResponseBodies: setSaveRequestAndResponseBodies:
function WCF_setSaveRequestAndResponseBodies(aValue) { function WCF_setSaveRequestAndResponseBodies(aValue) {
if (!this.webConsoleClient) {
// Don't continue if the webconsole disconnected.
return promise.resolve(null);
}
let deferred = promise.defer(); let deferred = promise.defer();
let newValue = !!aValue; let newValue = !!aValue;
let toSet = { let toSet = {

Просмотреть файл

@ -104,7 +104,7 @@ function configureLogging() {
gLogger = Log.repository.getLogger("Browser.Experiments"); gLogger = Log.repository.getLogger("Browser.Experiments");
gLogger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); 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); let logDumping = gPrefs.get(PREF_LOGGING_DUMP, false);
if (logDumping != gLogDumping) { if (logDumping != gLogDumping) {
@ -226,6 +226,11 @@ Experiments.Policy.prototype = {
return UpdateChannel.get(); 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. * @return Promise<> Resolved with the payload data.
*/ */
@ -304,8 +309,10 @@ Experiments.Experiments.prototype = {
AddonManager.addAddonListener(this); 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._loadTask = null;
this._run(); this._run();
}, },
@ -386,7 +393,7 @@ Experiments.Experiments.prototype = {
}, },
_telemetryStatusChanged: function () { _telemetryStatusChanged: function () {
_toggleExperimentsEnabled(gExperimentsEnabled); this._toggleExperimentsEnabled(gExperimentsEnabled);
}, },
/** /**
@ -473,10 +480,16 @@ Experiments.Experiments.prototype = {
}, },
_run: function() { _run: function() {
gLogger.trace("Experiments::_run");
this._checkForShutdown(); this._checkForShutdown();
if (!this._mainTask) { if (!this._mainTask) {
this._mainTask = Task.spawn(this._main.bind(this)).then( this._mainTask = Task.spawn(this._main.bind(this));
null, this._mainTask.then(
() => {
gLogger.trace("Experiments::_main finished, scheduling next run");
this._mainTask = null;
this._scheduleNextRun();
},
(e) => { (e) => {
gLogger.error("Experiments::_main caught error: " + e); gLogger.error("Experiments::_main caught error: " + e);
this._mainTask = null; this._mainTask = null;
@ -488,6 +501,7 @@ Experiments.Experiments.prototype = {
_main: function*() { _main: function*() {
do { do {
gLogger.trace("Experiments::_main iteration");
yield this._loadTask; yield this._loadTask;
if (this._refresh) { if (this._refresh) {
yield this._loadManifest(); yield this._loadManifest();
@ -500,11 +514,10 @@ Experiments.Experiments.prototype = {
// while we were running, go again right now. // while we were running, go again right now.
} }
while (this._refresh || this._terminateReason); while (this._refresh || this._terminateReason);
this._mainTask = null;
this._scheduleNextRun();
}, },
_loadManifest: function*() { _loadManifest: function*() {
gLogger.trace("Experiments::_loadManifest");
let uri = Services.urlFormatter.formatURLPref(PREF_BRANCH + PREF_MANIFEST_URI); let uri = Services.urlFormatter.formatURLPref(PREF_BRANCH + PREF_MANIFEST_URI);
this._checkForShutdown(); this._checkForShutdown();
@ -652,6 +665,7 @@ Experiments.Experiments.prototype = {
* Part of the main task to save the cache to disk, called from _main. * Part of the main task to save the cache to disk, called from _main.
*/ */
_saveToCache: function* () { _saveToCache: function* () {
gLogger.trace("Experiments::_saveToCache");
let path = this._cacheFilePath; let path = this._cacheFilePath;
let textData = JSON.stringify({ let textData = JSON.stringify({
version: CACHE_VERSION, version: CACHE_VERSION,
@ -670,6 +684,7 @@ Experiments.Experiments.prototype = {
* Task function, load the cached experiments manifest file from disk. * Task function, load the cached experiments manifest file from disk.
*/ */
_loadFromCache: function*() { _loadFromCache: function*() {
gLogger.trace("Experiments::_loadFromCache");
let path = this._cacheFilePath; let path = this._cacheFilePath;
try { try {
let result = yield loadJSONAsync(path, { compression: "lz4" }); let result = yield loadJSONAsync(path, { compression: "lz4" });
@ -706,7 +721,7 @@ Experiments.Experiments.prototype = {
* array in the manifest * array in the manifest
*/ */
_updateExperiments: function (manifestObject) { _updateExperiments: function (manifestObject) {
gLogger.trace("Experiments::updateExperiments() - experiments: " + JSON.stringify(manifestObject)); gLogger.trace("Experiments::_updateExperiments() - experiments: " + JSON.stringify(manifestObject));
if (manifestObject.version !== MANIFEST_VERSION) { if (manifestObject.version !== MANIFEST_VERSION) {
gLogger.warning("Experiments::updateExperiments() - unsupported version " + manifestObject.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 app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
let runtime = Cc["@mozilla.org/xre/app-info;1"] let runtime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULRuntime); .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 channel = this._policy.updatechannel();
let data = this._manifestData; let data = this._manifestData;
@ -1161,6 +1175,7 @@ Experiments.ExperimentEntry.prototype = {
let startSec = (this.startDate || 0) / 1000; let startSec = (this.startDate || 0) / 1000;
gLogger.trace("ExperimentEntry::isApplicable() - now=" + now gLogger.trace("ExperimentEntry::isApplicable() - now=" + now
+ ", randomValue=" + this._randomValue
+ ", data=" + JSON.stringify(this._manifestData)); + ", data=" + JSON.stringify(this._manifestData));
// Not applicable if it already ran. // Not applicable if it already ran.
@ -1183,11 +1198,11 @@ Experiments.ExperimentEntry.prototype = {
{ name: "endTime", { name: "endTime",
condition: () => now < data.endTime }, condition: () => now < data.endTime },
{ name: "maxStartTime", { name: "maxStartTime",
condition: () => !data.maxStartTime || now <= (data.maxStartTime - minActive) }, condition: () => !data.maxStartTime || now <= data.maxStartTime },
{ name: "maxActiveSeconds", { name: "maxActiveSeconds",
condition: () => !this._startDate || now <= (startSec + maxActive) }, condition: () => !this._startDate || now <= (startSec + maxActive) },
{ name: "appName", { name: "appName",
condition: () => !data.name || data.appName.indexOf(app.name) != -1 }, condition: () => !data.appName || data.appName.indexOf(app.name) != -1 },
{ name: "minBuildID", { name: "minBuildID",
condition: () => !data.minBuildID || app.platformBuildID >= data.minBuildID }, condition: () => !data.minBuildID || app.platformBuildID >= data.minBuildID },
{ name: "maxBuildID", { name: "maxBuildID",
@ -1201,9 +1216,9 @@ Experiments.ExperimentEntry.prototype = {
{ name: "locale", { name: "locale",
condition: () => !data.locale || data.locale.indexOf(locale) != -1 }, condition: () => !data.locale || data.locale.indexOf(locale) != -1 },
{ name: "sample", { name: "sample",
condition: () => !data.sample || this._randomValue <= data.sample }, condition: () => data.sample === undefined || this._randomValue <= data.sample },
{ name: "version", { name: "version",
condition: () => !data.version || data.appVersion.indexOf(app.version) != -1 }, condition: () => !data.version || data.version.indexOf(app.version) != -1 },
{ name: "minVersion", { name: "minVersion",
condition: () => !data.minVersion || versionCmp.compare(app.version, data.minVersion) >= 0 }, condition: () => !data.minVersion || versionCmp.compare(app.version, data.minVersion) >= 0 },
{ name: "maxVersion", { 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 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 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 EXPERIMENT3_ID = "test-experiment-3@tests.mozilla.org";
const EXPERIMENT4_ID = "test-experiment-4@tests.mozilla.org"; const EXPERIMENT4_ID = "test-experiment-4@tests.mozilla.org";
const DEFAULT_BUILDID = "2014060601";
const FAKE_EXPERIMENTS_1 = [ const FAKE_EXPERIMENTS_1 = [
{ {
id: "id1", id: "id1",
@ -169,7 +171,7 @@ function createAppInfo(options) {
let platformVersion = options.platformVersion || "1.0"; let platformVersion = options.platformVersion || "1.0";
let date = options.date || new Date(); let date = options.date || new Date();
let buildID = "" + date.getYear() + date.getMonth() + date.getDate() + "01"; let buildID = options.buildID || DEFAULT_BUILDID;
gAppInfo = { gAppInfo = {
// nsIXULAppInfo // nsIXULAppInfo

Просмотреть файл

@ -63,6 +63,7 @@ add_task(function* test_setup() {
gReporter = yield getReporter("json_payload_simple"); gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements(); yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true); let payload = yield gReporter.getJSONPayload(true);
do_register_cleanup(() => gReporter._shutdown());
patchPolicy(gPolicy, { patchPolicy(gPolicy, {
updatechannel: () => "nightly", updatechannel: () => "nightly",
@ -131,8 +132,3 @@ add_task(function* test_startStop() {
Assert.equal(maybeStop, true, "Experiment should have been stopped."); Assert.equal(maybeStop, true, "Experiment should have been stopped.");
Assert.equal(experiment.enabled, false, "Experiment should be disabled."); 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"); gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements(); yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true); let payload = yield gReporter.getJSONPayload(true);
do_register_cleanup(() => gReporter._shutdown());
gPolicy = new Experiments.Policy(); gPolicy = new Experiments.Policy();
patchPolicy(gPolicy, { patchPolicy(gPolicy, {
@ -1278,9 +1279,3 @@ add_task(function* test_unexpectedUninstall() {
yield experiments.uninit(); yield experiments.uninit();
yield removeCacheFile(); 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"); gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements(); yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true); let payload = yield gReporter.getJSONPayload(true);
do_register_cleanup(() => gReporter._shutdown());
gPolicy = new Experiments.Policy(); gPolicy = new Experiments.Policy();
patchPolicy(gPolicy, { patchPolicy(gPolicy, {
@ -264,8 +265,3 @@ add_task(function* test_cache() {
yield experiments.uninit(); yield experiments.uninit();
yield removeCacheFile(); 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"); gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements(); yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true); let payload = yield gReporter.getJSONPayload(true);
do_register_cleanup(() => gReporter._shutdown());
patchPolicy(gPolicy, { patchPolicy(gPolicy, {
updatechannel: () => "nightly", updatechannel: () => "nightly",
locale: () => "en-US",
healthReportPayload: () => Promise.resolve(payload), healthReportPayload: () => Promise.resolve(payload),
random: () => 0.5,
}); });
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
@ -108,10 +111,81 @@ const sanityFilter = function filter(c) {
add_task(function* test_simpleFields() { add_task(function* test_simpleFields() {
let testData = [ let testData = [
// "expected applicable?", failure reason or null, manifest data // "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"]}], [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"]}], [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; }"}], [true, null, {jsfilter: "function filter(c) { return true; }"}],
[false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}], [false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}],
[true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy [true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy
@ -150,18 +224,73 @@ add_task(function* test_simpleFields() {
}); });
add_task(function* test_times() { add_task(function* test_times() {
let baseDate = new Date(2014, 5, 6, 12); let now = new Date(2014, 5, 6, 12);
let baseTimeSec = baseDate.getTime() / 1000; let nowSec = now.getTime() / 1000;
let testData = [ let testData = [
// "expected applicable?", rejection reason or null, fake now date, manifest data // "expected applicable?", rejection reason or null, fake now date, manifest data
[false, "maxStartTime", baseDate,
{maxStartTime: baseTimeSec - 10 * SEC_IN_ONE_DAY}], // start time
[false, "endTime", baseDate,
{startTime: baseTimeSec - 10 * SEC_IN_ONE_DAY, [true, null, now,
endTime: baseTimeSec - 5 * SEC_IN_ONE_DAY}], {startTime: nowSec - 5 * SEC_IN_ONE_DAY,
[true, null, baseDate, endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
{startTime: baseTimeSec - 5 * SEC_IN_ONE_DAY, [true, null, now,
endTime: baseTimeSec + 10 * SEC_IN_ONE_DAY}], {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) { 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(); yield ex.uninit();
}); });
add_task(function* shutdown() {
yield removeCacheFile();
});

Просмотреть файл

@ -114,6 +114,7 @@ add_task(function* test_setup() {
gReporter = yield getReporter("json_payload_simple"); gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements(); yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true); let payload = yield gReporter.getJSONPayload(true);
do_register_cleanup(() => gReporter._shutdown());
gPolicy = new Experiments.Policy(); gPolicy = new Experiments.Policy();
let dummyTimer = { cancel: () => {}, clear: () => {} }; let dummyTimer = { cancel: () => {}, clear: () => {} };
@ -353,8 +354,3 @@ add_task(function* test_telemetryBasics() {
yield experiments.uninit(); yield experiments.uninit();
yield removeCacheFile(); yield removeCacheFile();
}); });
add_task(function* shutdown() {
yield gReporter._shutdown();
yield removeCacheFile();
});

Просмотреть файл

@ -16,7 +16,7 @@
%define forwardTransitionLength 150ms %define forwardTransitionLength 150ms
%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container %define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
%define conditionalForwardWithUrlbarWidth 40 %define conditionalForwardWithUrlbarWidth 30
#menubar-items { #menubar-items {
-moz-box-orient: vertical; /* for flex hack */ -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-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-moz-margin-start: -4px; -moz-margin-start: -4px;
margin-top: 3px;
margin-bottom: 3px;
} }
#forward-button[disabled] { #back-button {
transform: scale(0); padding-top: 3px;
opacity: 0; padding-bottom: 3px;
pointer-events: none; -moz-padding-start: 5px;
-moz-padding-end: 0;
position: relative;
z-index: 1;
border-radius: 0 10000px 10000px 0;
} }
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button { #back-button:-moz-locale-dir(rtl) {
transition: @forwardTransitionLength@ ease-out; 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, #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); 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 */ /* tabview menu item */
#menu_tabview { #menu_tabview {
@ -801,9 +876,21 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
} }
/* Location bar */ /* 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 { #urlbar {
-moz-appearance: textfield; background-color: -moz-field;
padding: 0;
} }
.urlbar-textbox-container { .urlbar-textbox-container {
@ -825,26 +912,59 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
} }
@conditionalForwardWithUrlbar@ > #urlbar-wrapper { @conditionalForwardWithUrlbar@ > #urlbar-wrapper {
-moz-padding-start: @conditionalForwardWithUrlbarWidth@px; padding-left: @conditionalForwardWithUrlbarWidth@px;
-moz-margin-start: -@conditionalForwardWithUrlbarWidth@px; -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
position: relative; position: relative;
pointer-events: none; pointer-events: none;
} }
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar { @conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
-moz-border-start: none;
margin-left: 0;
pointer-events: all; pointer-events: all;
} }
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar { @conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
transition: margin-left @forwardTransitionLength@ ease-out, transition: margin-left @forwardTransitionLength@ ease-out;
margin-right @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; 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 { #urlbar-icons {
@ -884,41 +1004,66 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
min-width: calc(54px + 11ch); 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 { #identity-box {
padding: 1px; padding: 1px;
margin: -1px;
-moz-margin-end: 0;
font-size: .9em; font-size: .9em;
} }
#identity-box:-moz-locale-dir(ltr) { #identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 2.5px; border-top-left-radius: 1.5px;
border-bottom-left-radius: 2.5px; border-bottom-left-radius: 1.5px;
} }
#identity-box:-moz-locale-dir(rtl) { #identity-box:-moz-locale-dir(rtl) {
border-top-right-radius: 2.5px; border-top-right-radius: 1.5px;
border-bottom-right-radius: 2.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 { #identity-box:-moz-focusring {
@ -931,10 +1076,27 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-padding-end: 5px; -moz-padding-end: 5px;
} }
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI, %include ../shared/identity-block.inc.css
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
background-color: #fff; #page-proxy-favicon {
-moz-margin-end: 4px; 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 */ /* Identity popup icons */

Просмотреть файл

@ -105,6 +105,7 @@ browser.jar:
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.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/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (newtab/controls.png) skin/classic/browser/newtab/controls.png (newtab/controls.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png) skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
@ -134,6 +135,12 @@ browser.jar:
#endif #endif
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css) * 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/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/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/social/services-16.png (social/services-16.png) skin/classic/browser/social/services-16.png (social/services-16.png)

Двоичные данные
browser/themes/linux/preferences/in-content/check.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 593 B

Двоичные данные
browser/themes/linux/preferences/in-content/dropdown-disabled.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 250 B

Двоичные данные
browser/themes/linux/preferences/in-content/dropdown.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 250 B

Двоичные данные
browser/themes/linux/preferences/in-content/header.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 11 KiB

Двоичные данные
browser/themes/linux/preferences/in-content/icons.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Просмотреть файл

@ -2,174 +2,89 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this file, - 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/. */ - 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"; button > .button-box,
menulist > .menulist-label-box {
#header {
margin-bottom: 18px;
}
caption {
font-size: 1.667rem;
}
.main-content {
max-width: 800px;
}
prefpane > .content-box {
overflow: auto;
}
/* Category List */
#categories {
-moz-appearance: none; -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; -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) { radio:hover::before,
border-top-left-radius: 5px; radio[selected]::before {
border-bottom-left-radius: 5px; max-height: 11px;
} margin-top: 6px;
margin-bottom: 6px;
.category:-moz-locale-dir(rtl) { -moz-margin-end: -17px;
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;
-moz-margin-start: 6px; -moz-margin-start: 6px;
-moz-margin-end: 5px;
list-style-image: url("chrome://browser/skin/preferences/Options.png");
} }
#category-general > .category-icon { .numberbox-input-box {
-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; -moz-appearance: none;
border: 1px solid ThreeDShadow; border-width: 0;
overflow-y: auto;
} }
/* XXX This style is for bug 740213 and should be removed once that spinbuttons {
bug has a solution. */ -moz-appearance: none;
description > html|a {
cursor: pointer;
} }
/* XXX Styles Below can be removed once bug 660726 lands */ .actionsMenu {
.nav-button { font-family: "Clear Sans", sans-serif;
min-width: 0; font-size: 1.25rem;
line-height: 22px;
} }
#back-btn:-moz-locale-dir(ltr) { .actionsMenu > .menulist-label-box > .menulist-icon {
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar"); margin-top: 1px;
-moz-margin-start: 1px;
-moz-margin-end: 6px;
} }
#forward-btn:-moz-locale-dir(ltr) { .actionsMenu > .menulist-label-box > .menulist-label {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar"); margin-top: 2px !important;
} }
#back-btn:-moz-locale-dir(rtl) { menulist.actionsMenu > .menulist-dropmarker {
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar"); margin-top: 11px;
} margin-bottom: 11px;
#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;
} }

Двоичные данные
browser/themes/linux/preferences/in-content/sorter.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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: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]: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"]: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; 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); border-color: hsla(0,0%,0%,.3);
box-shadow: 0 1px 0 hsla(0,0%,100%,.5), 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/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.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/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (newtab/controls.png) skin/classic/browser/newtab/controls.png (newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (newtab/controls@2x.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/saveFile.png (preferences/saveFile.png)
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css) * 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/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/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/social/services-16.png (social/services-16.png) skin/classic/browser/social/services-16.png (social/services-16.png)

Двоичные данные
browser/themes/osx/preferences/in-content/check.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 593 B

Двоичные данные
browser/themes/osx/preferences/in-content/check@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
browser/themes/osx/preferences/in-content/dropdown-disabled.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 250 B

Двоичные данные
browser/themes/osx/preferences/in-content/dropdown.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 250 B

Двоичные данные
browser/themes/osx/preferences/in-content/icons.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
browser/themes/osx/preferences/in-content/icons@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 30 KiB

Просмотреть файл

@ -2,182 +2,134 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this file, - 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/. */ - 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"); menulist:not([editable="true"]) > .menulist-dropmarker {
display: -moz-box;
@namespace html "http://www.w3.org/1999/xhtml"; margin-top: 1px;
margin-bottom: 1px;
#header {
margin-bottom: 18px;
} }
caption { checkbox:hover::before,
font-size: 1.667rem; checkbox[checked]::before {
margin-bottom: -2px;
-moz-margin-end: -20px;
-moz-margin-start: 5px;
} }
.main-content { radio:hover::before,
max-width: 800px; radio[selected]::before {
-moz-margin-end: -18px;
-moz-margin-start: 7px;
} }
prefpane > .content-box { .numberbox-input-box {
overflow: auto;
}
/* Category List */
#categories {
-moz-appearance: none; -moz-appearance: none;
border: none; border-width: 0;
-moz-margin-end: -1px;
background-color: transparent;
position: relative;
margin-top: 31px;
} }
.category { spinbuttons {
-moz-appearance: none; -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) { .spinbuttons-up {
border-top-left-radius: 5px; margin-top: 0 !important;
border-bottom-left-radius: 5px; border-radius: 4px 4px 0 0;
} }
.category:-moz-locale-dir(rtl) { .spinbuttons-down {
border-top-right-radius: 5px; margin-bottom: 0 !important;
border-bottom-right-radius: 5px; border-radius: 0 0 4px 4px;
} }
.category[selected] { .spinbuttons-button > .button-box {
background-color: rgba(255, 255, 255, 0.35); -moz-padding-start: 2px !important;
color: -moz-dialogtext; -moz-padding-end: 3px !important;
border-color: rgba(50, 65, 92, 0.4);
-moz-border-end-color: #C9CFD7;
} }
.category-name { .spinbuttons-button > .button-box > .button-text {
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; display: none;
} }
.actionsMenu > .menulist-label-box > .menulist-icon {
margin-top: 2px;
-moz-margin-start: 2px;
-moz-margin-end: 8px !important;
}
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 { .category-icon {
width: 32px; list-style-image: url("chrome://browser/skin/preferences/in-content/icons@2x.png");
height: 32px;
-moz-margin-start: 6px;
list-style-image: url("chrome://browser/skin/preferences/Options.png");
} }
#category-general > .category-icon { #category-general > .category-icon {
-moz-image-region: rect(0, 32px, 32px, 0); -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 { #category-content > .category-icon {
-moz-image-region: rect(0, 96px, 32px, 64px) -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 { #category-application > .category-icon {
-moz-image-region: rect(0, 128px, 32px, 96px) -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 { #category-privacy > .category-icon {
-moz-image-region: rect(0, 160px, 32px, 128px) -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 { #category-security > .category-icon {
-moz-image-region: rect(0, 192px, 32px, 160px) -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 { #category-advanced > .category-icon {
-moz-image-region: rect(0, 224px, 32px, 192px) -moz-image-region: rect(0, 336px, 48px, 288px);
} }
%ifdef MOZ_SERVICES_SYNC #category-advanced[selected] > .category-icon {
#category-sync > .category-icon { -moz-image-region: rect(48px, 336px, 96px, 288px);
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 {
display: none;
}
.header-button[disabled="true"] .toolbarbutton-icon {
opacity: 0.4;
}
.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));
} }

Двоичные данные
browser/themes/osx/preferences/in-content/sorter.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 154 B

Двоичные данные
browser/themes/shared/ClearSans-Regular.ttf Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -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-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text { .panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
-moz-hyphens: auto;
line-height: 1.1; line-height: 1.1;
max-height: 2.2em; 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-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid:not([customize-transitioning]) .toolbarbutton-1 > .toolbarbutton-multiline-text { .panelUI-grid:not([customize-transitioning]) .toolbarbutton-1 > .toolbarbutton-multiline-text {
position: absolute; 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); 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, box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
0 0 1px hsla(210,54%,20%,.2) 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 1px 0 hsla(210,54%,20%,0),
0 0 2px hsla(210,54%,20%,0); 0 0 2px hsla(210,54%,20%,0);
text-shadow: none; text-shadow: none;
@ -853,7 +853,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
#forward-button > .toolbarbutton-icon { #forward-button > .toolbarbutton-icon {
background-clip: padding-box !important; background-clip: padding-box !important;
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */ /*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; margin-left: -6px !important;
border-left-style: none !important; border-left-style: none !important;
border-radius: 0 !important; border-radius: 0 !important;
@ -1156,7 +1156,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
} }
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper { @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 { @conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {

Просмотреть файл

@ -126,6 +126,7 @@ browser.jar:
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.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/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (newtab/controls.png) skin/classic/browser/newtab/controls.png (newtab/controls.png)
skin/classic/browser/places/places.css (places/places.css) 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/saveFile.png (preferences/saveFile.png)
* skin/classic/browser/preferences/preferences.css (preferences/preferences.css) * 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/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/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/social/services-16.png (social/services-16.png) 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/videoFeedIcon16.png (feeds/feedIcon16-aero.png)
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css) 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/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/newTab.css (newtab/newTab.css)
skin/classic/aero/browser/newtab/controls.png (newtab/controls.png) skin/classic/aero/browser/newtab/controls.png (newtab/controls.png)
* skin/classic/aero/browser/places/places.css (places/places-aero.css) * 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/saveFile.png (preferences/saveFile-aero.png)
* skin/classic/aero/browser/preferences/preferences.css (preferences/preferences.css) * 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/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/applications.css (preferences/applications.css)
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/aero/browser/social/services-16.png (social/services-16.png) skin/classic/aero/browser/social/services-16.png (social/services-16.png)

Двоичные данные
browser/themes/windows/preferences/in-content/check.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 593 B

Двоичные данные
browser/themes/windows/preferences/in-content/check@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше