mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
a98c31f1a8
25
addon-sdk/source/lib/framescript/FrameScriptManager.jsm
Normal file
25
addon-sdk/source/lib/framescript/FrameScriptManager.jsm
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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 globalMM = Components.classes["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Components.interfaces.nsIMessageListenerManager);
|
||||
|
||||
// Load frame scripts from the same dir as this module.
|
||||
// Since this JSM will be loaded using require(), PATH will be
|
||||
// overridden while running tests, just like any other module.
|
||||
const PATH = __URI__.replace('FrameScriptManager.jsm', '');
|
||||
|
||||
// ensure frame scripts are loaded only once
|
||||
let loadedTabEvents = false;
|
||||
|
||||
function enableTabEvents() {
|
||||
if (loadedTabEvents)
|
||||
return;
|
||||
|
||||
loadedTabEvents = true;
|
||||
globalMM.loadFrameScript(PATH + 'tab-events.js', true);
|
||||
}
|
||||
|
||||
const EXPORTED_SYMBOLS = ['enableTabEvents'];
|
44
addon-sdk/source/lib/framescript/tab-events.js
Normal file
44
addon-sdk/source/lib/framescript/tab-events.js
Normal file
@ -0,0 +1,44 @@
|
||||
/* 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";
|
||||
|
||||
// bug 673569 - let each frame script have its own anonymous scope
|
||||
(function() {
|
||||
|
||||
const observerSvc = Components.classes["@mozilla.org/observer-service;1"].
|
||||
getService(Components.interfaces.nsIObserverService);
|
||||
|
||||
// map observer topics to tab event names
|
||||
const EVENTS = {
|
||||
'content-document-interactive': 'ready',
|
||||
'chrome-document-interactive': 'ready',
|
||||
'content-document-loaded': 'load',
|
||||
'chrome-document-loaded': 'load',
|
||||
// 'content-page-shown': 'pageshow', // bug 1024105
|
||||
}
|
||||
|
||||
let listener = {
|
||||
observe: function(subject, topic) {
|
||||
// observer service keeps a strong reference to the listener, and this
|
||||
// method can get called after the tab is closed, so we should remove it.
|
||||
if (!docShell) {
|
||||
observerSvc.removeObserver(this, topic);
|
||||
}
|
||||
else {
|
||||
if (subject === content.document)
|
||||
sendAsyncMessage('sdk/tab/event', { type: EVENTS[topic] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(EVENTS).forEach( (topic) =>
|
||||
observerSvc.addObserver(listener, topic, false));
|
||||
|
||||
// bug 1024105 - content-page-shown notification doesn't pass persisted param
|
||||
docShell.chromeEventHandler.addEventListener('pageshow', (e) => {
|
||||
if (e.target === content.document)
|
||||
sendAsyncMessage('sdk/tab/event', { type: e.type, persisted: e.persisted });
|
||||
}, true);
|
||||
|
||||
})();
|
@ -199,6 +199,7 @@ destroy.define(Worker, function (worker, reason) {
|
||||
// Specifying no type or listener removes all listeners
|
||||
// from target
|
||||
off(worker);
|
||||
off(worker.port);
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -10,8 +10,9 @@ module.metadata = {
|
||||
|
||||
const { Cc, Ci, Cr } = require("chrome");
|
||||
const { emit, on, off } = require("./core");
|
||||
const { addObserver } = Cc['@mozilla.org/observer-service;1'].
|
||||
const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
const { when: unload } = require("../system/unload");
|
||||
|
||||
// Simple class that can be used to instantiate event channel that
|
||||
// implements `nsIObserver` interface. It's will is used by `observe`
|
||||
@ -48,6 +49,11 @@ function observe(topic) {
|
||||
// will be held.
|
||||
addObserver(observerChannel, topic, true);
|
||||
|
||||
// We need to remove any observer added once the add-on is unloaded;
|
||||
// otherwise we'll get a "dead object" exception.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
|
||||
unload(() => removeObserver(observerChannel, topic));
|
||||
|
||||
return observerChannel;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,21 @@ module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { Ci } = require("chrome");
|
||||
|
||||
let { emit } = require("./core");
|
||||
let { when: unload } = require("../system/unload");
|
||||
let listeners = new Map();
|
||||
|
||||
let getWindowFrom = x =>
|
||||
x instanceof Ci.nsIDOMWindow ? x :
|
||||
x instanceof Ci.nsIDOMDocument ? x.defaultView :
|
||||
x instanceof Ci.nsIDOMNode ? x.ownerDocument.defaultView :
|
||||
null;
|
||||
|
||||
function removeFromListeners() {
|
||||
listeners.delete(this);
|
||||
}
|
||||
|
||||
// Simple utility function takes event target, event type and optional
|
||||
// `options.capture` and returns node style event stream that emits "data"
|
||||
@ -16,11 +30,41 @@ let { emit } = require("./core");
|
||||
function open(target, type, options) {
|
||||
let output = {};
|
||||
let capture = options && options.capture ? true : false;
|
||||
let listener = (event) => emit(output, "data", event);
|
||||
|
||||
target.addEventListener(type, function(event) {
|
||||
emit(output, "data", event);
|
||||
}, capture);
|
||||
// `open` is currently used only on DOM Window objects, however it was made
|
||||
// to be used to any kind of `target` that supports `addEventListener`,
|
||||
// therefore is safer get the `window` from the `target` instead assuming
|
||||
// that `target` is the `window`.
|
||||
let window = getWindowFrom(target);
|
||||
|
||||
// If we're not able to get a `window` from `target`, there is something
|
||||
// wrong. We cannot add listeners that can leak later, or results in
|
||||
// "dead object" exception.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833
|
||||
if (!window)
|
||||
throw new Error("Unable to obtain the owner window from the target given.");
|
||||
|
||||
let cleaners = listeners.get(window) || [];
|
||||
cleaners.push(() => target.removeEventListener(type, listener, capture));
|
||||
|
||||
listeners.set(window, cleaners);
|
||||
|
||||
// We need to remove from our map the `window` once is closed, to prevent
|
||||
// memory leak
|
||||
window.addEventListener("DOMWindowClose", removeFromListeners);
|
||||
|
||||
target.addEventListener(type, listener, capture);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
unload(() => {
|
||||
for (let [window, cleaners] of listeners) {
|
||||
cleaners.forEach(callback => callback())
|
||||
}
|
||||
|
||||
listeners.clear();
|
||||
});
|
||||
|
||||
exports.open = open;
|
||||
|
@ -17,6 +17,7 @@ function Options(options) {
|
||||
},
|
||||
isPinned: { is: ["undefined", "boolean"] },
|
||||
isPrivate: { is: ["undefined", "boolean"] },
|
||||
inNewWindow: { is: ["undefined", "boolean"] },
|
||||
onOpen: { is: ["undefined", "function"] },
|
||||
onClose: { is: ["undefined", "function"] },
|
||||
onReady: { is: ["undefined", "function"] },
|
||||
|
@ -21,6 +21,10 @@ const { getURL } = require('../url/utils');
|
||||
const { viewFor } = require('../view/core');
|
||||
const { observer } = require('./observer');
|
||||
|
||||
// cfx doesn't know require() now handles JSM modules
|
||||
const FRAMESCRIPT_MANAGER = '../../framescript/FrameScriptManager.jsm';
|
||||
require(FRAMESCRIPT_MANAGER).enableTabEvents();
|
||||
|
||||
// Array of the inner instances of all the wrapped tabs.
|
||||
const TABS = [];
|
||||
|
||||
@ -39,9 +43,6 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
*/
|
||||
window: null,
|
||||
constructor: function Tab(options) {
|
||||
this._onReady = this._onReady.bind(this);
|
||||
this._onLoad = this._onLoad.bind(this);
|
||||
this._onPageShow = this._onPageShow.bind(this);
|
||||
this._tab = options.tab;
|
||||
// TODO: Remove this dependency
|
||||
let window = this.window = options.window || require('../windows').BrowserWindow({ window: getOwnerWindow(this._tab) });
|
||||
@ -59,9 +60,12 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
|
||||
this.on(EVENTS.close.name, this.destroy.bind(this));
|
||||
|
||||
this._browser.addEventListener(EVENTS.ready.dom, this._onReady, true);
|
||||
this._browser.addEventListener(EVENTS.load.dom, this._onLoad, true);
|
||||
this._browser.addEventListener(EVENTS.pageshow.dom, this._onPageShow, true);
|
||||
this._onContentEvent = this._onContentEvent.bind(this);
|
||||
this._browser.messageManager.addMessageListener('sdk/tab/event', this._onContentEvent);
|
||||
|
||||
// bug 1024632 - first tab inNewWindow gets events from the synthetic
|
||||
// about:blank document. ignore them unless that is the actual target url.
|
||||
this._skipBlankEvents = options.inNewWindow && options.url !== 'about:blank';
|
||||
|
||||
if (options.isPinned)
|
||||
this.pin();
|
||||
@ -84,9 +88,7 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
let browser = this._browser;
|
||||
// The tab may already be removed from DOM -or- not yet added
|
||||
if (browser) {
|
||||
browser.removeEventListener(EVENTS.ready.dom, this._onReady, true);
|
||||
browser.removeEventListener(EVENTS.load.dom, this._onLoad, true);
|
||||
browser.removeEventListener(EVENTS.pageshow.dom, this._onPageShow, true);
|
||||
browser.messageManager.removeMessageListener('sdk/tab/event', this._onContentEvent);
|
||||
}
|
||||
this._tab = null;
|
||||
TABS.splice(TABS.indexOf(this), 1);
|
||||
@ -94,36 +96,20 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal listener that emits public event 'ready' when the page of this
|
||||
* tab is loaded, from DOMContentLoaded
|
||||
* internal message listener emits public events (ready, load and pageshow)
|
||||
* forwarded from content frame script tab-event.js
|
||||
*/
|
||||
_onReady: function _onReady(event) {
|
||||
// IFrames events will bubble so we need to ignore those.
|
||||
if (event.target == this._contentDocument)
|
||||
this._emit(EVENTS.ready.name, this._public);
|
||||
_onContentEvent: function({ data }) {
|
||||
// bug 1024632 - skip initial events from synthetic about:blank document
|
||||
if (this._skipBlankEvents && this.window.tabs.length === 1 && this.url === 'about:blank')
|
||||
return;
|
||||
|
||||
// first time we don't skip blank events, disable further skipping
|
||||
this._skipBlankEvents = false;
|
||||
|
||||
this._emit(data.type, this._public, data.persisted);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal listener that emits public event 'load' when the page of this
|
||||
* tab is loaded, for triggering on non-HTML content, bug #671305
|
||||
*/
|
||||
_onLoad: function _onLoad(event) {
|
||||
// IFrames events will bubble so we need to ignore those.
|
||||
if (event.target == this._contentDocument) {
|
||||
this._emit(EVENTS.load.name, this._public);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal listener that emits public event 'pageshow' when the page of this
|
||||
* tab is loaded from cache, bug #671305
|
||||
*/
|
||||
_onPageShow: function _onPageShow(event) {
|
||||
// IFrames events will bubble so we need to ignore those.
|
||||
if (event.target == this._contentDocument) {
|
||||
this._emit(EVENTS.pageshow.name, this._public, event.persisted);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Internal tab event router. Window will emit tab related events for all it's
|
||||
* tabs, this listener will propagate all the events for this tab to it's
|
||||
|
@ -33,6 +33,7 @@ const { isLocalURL } = require('../url');
|
||||
const { ensure } = require('../system/unload');
|
||||
const { identify } = require('./id');
|
||||
const { uuid } = require('../util/uuid');
|
||||
const { viewFor } = require('../view/core');
|
||||
|
||||
const sidebarNS = ns();
|
||||
|
||||
@ -239,12 +240,8 @@ const Sidebar = Class({
|
||||
updateURL(this, v);
|
||||
modelFor(this).url = v;
|
||||
},
|
||||
show: function() {
|
||||
return showSidebar(null, this);
|
||||
},
|
||||
hide: function() {
|
||||
return hideSidebar(null, this);
|
||||
},
|
||||
show: function(window) showSidebar(viewFor(window), this),
|
||||
hide: function(window) hideSidebar(viewFor(window), this),
|
||||
dispose: function() {
|
||||
const internals = sidebarNS(this);
|
||||
|
||||
|
@ -70,6 +70,9 @@ const BrowserWindowTrait = Trait.compose(
|
||||
else if ('url' in options) {
|
||||
this._tabOptions = [ Options(options.url) ];
|
||||
}
|
||||
for (let tab of this._tabOptions) {
|
||||
tab.inNewWindow = true;
|
||||
}
|
||||
|
||||
this._isPrivate = isPrivateBrowsingSupported && !!options.isPrivate;
|
||||
|
||||
|
13
addon-sdk/source/test/addons/e10s-tabs/lib/main.js
Normal file
13
addon-sdk/source/test/addons/e10s-tabs/lib/main.js
Normal file
@ -0,0 +1,13 @@
|
||||
/* 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 { merge } = require('sdk/util/object');
|
||||
|
||||
merge(module.exports, require('./test-tab'));
|
||||
merge(module.exports, require('./test-tab-events'));
|
||||
merge(module.exports, require('./test-tab-observer'));
|
||||
merge(module.exports, require('./test-tab-utils'));
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
@ -0,0 +1,100 @@
|
||||
/* 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 { loader } = LoaderWithHookedConsole(module);
|
||||
|
||||
const pb = loader.require('sdk/private-browsing');
|
||||
const pbUtils = loader.require('sdk/private-browsing/utils');
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const { open: openWindow, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { openTab, getTabContentWindow, getActiveTab, setTabURL, closeTab } = require('sdk/tabs/utils');
|
||||
const promise = require("sdk/core/promise");
|
||||
const windowHelpers = require('sdk/window/helpers');
|
||||
const events = require("sdk/system/events");
|
||||
|
||||
function LoaderWithHookedConsole(module) {
|
||||
let globals = {};
|
||||
let errors = [];
|
||||
|
||||
globals.console = Object.create(console, {
|
||||
error: {
|
||||
value: function(e) {
|
||||
errors.push(e);
|
||||
if (!/DEPRECATED:/.test(e)) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let loader = Loader(module, globals);
|
||||
|
||||
return {
|
||||
loader: loader,
|
||||
errors: errors
|
||||
}
|
||||
}
|
||||
|
||||
function deactivate(callback) {
|
||||
if (pbUtils.isGlobalPBSupported) {
|
||||
if (callback)
|
||||
pb.once('stop', callback);
|
||||
pb.deactivate();
|
||||
}
|
||||
}
|
||||
exports.deactivate = deactivate;
|
||||
|
||||
exports.pb = pb;
|
||||
exports.pbUtils = pbUtils;
|
||||
exports.LoaderWithHookedConsole = LoaderWithHookedConsole;
|
||||
|
||||
exports.openWebpage = function openWebpage(url, enablePrivate) {
|
||||
if (xulApp.is("Fennec")) {
|
||||
let chromeWindow = getMostRecentBrowserWindow();
|
||||
let rawTab = openTab(chromeWindow, url, {
|
||||
isPrivate: enablePrivate
|
||||
});
|
||||
|
||||
return {
|
||||
ready: promise.resolve(getTabContentWindow(rawTab)),
|
||||
close: function () {
|
||||
closeTab(rawTab);
|
||||
// Returns a resolved promise as there is no need to wait
|
||||
return promise.resolve();
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
let win = openWindow(null, {
|
||||
features: {
|
||||
private: enablePrivate
|
||||
}
|
||||
});
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Wait for delayed startup code to be executed, in order to ensure
|
||||
// that the window is really ready
|
||||
events.on("browser-delayed-startup-finished", function onReady({subject}) {
|
||||
if (subject == win) {
|
||||
events.off("browser-delayed-startup-finished", onReady);
|
||||
deferred.resolve(win);
|
||||
|
||||
let rawTab = getActiveTab(win);
|
||||
setTabURL(rawTab, url);
|
||||
deferred.resolve(getTabContentWindow(rawTab));
|
||||
}
|
||||
}, true);
|
||||
|
||||
return {
|
||||
ready: deferred.promise,
|
||||
close: function () {
|
||||
return windowHelpers.close(win);
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
238
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-events.js
Normal file
238
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-events.js
Normal file
@ -0,0 +1,238 @@
|
||||
/* 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 utils = require("sdk/tabs/utils");
|
||||
const { open, close } = require("sdk/window/helpers");
|
||||
const { getMostRecentBrowserWindow } = require("sdk/window/utils");
|
||||
const { events } = require("sdk/tab/events");
|
||||
const { on, off } = require("sdk/event/core");
|
||||
const { resolve, defer } = require("sdk/core/promise");
|
||||
|
||||
let isFennec = require("sdk/system/xul-app").is("Fennec");
|
||||
|
||||
function test(options) {
|
||||
return function(assert, done) {
|
||||
let tabEvents = [];
|
||||
let tabs = [];
|
||||
let { promise, resolve: resolveP } = defer();
|
||||
let win = isFennec ? resolve(getMostRecentBrowserWindow()) :
|
||||
open(null, {
|
||||
features: { private: true, toolbar:true, chrome: true }
|
||||
});
|
||||
let window = null;
|
||||
|
||||
// Firefox events are fired sync; Fennec events async
|
||||
// this normalizes the tests
|
||||
function handler (event) {
|
||||
tabEvents.push(event);
|
||||
runIfReady();
|
||||
}
|
||||
|
||||
function runIfReady () {
|
||||
let releventEvents = getRelatedEvents(tabEvents, tabs);
|
||||
if (options.readyWhen(releventEvents))
|
||||
options.end({
|
||||
tabs: tabs,
|
||||
events: releventEvents,
|
||||
assert: assert,
|
||||
done: resolveP
|
||||
});
|
||||
}
|
||||
|
||||
win.then(function(w) {
|
||||
window = w;
|
||||
on(events, "data", handler);
|
||||
options.start({ tabs: tabs, window: window });
|
||||
|
||||
// Execute here for synchronous FF events, as the handlers
|
||||
// were called before tabs were pushed to `tabs`
|
||||
runIfReady();
|
||||
return promise;
|
||||
}).then(function() {
|
||||
off(events, "data", handler);
|
||||
return isFennec ? null : close(window);
|
||||
}).then(done, assert.fail);
|
||||
};
|
||||
}
|
||||
|
||||
// Just making sure that tab events work for already opened tabs not only
|
||||
// for new windows.
|
||||
exports["test current window"] = test({
|
||||
readyWhen: events => events.length === 3,
|
||||
start: ({ tabs, window }) => {
|
||||
let tab = utils.openTab(window, 'data:text/plain,open');
|
||||
tabs.push(tab);
|
||||
utils.closeTab(tab);
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [open, select, close] = events;
|
||||
let tab = tabs[0];
|
||||
|
||||
assert.equal(open.type, "TabOpen");
|
||||
assert.equal(open.target, tab);
|
||||
|
||||
assert.equal(select.type, "TabSelect");
|
||||
assert.equal(select.target, tab);
|
||||
|
||||
assert.equal(close.type, "TabClose");
|
||||
assert.equal(close.target, tab);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
exports["test open"] = test({
|
||||
readyWhen: events => events.length === 2,
|
||||
start: ({ tabs, window }) => {
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,open'));
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [open, select] = events;
|
||||
let tab = tabs[0];
|
||||
|
||||
assert.equal(open.type, "TabOpen");
|
||||
assert.equal(open.target, tab);
|
||||
|
||||
assert.equal(select.type, "TabSelect");
|
||||
assert.equal(select.target, tab);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
exports["test open -> close"] = test({
|
||||
readyWhen: events => events.length === 3,
|
||||
start: ({ tabs, window }) => {
|
||||
// First tab is useless we just open it so that closing second tab won't
|
||||
// close window on some platforms.
|
||||
utils.openTab(window, 'data:text/plain,ignore');
|
||||
let tab = utils.openTab(window, 'data:text/plain,open-close');
|
||||
tabs.push(tab);
|
||||
utils.closeTab(tab);
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [open, select, close] = events;
|
||||
let tab = tabs[0];
|
||||
|
||||
assert.equal(open.type, "TabOpen");
|
||||
assert.equal(open.target, tab);
|
||||
|
||||
assert.equal(select.type, "TabSelect");
|
||||
assert.equal(select.target, tab);
|
||||
|
||||
assert.equal(close.type, "TabClose");
|
||||
assert.equal(close.target, tab);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
exports["test open -> open -> select"] = test({
|
||||
readyWhen: events => events.length === 5,
|
||||
start: ({tabs, window}) => {
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,Tab-1'));
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,Tab-2'));
|
||||
utils.activateTab(tabs[0], window);
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [ tab1, tab2 ] = tabs;
|
||||
let tab1Events = 0;
|
||||
getRelatedEvents(events, tab1).map(event => {
|
||||
tab1Events++;
|
||||
if (tab1Events === 1)
|
||||
assert.equal(event.type, "TabOpen", "first tab opened");
|
||||
else
|
||||
assert.equal(event.type, "TabSelect", "first tab selected");
|
||||
assert.equal(event.target, tab1);
|
||||
});
|
||||
assert.equal(tab1Events, 3, "first tab has 3 events");
|
||||
|
||||
let tab2Opened;
|
||||
getRelatedEvents(events, tab2).map(event => {
|
||||
if (!tab2Opened)
|
||||
assert.equal(event.type, "TabOpen", "second tab opened");
|
||||
else
|
||||
assert.equal(event.type, "TabSelect", "second tab selected");
|
||||
tab2Opened = true;
|
||||
assert.equal(event.target, tab2);
|
||||
});
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
exports["test open -> pin -> unpin"] = test({
|
||||
readyWhen: events => events.length === (isFennec ? 2 : 5),
|
||||
start: ({ tabs, window }) => {
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,pin-unpin'));
|
||||
utils.pin(tabs[0]);
|
||||
utils.unpin(tabs[0]);
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [open, select, move, pin, unpin] = events;
|
||||
let tab = tabs[0];
|
||||
|
||||
assert.equal(open.type, "TabOpen");
|
||||
assert.equal(open.target, tab);
|
||||
|
||||
assert.equal(select.type, "TabSelect");
|
||||
assert.equal(select.target, tab);
|
||||
|
||||
if (isFennec) {
|
||||
assert.pass("Tab pin / unpin is not supported by Fennec");
|
||||
}
|
||||
else {
|
||||
assert.equal(move.type, "TabMove");
|
||||
assert.equal(move.target, tab);
|
||||
|
||||
assert.equal(pin.type, "TabPinned");
|
||||
assert.equal(pin.target, tab);
|
||||
|
||||
assert.equal(unpin.type, "TabUnpinned");
|
||||
assert.equal(unpin.target, tab);
|
||||
}
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
exports["test open -> open -> move "] = test({
|
||||
readyWhen: events => events.length === (isFennec ? 4 : 5),
|
||||
start: ({tabs, window}) => {
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,Tab-1'));
|
||||
tabs.push(utils.openTab(window, 'data:text/plain,Tab-2'));
|
||||
utils.move(tabs[0], 2);
|
||||
},
|
||||
end: ({ tabs, events, assert, done }) => {
|
||||
let [ tab1, tab2 ] = tabs;
|
||||
let tab1Events = 0;
|
||||
getRelatedEvents(events, tab1).map(event => {
|
||||
tab1Events++;
|
||||
if (tab1Events === 1)
|
||||
assert.equal(event.type, "TabOpen", "first tab opened");
|
||||
else if (tab1Events === 2)
|
||||
assert.equal(event.type, "TabSelect", "first tab selected");
|
||||
else if (tab1Events === 3 && isFennec)
|
||||
assert.equal(event.type, "TabMove", "first tab moved");
|
||||
assert.equal(event.target, tab1);
|
||||
});
|
||||
assert.equal(tab1Events, isFennec ? 2 : 3,
|
||||
"correct number of events for first tab");
|
||||
|
||||
let tab2Events = 0;
|
||||
getRelatedEvents(events, tab2).map(event => {
|
||||
tab2Events++;
|
||||
if (tab2Events === 1)
|
||||
assert.equal(event.type, "TabOpen", "second tab opened");
|
||||
else
|
||||
assert.equal(event.type, "TabSelect", "second tab selected");
|
||||
assert.equal(event.target, tab2);
|
||||
});
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
function getRelatedEvents (events, tabs) {
|
||||
return events.filter(({target}) => ~([].concat(tabs)).indexOf(target));
|
||||
}
|
||||
|
||||
// require("sdk/test").run(exports);
|
@ -0,0 +1,46 @@
|
||||
/* 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";
|
||||
|
||||
// TODO Fennec support in Bug #894525
|
||||
module.metadata = {
|
||||
"engines": {
|
||||
"Firefox": "*"
|
||||
}
|
||||
}
|
||||
|
||||
const { openTab, closeTab } = require("sdk/tabs/utils");
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
|
||||
exports["test unload tab observer"] = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
|
||||
let window = loader.require("sdk/deprecated/window-utils").activeBrowserWindow;
|
||||
let observer = loader.require("sdk/tabs/observer").observer;
|
||||
let opened = 0;
|
||||
let closed = 0;
|
||||
|
||||
observer.on("open", function onOpen(window) { opened++; });
|
||||
observer.on("close", function onClose(window) { closed++; });
|
||||
|
||||
// Open and close tab to trigger observers.
|
||||
closeTab(openTab(window, "data:text/html;charset=utf-8,tab-1"));
|
||||
|
||||
// Unload the module so that all listeners set by observer are removed.
|
||||
loader.unload();
|
||||
|
||||
// Open and close tab once again.
|
||||
closeTab(openTab(window, "data:text/html;charset=utf-8,tab-2"));
|
||||
|
||||
// Enqueuing asserts to make sure that assertion is not performed early.
|
||||
setTimeout(function () {
|
||||
assert.equal(1, opened, "observer open was called before unload only");
|
||||
assert.equal(1, closed, "observer close was called before unload only");
|
||||
done();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// require("test").run(exports);
|
67
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js
Normal file
67
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab-utils.js
Normal file
@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
const { getTabs } = require('sdk/tabs/utils');
|
||||
const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
|
||||
const { browserWindows } = require('sdk/windows');
|
||||
const tabs = require('sdk/tabs');
|
||||
const { pb } = require('./private-browsing/helper');
|
||||
const { isPrivate } = require('sdk/private-browsing');
|
||||
const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils');
|
||||
const { open, close } = require('sdk/window/helpers');
|
||||
const { windows } = require('sdk/window/utils');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { fromIterator } = require('sdk/util/array');
|
||||
|
||||
if (isWindowPBSupported) {
|
||||
exports.testGetTabs = function(assert, done) {
|
||||
let tabCount = getTabs().length;
|
||||
let windowCount = browserWindows.length;
|
||||
|
||||
open(null, {
|
||||
features: {
|
||||
private: true,
|
||||
toolbar: true,
|
||||
chrome: true
|
||||
}
|
||||
}).then(function(window) {
|
||||
assert.ok(isPrivate(window), 'new tab is private');
|
||||
|
||||
assert.equal(getTabs().length, tabCount, 'there are no new tabs found');
|
||||
getTabs().forEach(function(tab) {
|
||||
assert.equal(isPrivate(tab), false, 'all found tabs are not private');
|
||||
assert.equal(isPrivate(getOwnerWindow(tab)), false, 'all found tabs are not private');
|
||||
assert.equal(isPrivate(getTabContentWindow(tab)), false, 'all found tabs are not private');
|
||||
});
|
||||
|
||||
assert.equal(browserWindows.length, windowCount, 'there are no new windows found');
|
||||
fromIterator(browserWindows).forEach(function(window) {
|
||||
assert.equal(isPrivate(window), false, 'all found windows are not private');
|
||||
});
|
||||
|
||||
assert.equal(windows(null, {includePrivate: true}).length, 2, 'there are really two windows');
|
||||
|
||||
close(window).then(done);
|
||||
});
|
||||
};
|
||||
}
|
||||
else if (isTabPBSupported) {
|
||||
exports.testGetTabs = function(assert, done) {
|
||||
let startTabCount = getTabs().length;
|
||||
let tab = openTab(getMostRecentBrowserWindow(), 'about:blank', {
|
||||
isPrivate: true
|
||||
});
|
||||
|
||||
assert.ok(isPrivate(getTabContentWindow(tab)), 'new tab is private');
|
||||
let utils_tabs = getTabs();
|
||||
assert.equal(utils_tabs.length, startTabCount + 1,
|
||||
'there are two tabs found');
|
||||
assert.equal(utils_tabs[utils_tabs.length-1], tab,
|
||||
'the last tab is the opened tab');
|
||||
assert.equal(browserWindows.length, 1, 'there is only one window');
|
||||
closeTab(tab);
|
||||
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
// require('test').run(exports);
|
193
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab.js
Normal file
193
addon-sdk/source/test/addons/e10s-tabs/lib/test-tab.js
Normal file
@ -0,0 +1,193 @@
|
||||
/* 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 tabs = require("sdk/tabs"); // From addon-kit
|
||||
const windowUtils = require("sdk/deprecated/window-utils");
|
||||
const { getTabForWindow } = require('sdk/tabs/helpers');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { viewFor } = require("sdk/view/core");
|
||||
const { modelFor } = require("sdk/model/core");
|
||||
const { getTabId, isTab } = require("sdk/tabs/utils");
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
|
||||
// The primary test tab
|
||||
var primaryTab;
|
||||
|
||||
// We have an auxiliary tab to test background tabs.
|
||||
var auxTab;
|
||||
|
||||
// The window for the outer iframe in the primary test page
|
||||
var iframeWin;
|
||||
|
||||
exports["test GetTabForWindow"] = function(assert, done) {
|
||||
|
||||
assert.equal(getTabForWindow(windowUtils.activeWindow), null,
|
||||
"getTabForWindow return null on topwindow");
|
||||
assert.equal(getTabForWindow(windowUtils.activeBrowserWindow), null,
|
||||
"getTabForWindow return null on topwindow");
|
||||
|
||||
let subSubDocument = encodeURIComponent(
|
||||
'Sub iframe<br/>'+
|
||||
'<iframe id="sub-sub-iframe" src="data:text/html;charset=utf-8,SubSubIframe" />');
|
||||
let subDocument = encodeURIComponent(
|
||||
'Iframe<br/>'+
|
||||
'<iframe id="sub-iframe" src="data:text/html;charset=utf-8,'+subSubDocument+'" />');
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(
|
||||
'Content<br/><iframe id="iframe" src="data:text/html;charset=utf-8,'+subDocument+'" />');
|
||||
|
||||
// Open up a new tab in the background.
|
||||
//
|
||||
// This lets us test whether GetTabForWindow works even when the tab in
|
||||
// question is not active.
|
||||
tabs.open({
|
||||
inBackground: true,
|
||||
url: "about:mozilla",
|
||||
onReady: function(tab) { auxTab = tab; step2(url, assert);},
|
||||
onActivate: function(tab) { step3(assert, done); }
|
||||
});
|
||||
};
|
||||
|
||||
function step2(url, assert) {
|
||||
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function(tab) {
|
||||
primaryTab = tab;
|
||||
let window = windowUtils.activeBrowserWindow.content;
|
||||
|
||||
let matchedTab = getTabForWindow(window);
|
||||
assert.equal(matchedTab, tab,
|
||||
"We are able to find the tab with his content window object");
|
||||
|
||||
let timer = require("sdk/timers");
|
||||
function waitForFrames() {
|
||||
let iframe = window.document.getElementById("iframe");
|
||||
if (!iframe) {
|
||||
timer.setTimeout(waitForFrames, 100);
|
||||
return;
|
||||
}
|
||||
iframeWin = iframe.contentWindow;
|
||||
let subIframe = iframeWin.document.getElementById("sub-iframe");
|
||||
if (!subIframe) {
|
||||
timer.setTimeout(waitForFrames, 100);
|
||||
return;
|
||||
}
|
||||
let subIframeWin = subIframe.contentWindow;
|
||||
let subSubIframe = subIframeWin.document.getElementById("sub-sub-iframe");
|
||||
if (!subSubIframe) {
|
||||
timer.setTimeout(waitForFrames, 100);
|
||||
return;
|
||||
}
|
||||
let subSubIframeWin = subSubIframe.contentWindow;
|
||||
|
||||
matchedTab = getTabForWindow(iframeWin);
|
||||
assert.equal(matchedTab, tab,
|
||||
"We are able to find the tab with an iframe window object");
|
||||
|
||||
matchedTab = getTabForWindow(subIframeWin);
|
||||
assert.equal(matchedTab, tab,
|
||||
"We are able to find the tab with a sub-iframe window object");
|
||||
|
||||
matchedTab = getTabForWindow(subSubIframeWin);
|
||||
assert.equal(matchedTab, tab,
|
||||
"We are able to find the tab with a sub-sub-iframe window object");
|
||||
|
||||
// Put our primary tab in the background and test again.
|
||||
// The onActivate listener will take us to step3.
|
||||
auxTab.activate();
|
||||
}
|
||||
waitForFrames();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function step3(assert, done) {
|
||||
|
||||
let matchedTab = getTabForWindow(iframeWin);
|
||||
assert.equal(matchedTab, primaryTab,
|
||||
"We get the correct tab even when it's in the background");
|
||||
|
||||
primaryTab.close(function () {
|
||||
auxTab.close(function () { done();});
|
||||
});
|
||||
}
|
||||
|
||||
exports["test behavior on close"] = function(assert, done) {
|
||||
|
||||
tabs.open({
|
||||
url: "about:mozilla",
|
||||
onReady: function(tab) {
|
||||
assert.equal(tab.url, "about:mozilla", "Tab has the expected url");
|
||||
// if another test ends before closing a tab then index != 1 here
|
||||
assert.ok(tab.index >= 1, "Tab has the expected index, a value greater than 0");
|
||||
tab.close(function () {
|
||||
assert.equal(tab.url, undefined,
|
||||
"After being closed, tab attributes are undefined (url)");
|
||||
assert.equal(tab.index, undefined,
|
||||
"After being closed, tab attributes are undefined (index)");
|
||||
if (app.is("Firefox")) {
|
||||
// Ensure that we can call destroy multiple times without throwing;
|
||||
// Fennec doesn't use this internal utility
|
||||
tab.destroy();
|
||||
tab.destroy();
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports["test viewFor(tab)"] = (assert, done) => {
|
||||
// Note we defer handlers as length collection is updated after
|
||||
// handler is invoked, so if test is finished before counnts are
|
||||
// updated wrong length will show up in followup tests.
|
||||
tabs.once("open", defer(tab => {
|
||||
const view = viewFor(tab);
|
||||
assert.ok(view, "view is returned");
|
||||
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||
|
||||
tab.close(defer(done));
|
||||
}));
|
||||
|
||||
tabs.open({ url: "about:mozilla" });
|
||||
};
|
||||
|
||||
|
||||
exports["test modelFor(xulTab)"] = (assert, done) => {
|
||||
tabs.open({
|
||||
url: "about:mozilla",
|
||||
onReady: tab => {
|
||||
const view = viewFor(tab);
|
||||
assert.ok(view, "view is returned");
|
||||
assert.ok(isTab(view), "view is underlaying tab");
|
||||
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||
assert.equal(modelFor(view), tab, "modelFor(view) is SDK tab");
|
||||
|
||||
tab.close(defer(done));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports["test tab.readyState"] = (assert, done) => {
|
||||
tabs.open({
|
||||
url: "data:text/html;charset=utf-8,test_readyState",
|
||||
onOpen: (tab) => {
|
||||
assert.equal(tab.readyState, "uninitialized",
|
||||
"tab is 'uninitialized' when opened");
|
||||
},
|
||||
onReady: (tab) => {
|
||||
assert.notEqual(["interactive", "complete"].indexOf(tab.readyState), -1,
|
||||
"tab is either interactive or complete when onReady");
|
||||
},
|
||||
onLoad: (tab) => {
|
||||
assert.equal(tab.readyState, "complete", "tab is complete onLoad");
|
||||
tab.close(defer(done));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// require("sdk/test").run(exports);
|
10
addon-sdk/source/test/addons/e10s-tabs/package.json
Normal file
10
addon-sdk/source/test/addons/e10s-tabs/package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "e10s-tabs",
|
||||
"title": "e10s-tabs",
|
||||
"id": "jid1-ZZaXFHAPlHwbgw",
|
||||
"description": "run tab tests in e10s mode",
|
||||
"author": "Tomislav Jovanovic",
|
||||
"license": "MPL 2.0",
|
||||
"version": "0.1",
|
||||
"e10s": true
|
||||
}
|
@ -10,6 +10,12 @@ const { openTab, closeTab, getBrowserForTab } = require("sdk/tabs/utils");
|
||||
const { defer } = require("sdk/core/promise");
|
||||
const { curry, identity, partial } = require("sdk/lang/functional");
|
||||
|
||||
const { nuke } = require("sdk/loader/sandbox");
|
||||
|
||||
const { open: openWindow, close: closeWindow } = require('sdk/window/helpers');
|
||||
|
||||
const openBrowserWindow = partial(openWindow, null, {features: {toolbar: true}});
|
||||
|
||||
let when = curry(function(options, tab) {
|
||||
let type = options.type || options;
|
||||
let capture = options.capture || false;
|
||||
@ -116,6 +122,46 @@ exports["test nested frames"] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports["test dead object errors"] = function(assert, done) {
|
||||
let system = require("sdk/system/events");
|
||||
let loader = Loader(module);
|
||||
let { events } = loader.require("sdk/content/events");
|
||||
|
||||
// The dead object error is properly reported on console but
|
||||
// doesn't raise any test's exception
|
||||
function onMessage({ subject }) {
|
||||
let message = subject.wrappedJSObject;
|
||||
let { level } = message;
|
||||
let text = String(message.arguments[0]);
|
||||
|
||||
if (level === "error" && text.contains("can't access dead object"))
|
||||
fail(text);
|
||||
}
|
||||
|
||||
let cleanup = () => system.off("console-api-log-event", onMessage);
|
||||
let fail = (reason) => {
|
||||
cleanup();
|
||||
assert.fail(reason);
|
||||
}
|
||||
|
||||
loader.unload();
|
||||
|
||||
// in order to get a dead object error on this module, we need to nuke
|
||||
// the relative sandbox; unload the loader is not enough
|
||||
let url = Object.keys(loader.sandboxes).
|
||||
find(url => url.endsWith("/sdk/content/events.js"));
|
||||
|
||||
nuke(loader.sandboxes[url]);
|
||||
|
||||
system.on("console-api-log-event", onMessage, true);
|
||||
|
||||
openBrowserWindow().
|
||||
then(closeWindow).
|
||||
then(() => assert.pass("checking dead object errors")).
|
||||
then(cleanup).
|
||||
then(done, fail);
|
||||
};
|
||||
|
||||
// ignore *-document-global-created events that are not very consistent.
|
||||
// only allow data uris that we create to ignore unwanted events, e.g.,
|
||||
// about:blank, http:// requests from Fennec's `about:`home page that displays
|
||||
@ -125,7 +171,7 @@ function eventFilter (type, target, callback) {
|
||||
if (target.URL.startsWith("data:text/html,") &&
|
||||
type !== "chrome-document-global-created" &&
|
||||
type !== "content-document-global-created")
|
||||
|
||||
|
||||
callback();
|
||||
}
|
||||
require("test").run(exports);
|
||||
|
@ -937,4 +937,31 @@ exports["test:global postMessage"] = WorkerTest(
|
||||
});
|
||||
});
|
||||
|
||||
exports["test:destroy unbinds listeners from port"] = WorkerTest(
|
||||
"data:text/html;charset=utf-8,portdestroyer",
|
||||
function(assert, browser, done) {
|
||||
let destroyed = false;
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "new " + function WorkerScope() {
|
||||
self.port.emit("destroy");
|
||||
setInterval(self.port.emit, 10, "ping");
|
||||
},
|
||||
onDestroy: done
|
||||
});
|
||||
worker.port.on("ping", () => {
|
||||
if (destroyed) {
|
||||
assert.fail("Should not call events on port after destroy.");
|
||||
}
|
||||
});
|
||||
worker.port.on("destroy", () => {
|
||||
destroyed = true;
|
||||
worker.destroy();
|
||||
assert.pass("Worker destroyed, waiting for no future listeners handling events.");
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
require("test").run(exports);
|
||||
|
@ -678,8 +678,10 @@ exports.testContentScriptWhenOnTabOpen = function(assert, done) {
|
||||
// test timing for all 3 contentScriptWhen options (start, ready, end)
|
||||
// for PageMods created while the tab is interactive (in tab.onReady)
|
||||
exports.testContentScriptWhenOnTabReady = function(assert, done) {
|
||||
const url = "data:text/html;charset=utf-8,testContentScriptWhenOnTabReady";
|
||||
|
||||
// need a bit bigger document to get the right timing of events with e10s
|
||||
let iframeURL = 'data:text/html;charset=utf-8,testContentScriptWhenOnTabReady';
|
||||
let iframe = '<iframe src="' + iframeURL + '" />';
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function(tab) {
|
||||
|
@ -65,7 +65,7 @@ exports.testSidebarIsNotOpenInNewPrivateWindow = function(assert, done) {
|
||||
assert.equal(isSidebarShowing(window), true, 'the sidebar is showing');
|
||||
assert.equal(isShowing(sidebar), true, 'the sidebar is showing');
|
||||
|
||||
let window2 = window.OpenBrowserWindow({private: true});
|
||||
let window2 = window.OpenBrowserWindow({ private: true });
|
||||
windowPromise(window2, 'load').then(focus).then(function() {
|
||||
// TODO: find better alt to setTimeout...
|
||||
setTimeout(function() {
|
||||
|
@ -13,7 +13,7 @@ const { Cu } = require('chrome');
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { show, hide } = require('sdk/ui/sidebar/actions');
|
||||
const { isShowing } = require('sdk/ui/sidebar/utils');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { getMostRecentBrowserWindow, isFocused } = require('sdk/window/utils');
|
||||
const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers');
|
||||
const { setTimeout, setImmediate } = require('sdk/timers');
|
||||
const { isPrivate } = require('sdk/private-browsing');
|
||||
@ -21,6 +21,7 @@ const data = require('./fixtures');
|
||||
const { URL } = require('sdk/url');
|
||||
const { once, off, emit } = require('sdk/event/core');
|
||||
const { defer, all } = require('sdk/core/promise');
|
||||
const { modelFor } = require('sdk/model/core');
|
||||
|
||||
const { BUILTIN_SIDEBAR_MENUITEMS, isSidebarShowing,
|
||||
getSidebarMenuitems, getExtraSidebarMenuitems, makeID, simulateCommand,
|
||||
@ -1419,7 +1420,7 @@ exports.testEventListeners = function(assert, done) {
|
||||
// For more information see Bug 920780
|
||||
exports.testAttachDoesNotEmitWhenShown = function(assert, done) {
|
||||
const { Sidebar } = require('sdk/ui/sidebar');
|
||||
let testName = 'testSidebarLeakCheckUnloadAfterAttach';
|
||||
let testName = 'testAttachDoesNotEmitWhenShown';
|
||||
let count = 0;
|
||||
|
||||
let sidebar = Sidebar({
|
||||
@ -1459,6 +1460,73 @@ exports.testAttachDoesNotEmitWhenShown = function(assert, done) {
|
||||
sidebar.show();
|
||||
}
|
||||
|
||||
exports.testShowHideRawWindowArg = function*(assert) {
|
||||
const { Sidebar } = require('sdk/ui/sidebar');
|
||||
|
||||
let testName = 'testShowHideRawWindowArg';
|
||||
let sidebar = Sidebar({
|
||||
id: testName,
|
||||
title: testName,
|
||||
url: 'data:text/html;charset=utf-8,' + testName
|
||||
});
|
||||
|
||||
let mainWindow = getMostRecentBrowserWindow();
|
||||
let newWindow = yield open().then(focus);
|
||||
|
||||
yield focus(mainWindow);
|
||||
|
||||
yield sidebar.show(newWindow);
|
||||
|
||||
assert.pass('the sidebar was shown');
|
||||
assert.ok(!isSidebarShowing(mainWindow), 'sidebar is not showing in main window');
|
||||
assert.ok(isSidebarShowing(newWindow), 'sidebar is showing in new window');
|
||||
|
||||
assert.ok(isFocused(mainWindow), 'main window is still focused');
|
||||
|
||||
yield sidebar.hide(newWindow);
|
||||
|
||||
assert.ok(isFocused(mainWindow), 'main window is still focused');
|
||||
assert.ok(!isSidebarShowing(mainWindow), 'sidebar is not showing in main window');
|
||||
assert.ok(!isSidebarShowing(newWindow), 'sidebar is not showing in new window');
|
||||
sidebar.destroy();
|
||||
|
||||
yield close(newWindow);
|
||||
}
|
||||
|
||||
exports.testShowHideSDKWindowArg = function*(assert) {
|
||||
const { Sidebar } = require('sdk/ui/sidebar');
|
||||
|
||||
let testName = 'testShowHideSDKWindowArg';
|
||||
let sidebar = Sidebar({
|
||||
id: testName,
|
||||
title: testName,
|
||||
url: 'data:text/html;charset=utf-8,' + testName
|
||||
});
|
||||
|
||||
let mainWindow = getMostRecentBrowserWindow();
|
||||
let newWindow = yield open().then(focus);
|
||||
let newSDKWindow = modelFor(newWindow);
|
||||
|
||||
yield focus(mainWindow);
|
||||
|
||||
yield sidebar.show(newSDKWindow);
|
||||
|
||||
assert.pass('the sidebar was shown');
|
||||
assert.ok(!isSidebarShowing(mainWindow), 'sidebar is not showing in main window');
|
||||
assert.ok(isSidebarShowing(newWindow), 'sidebar is showing in new window');
|
||||
|
||||
assert.ok(isFocused(mainWindow), 'main window is still focused');
|
||||
|
||||
yield sidebar.hide(newSDKWindow);
|
||||
|
||||
assert.ok(isFocused(mainWindow), 'main window is still focused');
|
||||
assert.ok(!isSidebarShowing(mainWindow), 'sidebar is not showing in main window');
|
||||
assert.ok(!isSidebarShowing(newWindow), 'sidebar is not showing in new window');
|
||||
sidebar.destroy();
|
||||
|
||||
yield close(newWindow);
|
||||
}
|
||||
|
||||
// If the module doesn't support the app we're being run in, require() will
|
||||
// throw. In that case, remove all tests above from exports, and add one dummy
|
||||
// test that passes.
|
||||
|
@ -1275,7 +1275,6 @@ let CustomizableUIInternal = {
|
||||
shortcut = ShortcutUtils.findShortcut(document.getElementById(commandId));
|
||||
}
|
||||
if (!shortcut) {
|
||||
ERROR("Could not find a keyboard shortcut for '" + aShortcutNode.outerHTML + "'.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ function setAttributes(aNode, aAttrs) {
|
||||
let additionalArgs = [];
|
||||
if (aAttrs.shortcutId) {
|
||||
let shortcut = doc.getElementById(aAttrs.shortcutId);
|
||||
if (doc) {
|
||||
if (shortcut) {
|
||||
additionalArgs.push(ShortcutUtils.prettifyShortcut(shortcut));
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +284,6 @@ var gPrivacyPane = {
|
||||
|
||||
if (shouldProceed) {
|
||||
pref.value = autoStart.hasAttribute('checked');
|
||||
document.documentElement.acceptDialog();
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
|
@ -14,7 +14,7 @@ add_task(function test_load_start() {
|
||||
|
||||
// Load a new URI but remove the tab before it has finished loading.
|
||||
browser.loadURI("about:mozilla");
|
||||
yield promiseContentMessage(browser, "ss-test:onFrameTreeReset");
|
||||
yield promiseContentMessage(browser, "ss-test:OnHistoryReplaceEntry");
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
// Undo close the tab.
|
||||
|
@ -7,6 +7,7 @@
|
||||
let Cu = Components.utils;
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/sessionstore/FrameTree.jsm", this);
|
||||
let gFrameTree = new FrameTree(this);
|
||||
|
||||
@ -20,6 +21,47 @@ gFrameTree.addObserver({
|
||||
}
|
||||
});
|
||||
|
||||
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
webNav.sessionHistory.addSHistoryListener({
|
||||
OnHistoryNewEntry: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryNewEntry");
|
||||
},
|
||||
|
||||
OnHistoryGoBack: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryGoBack");
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGoForward: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryGoForward");
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGotoIndex: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryGotoIndex");
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryPurge: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryPurge");
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryReload: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryReload");
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryReplaceEntry: function () {
|
||||
sendAsyncMessage("ss-test:OnHistoryReplaceEntry");
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISHistoryListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
});
|
||||
|
||||
/**
|
||||
* This frame script is only loaded for sessionstore mochitests. It enables us
|
||||
* to modify and query docShell data when running with multiple processes.
|
||||
|
@ -43,6 +43,9 @@ DebuggerPanel.prototype = {
|
||||
// Local debugging needs to make the target remote.
|
||||
if (!this.target.isRemote) {
|
||||
targetPromise = this.target.makeRemote();
|
||||
// Listen for tab switching events to manage focus when the content window
|
||||
// is paused and events suppressed.
|
||||
this.target.tab.addEventListener('TabSelect', this);
|
||||
} else {
|
||||
targetPromise = promise.resolve(this.target);
|
||||
}
|
||||
@ -76,6 +79,10 @@ DebuggerPanel.prototype = {
|
||||
this.target.off("thread-paused", this.highlightWhenPaused);
|
||||
this.target.off("thread-resumed", this.unhighlightWhenResumed);
|
||||
|
||||
if (!this.target.isRemote) {
|
||||
this.target.tab.removeEventListener('TabSelect', this);
|
||||
}
|
||||
|
||||
return this._destroyer = this._controller.shutdownDebugger().then(() => {
|
||||
this.emit("destroyed");
|
||||
});
|
||||
@ -105,5 +112,15 @@ DebuggerPanel.prototype = {
|
||||
|
||||
unhighlightWhenResumed: function() {
|
||||
this._toolbox.unhighlightTool("jsdebugger");
|
||||
},
|
||||
|
||||
// nsIDOMEventListener API
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
if (aEvent.target == this.target.tab &&
|
||||
this._controller.activeThread.state == "paused") {
|
||||
// Wait a tick for the content focus event to be delivered.
|
||||
DevToolsUtils.executeSoon(() => this._toolbox.focusTool("jsdebugger"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -190,6 +190,7 @@ skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_pause-exceptions-02.js]
|
||||
[browser_dbg_pause-resume.js]
|
||||
[browser_dbg_pause-warning.js]
|
||||
[browser_dbg_paused-keybindings.js]
|
||||
[browser_dbg_pretty-print-01.js]
|
||||
[browser_dbg_pretty-print-02.js]
|
||||
[browser_dbg_pretty-print-03.js]
|
||||
|
@ -0,0 +1,45 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that keybindings still work when the content window is paused and
|
||||
// the tab is selected again.
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
|
||||
let panel, debuggee, gDebugger, searchBox;
|
||||
|
||||
let [, debuggee, panel] = yield initDebugger(TAB_URL);
|
||||
gDebugger = panel.panelWin;
|
||||
searchBox = gDebugger.DebuggerView.Filtering._searchbox;
|
||||
|
||||
// Spin the event loop before causing the debuggee to pause, to allow
|
||||
// this function to return first.
|
||||
executeSoon(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
debuggee.document.querySelector("button"),
|
||||
debuggee);
|
||||
});
|
||||
yield waitForSourceAndCaretAndScopes(panel, ".html", 20);
|
||||
yield ensureThreadClientState(panel, "paused");
|
||||
|
||||
// Now open a tab and close it.
|
||||
let tab2 = yield addTab(TAB_URL);
|
||||
yield removeTab(tab2);
|
||||
yield ensureCaretAt(panel, 20);
|
||||
|
||||
// Try to use the Cmd-L keybinding to see if it still works.
|
||||
let caretMove = ensureCaretAt(panel, 15, 1, true);
|
||||
// Wait a tick for the editor focus event to occur first.
|
||||
executeSoon(function () {
|
||||
EventUtils.synthesizeKey("l", { accelKey: true });
|
||||
EventUtils.synthesizeKey("1", {});
|
||||
EventUtils.synthesizeKey("5", {});
|
||||
});
|
||||
yield caretMove;
|
||||
|
||||
yield resumeDebuggerThenCloseAndFinish(panel);
|
||||
}).then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
let doc;
|
||||
let salutation;
|
||||
let closing;
|
||||
|
||||
const NEWHEIGHT = 226;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<div id="first" style="{ margin: 10em; ' +
|
||||
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA}">\n' +
|
||||
'<h1>Some header text</h1>\n' +
|
||||
'<p id="salutation" style="{font-size: 12pt}">hi.</p>\n' +
|
||||
'<p id="body" style="{font-size: 12pt}">I am a test-case. This text exists ' +
|
||||
'solely to provide some things to test the inspector initialization.</p>\n' +
|
||||
'If you are reading this, you should go do something else instead. Maybe ' +
|
||||
'read a book. Or better yet, write some test-cases for another bit of code. ' +
|
||||
'<span style="{font-style: italic}">Maybe more inspector test-cases!</span></p>\n' +
|
||||
'<p id="closing">end transmission</p>\n' +
|
||||
'</div>';
|
||||
doc.title = "Inspector Initialization Test";
|
||||
startInspectorTests();
|
||||
}
|
||||
|
||||
function startInspectorTests()
|
||||
{
|
||||
ok(InspectorUI, "InspectorUI variable exists");
|
||||
Services.obs.addObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
if (InspectorUI.treePanelEnabled) {
|
||||
Services.obs.addObserver(treePanelTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
InspectorUI.stopInspecting();
|
||||
|
||||
InspectorUI.treePanel.open();
|
||||
} else
|
||||
finishInspectorTests();
|
||||
}
|
||||
|
||||
function treePanelTests()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
Services.obs.addObserver(treePanelTests2,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
let height = Services.prefs.getIntPref("devtools.inspector.htmlHeight");
|
||||
|
||||
is(InspectorUI.treePanel.container.height, height,
|
||||
"Container height is " + height);
|
||||
|
||||
InspectorUI.treePanel.container.height = NEWHEIGHT;
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.treePanel.close();
|
||||
InspectorUI.treePanel.open();
|
||||
});
|
||||
}
|
||||
|
||||
function treePanelTests2()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelTests2,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
let height = Services.prefs.getIntPref("devtools.inspector.htmlHeight");
|
||||
|
||||
is(InspectorUI.treePanel.container.height, NEWHEIGHT,
|
||||
"Container height is now " + height);
|
||||
|
||||
InspectorUI.treePanel.close();
|
||||
executeSoon(function() {
|
||||
finishInspectorTests()
|
||||
});
|
||||
}
|
||||
|
||||
function finishInspectorTests()
|
||||
{
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html;charset=utf-8,browser_inspector_tree_height.js";
|
||||
}
|
||||
|
@ -181,6 +181,7 @@ HTMLEditor.prototype = {
|
||||
this.editorInner.removeEventListener("click", stopPropagation, false);
|
||||
|
||||
this.hide(false);
|
||||
this.container.parentNode.removeChild(this.container);
|
||||
this.container.remove();
|
||||
this.editor.destroy();
|
||||
}
|
||||
};
|
||||
|
@ -118,7 +118,7 @@ let NetMonitorView = {
|
||||
/**
|
||||
* Destroys the UI for all the displayed panes.
|
||||
*/
|
||||
_destroyPanes: function() {
|
||||
_destroyPanes: Task.async(function*() {
|
||||
dumpn("Destroying the NetMonitorView panes");
|
||||
|
||||
Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
|
||||
@ -126,7 +126,12 @@ let NetMonitorView = {
|
||||
|
||||
this._detailsPane = null;
|
||||
this._detailsPaneToggleButton = null;
|
||||
},
|
||||
|
||||
for (let p of this._editorPromises.values()) {
|
||||
let editor = yield p;
|
||||
editor.destroy();
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Gets the visibility state of the network details pane.
|
||||
|
@ -40,6 +40,11 @@ var ItchEditor = Class({
|
||||
emit(this, name, ...args);
|
||||
},
|
||||
|
||||
/* Does the editor not have any unsaved changes? */
|
||||
isClean: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the editor with a single host. This should be called
|
||||
* by objects extending this object with:
|
||||
@ -145,6 +150,13 @@ var TextEditor = Class({
|
||||
return extraKeys;
|
||||
},
|
||||
|
||||
isClean: function() {
|
||||
if (!this.editor.isAppended()) {
|
||||
return true;
|
||||
}
|
||||
return this.editor.isClean();
|
||||
},
|
||||
|
||||
initialize: function(document, mode=Editor.modes.text) {
|
||||
ItchEditor.prototype.initialize.apply(this, arguments);
|
||||
this.label = mode.name;
|
||||
@ -165,11 +177,6 @@ var TextEditor = Class({
|
||||
});
|
||||
|
||||
this.appended = this.editor.appendTo(this.elt);
|
||||
this.appended.then(() => {
|
||||
if (this.editor) {
|
||||
this.editor.setupAutoCompletion();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ var DeletePlugin = Class({
|
||||
this.host.addCommand(this, {
|
||||
id: "cmd-delete"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
this.contextMenuItem = this.host.createMenuItem({
|
||||
parent: this.host.contextMenuPopup,
|
||||
label: getLocalizedString("projecteditor.deleteLabel"),
|
||||
command: "cmd-delete"
|
||||
@ -34,6 +34,19 @@ var DeletePlugin = Class({
|
||||
);
|
||||
},
|
||||
|
||||
onContextMenuOpen: function(resource) {
|
||||
// Do not allow deletion of the top level items in the tree. In the
|
||||
// case of the Web IDE in particular this can leave the UI in a weird
|
||||
// state. If we'd like to add ability to delete the project folder from
|
||||
// the tree in the future, then the UI could be cleaned up by listening
|
||||
// to the ProjectTree's "resource-removed" event.
|
||||
if (!resource.parent) {
|
||||
this.contextMenuItem.setAttribute("hidden", "true");
|
||||
} else {
|
||||
this.contextMenuItem.removeAttribute("hidden");
|
||||
}
|
||||
},
|
||||
|
||||
onCommand: function(cmd) {
|
||||
if (cmd === "cmd-delete") {
|
||||
let tree = this.host.projectTree;
|
||||
|
@ -22,9 +22,8 @@ var DirtyPlugin = Class({
|
||||
|
||||
// Dont' force a refresh unless the dirty state has changed...
|
||||
let priv = this.priv(editor);
|
||||
let clean = editor.editor.isClean();
|
||||
let clean = editor.isClean()
|
||||
if (priv.isClean !== clean) {
|
||||
|
||||
let resource = editor.shell.resource;
|
||||
emit(resource, "label-change", resource);
|
||||
priv.isClean = clean;
|
||||
|
@ -62,6 +62,7 @@ require("projecteditor/plugins/status-bar/plugin");
|
||||
* - "onEditorCursorActivity": When there is cursor activity in a text editor
|
||||
* - "onCommand": When a command happens
|
||||
* - "onEditorDestroyed": When editor is destroyed
|
||||
* - "onContextMenuOpen": When the context menu is opened on the project tree
|
||||
*
|
||||
* The events can be bound like so:
|
||||
* projecteditor.on("onEditorCreated", (editor) => { });
|
||||
@ -87,6 +88,7 @@ var ProjectEditor = Class({
|
||||
this._onEditorActivated = this._onEditorActivated.bind(this);
|
||||
this._onEditorDeactivated = this._onEditorDeactivated.bind(this);
|
||||
this._updateMenuItems = this._updateMenuItems.bind(this);
|
||||
this._updateContextMenuItems = this._updateContextMenuItems.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.menubar = options.menubar || null;
|
||||
this.menuindex = options.menuindex || null;
|
||||
@ -231,6 +233,7 @@ var ProjectEditor = Class({
|
||||
this.editorKeyset = this.document.getElementById("editMenuKeys");
|
||||
|
||||
this.contextMenuPopup = this.document.getElementById("context-menu-popup");
|
||||
this.contextMenuPopup.addEventListener("popupshowing", this._updateContextMenuItems);
|
||||
|
||||
this.projectEditorCommandset.addEventListener("command", (evt) => {
|
||||
evt.stopPropagation();
|
||||
@ -269,6 +272,15 @@ var ProjectEditor = Class({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable / disable necessary context menu items by passing an event
|
||||
* onto plugins.
|
||||
*/
|
||||
_updateContextMenuItems: function() {
|
||||
let resource = this.projectTree.getSelectedResource();
|
||||
this.pluginDispatch("onContextMenuOpen", resource);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy all objects on the iframe unload event.
|
||||
*/
|
||||
|
@ -192,7 +192,10 @@ var ShellDeck = Class({
|
||||
this.deck.selectedPanel = shell.elt;
|
||||
this._activeShell = shell;
|
||||
|
||||
shell.load();
|
||||
// Only reload the shell if the editor doesn't have local changes.
|
||||
if (shell.editor.isClean()) {
|
||||
shell.load();
|
||||
}
|
||||
shell.editorLoaded.then(() => {
|
||||
// Handle case where another shell has been requested before this
|
||||
// one is finished loading.
|
||||
|
@ -13,68 +13,73 @@ let test = asyncTest(function*() {
|
||||
let root = [...projecteditor.project.allStores()][0].root;
|
||||
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
|
||||
for (let child of root.children) {
|
||||
yield deleteWithContextMenu(projecteditor.projectTree.getViewContainer(child));
|
||||
yield deleteWithContextMenu(projecteditor, projecteditor.projectTree.getViewContainer(child));
|
||||
}
|
||||
|
||||
function onPopupShow(contextMenu) {
|
||||
let defer = promise.defer();
|
||||
contextMenu.addEventListener("popupshown", function onpopupshown() {
|
||||
contextMenu.removeEventListener("popupshown", onpopupshown);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
yield testDeleteOnRoot(projecteditor, projecteditor.projectTree.getViewContainer(root));
|
||||
});
|
||||
|
||||
function openContextMenuOn(node) {
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
node,
|
||||
{button: 2, type: "contextmenu"},
|
||||
node.ownerDocument.defaultView
|
||||
);
|
||||
}
|
||||
|
||||
function deleteWithContextMenu(container) {
|
||||
let defer = promise.defer();
|
||||
function openContextMenuOn(node) {
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
node,
|
||||
{button: 2, type: "contextmenu"},
|
||||
node.ownerDocument.defaultView
|
||||
);
|
||||
}
|
||||
|
||||
let resource = container.resource;
|
||||
let popup = projecteditor.contextMenuPopup;
|
||||
info ("Going to attempt deletion for: " + resource.path)
|
||||
function testDeleteOnRoot(projecteditor, container) {
|
||||
let popup = projecteditor.contextMenuPopup;
|
||||
let oncePopupShown = onPopupShow(popup);
|
||||
openContextMenuOn(container.label);
|
||||
yield oncePopupShown;
|
||||
|
||||
onPopupShow(popup).then(function () {
|
||||
let deleteCommand = popup.querySelector("[command=cmd-delete]");
|
||||
ok (deleteCommand, "Delete command exists in popup");
|
||||
is (deleteCommand.getAttribute("hidden"), "", "Delete command is visible");
|
||||
is (deleteCommand.getAttribute("disabled"), "", "Delete command is enabled");
|
||||
let deleteCommand = popup.querySelector("[command=cmd-delete]");
|
||||
ok (deleteCommand, "Delete command exists in popup");
|
||||
is (deleteCommand.getAttribute("hidden"), "true", "Delete command is hidden");
|
||||
}
|
||||
|
||||
function onConfirmShown(aSubject) {
|
||||
info("confirm dialog observed as expected");
|
||||
Services.obs.removeObserver(onConfirmShown, "common-dialog-loaded");
|
||||
Services.obs.removeObserver(onConfirmShown, "tabmodal-dialog-loaded");
|
||||
function deleteWithContextMenu(projecteditor, container) {
|
||||
let defer = promise.defer();
|
||||
|
||||
projecteditor.project.on("refresh-complete", function refreshComplete() {
|
||||
projecteditor.project.off("refresh-complete", refreshComplete);
|
||||
OS.File.stat(resource.path).then(() => {
|
||||
ok (false, "The file was not deleted");
|
||||
defer.resolve();
|
||||
}, (ex) => {
|
||||
ok (ex instanceof OS.File.Error && ex.becauseNoSuchFile, "OS.File.stat promise was rejected because the file is gone");
|
||||
defer.resolve();
|
||||
});
|
||||
let popup = projecteditor.contextMenuPopup;
|
||||
let resource = container.resource;
|
||||
info ("Going to attempt deletion for: " + resource.path);
|
||||
|
||||
onPopupShow(popup).then(function () {
|
||||
let deleteCommand = popup.querySelector("[command=cmd-delete]");
|
||||
ok (deleteCommand, "Delete command exists in popup");
|
||||
is (deleteCommand.getAttribute("hidden"), "", "Delete command is visible");
|
||||
is (deleteCommand.getAttribute("disabled"), "", "Delete command is enabled");
|
||||
|
||||
function onConfirmShown(aSubject) {
|
||||
info("confirm dialog observed as expected");
|
||||
Services.obs.removeObserver(onConfirmShown, "common-dialog-loaded");
|
||||
Services.obs.removeObserver(onConfirmShown, "tabmodal-dialog-loaded");
|
||||
|
||||
projecteditor.project.on("refresh-complete", function refreshComplete() {
|
||||
projecteditor.project.off("refresh-complete", refreshComplete);
|
||||
OS.File.stat(resource.path).then(() => {
|
||||
ok (false, "The file was not deleted");
|
||||
defer.resolve();
|
||||
}, (ex) => {
|
||||
ok (ex instanceof OS.File.Error && ex.becauseNoSuchFile, "OS.File.stat promise was rejected because the file is gone");
|
||||
defer.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Click the 'OK' button
|
||||
aSubject.Dialog.ui.button0.click();
|
||||
}
|
||||
// Click the 'OK' button
|
||||
aSubject.Dialog.ui.button0.click();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(onConfirmShown, "common-dialog-loaded", false);
|
||||
Services.obs.addObserver(onConfirmShown, "tabmodal-dialog-loaded", false);
|
||||
Services.obs.addObserver(onConfirmShown, "common-dialog-loaded", false);
|
||||
Services.obs.addObserver(onConfirmShown, "tabmodal-dialog-loaded", false);
|
||||
|
||||
deleteCommand.click();
|
||||
popup.hidePopup();
|
||||
});
|
||||
deleteCommand.click();
|
||||
popup.hidePopup();
|
||||
});
|
||||
|
||||
openContextMenuOn(container.label);
|
||||
openContextMenuOn(container.label);
|
||||
|
||||
return defer.promise;
|
||||
}
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
@ -22,9 +22,41 @@ let test = asyncTest(function*() {
|
||||
let resource = resources.filter(r=>r.basename === data.basename)[0];
|
||||
yield selectFile(projecteditor, resource);
|
||||
yield testChangeFileExternally(projecteditor, getTempFile(data.path).path, data.newContent);
|
||||
yield testChangeUnsavedFileExternally(projecteditor, getTempFile(data.path).path, data.newContent + "[changed]");
|
||||
}
|
||||
});
|
||||
|
||||
function testChangeUnsavedFileExternally(projecteditor, filePath, newData) {
|
||||
info ("Testing file external changes for: " + filePath);
|
||||
|
||||
let editor = projecteditor.currentEditor;
|
||||
let resource = projecteditor.resourceFor(editor);
|
||||
let initialData = yield getFileData(filePath);
|
||||
|
||||
is (resource.path, filePath, "Resource path is set correctly");
|
||||
is (editor.editor.getText(), initialData, "Editor is loaded with correct file contents");
|
||||
|
||||
info ("Editing but not saving file in project editor");
|
||||
ok (editor.isClean(), "Editor is clean");
|
||||
editor.editor.setText("foobar");
|
||||
ok (!editor.isClean(), "Editor is dirty");
|
||||
|
||||
info ("Editor has been selected, writing to file externally");
|
||||
yield writeToFile(resource.path, newData);
|
||||
|
||||
info ("Selecting another resource, then reselecting this one");
|
||||
projecteditor.projectTree.selectResource(resource.store.root);
|
||||
yield onceEditorActivated(projecteditor);
|
||||
projecteditor.projectTree.selectResource(resource);
|
||||
yield onceEditorActivated(projecteditor);
|
||||
|
||||
let editor = projecteditor.currentEditor;
|
||||
info ("Checking to make sure the editor is now populated correctly");
|
||||
is (editor.editor.getText(), "foobar", "Editor has not been updated with new file contents");
|
||||
|
||||
info ("Finished checking saving for " + filePath);
|
||||
}
|
||||
|
||||
function testChangeFileExternally(projecteditor, filePath, newData) {
|
||||
info ("Testing file external changes for: " + filePath);
|
||||
|
||||
|
@ -106,21 +106,3 @@ function openAndCloseMenu(menu) {
|
||||
EventUtils.synthesizeMouseAtCenter(menu, {}, menu.ownerDocument.defaultView);
|
||||
yield hidden;
|
||||
}
|
||||
|
||||
function onPopupShow(menu) {
|
||||
let defer = promise.defer();
|
||||
menu.addEventListener("popupshown", function onpopupshown() {
|
||||
menu.removeEventListener("popupshown", onpopupshown);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
function onPopupHidden(menu) {
|
||||
let defer = promise.defer();
|
||||
menu.addEventListener("popuphidden", function onpopupshown() {
|
||||
menu.removeEventListener("popuphidden", onpopupshown);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
@ -303,3 +303,22 @@ function onceEditorSave(projecteditor) {
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
function onPopupShow(menu) {
|
||||
let defer = promise.defer();
|
||||
menu.addEventListener("popupshown", function onpopupshown() {
|
||||
menu.removeEventListener("popupshown", onpopupshown);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
function onPopupHidden(menu) {
|
||||
let defer = promise.defer();
|
||||
menu.addEventListener("popuphidden", function onpopuphidden() {
|
||||
menu.removeEventListener("popuphidden", onpopuphidden);
|
||||
defer.resolve();
|
||||
});
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
|
@ -1613,7 +1613,6 @@ var Scratchpad = {
|
||||
this.editor.appendTo(editorElement).then(() => {
|
||||
var lines = initialText.split("\n");
|
||||
|
||||
this.editor.setupAutoCompletion();
|
||||
this.editor.on("change", this._onChanged);
|
||||
this._onPaste = WebConsoleUtils.pasteHandlerGen(this.editor.container.contentDocument.body,
|
||||
document.querySelector('#scratchpad-notificationbox'));
|
||||
@ -2323,6 +2322,12 @@ var CloseObserver = {
|
||||
|
||||
uninit: function CO_uninit()
|
||||
{
|
||||
// Will throw exception if removeObserver is called twice.
|
||||
if (this._uninited) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._uninited = true;
|
||||
Services.obs.removeObserver(this, "browser-lastwindow-close-requested",
|
||||
false);
|
||||
},
|
||||
|
@ -359,9 +359,14 @@ let ShadersEditorsView = {
|
||||
/**
|
||||
* Destruction function, called when the tool is closed.
|
||||
*/
|
||||
destroy: function() {
|
||||
destroy: Task.async(function*() {
|
||||
this._destroyed = true;
|
||||
this._toggleListeners("off");
|
||||
},
|
||||
for (let p of this._editorPromises.values()) {
|
||||
let editor = yield p;
|
||||
editor.destroy();
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets the text displayed in the vertex and fragment shader editors.
|
||||
@ -415,7 +420,12 @@ let ShadersEditorsView = {
|
||||
let parent = $("#" + type +"-editor");
|
||||
let editor = new Editor(DEFAULT_EDITOR_CONFIG);
|
||||
editor.config.mode = Editor.modes[type];
|
||||
editor.appendTo(parent).then(() => deferred.resolve(editor));
|
||||
|
||||
if (this._destroyed) {
|
||||
deferred.resolve(editor);
|
||||
} else {
|
||||
editor.appendTo(parent).then(() => deferred.resolve(editor));
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
@ -11,14 +11,14 @@ const CM_TERN_SCRIPTS = [
|
||||
"chrome://browser/content/devtools/codemirror/show-hint.js"
|
||||
];
|
||||
|
||||
const privates = new WeakMap();
|
||||
const autocompleteMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Prepares an editor instance for autocompletion.
|
||||
*/
|
||||
function initializeAutoCompletion(ctx, options = {}) {
|
||||
let { cm, ed, Editor } = ctx;
|
||||
if (privates.has(ed)) {
|
||||
if (autocompleteMap.has(ed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -88,12 +88,12 @@ function initializeAutoCompletion(ctx, options = {}) {
|
||||
cm.off("cursorActivity", updateArgHintsCallback);
|
||||
cm.removeKeyMap(keyMap);
|
||||
win.tern = cm.tern = null;
|
||||
privates.delete(ed);
|
||||
autocompleteMap.delete(ed);
|
||||
};
|
||||
|
||||
ed.on("destroy", destroyTern);
|
||||
|
||||
privates.set(ed, {
|
||||
autocompleteMap.set(ed, {
|
||||
destroy: destroyTern
|
||||
});
|
||||
|
||||
@ -126,8 +126,8 @@ function initializeAutoCompletion(ctx, options = {}) {
|
||||
"Up": cycle.bind(null, true),
|
||||
"Enter": () => {
|
||||
if (popup && popup.isOpen) {
|
||||
if (!privates.get(ed).suggestionInsertedOnce) {
|
||||
privates.get(ed).insertingSuggestion = true;
|
||||
if (!autocompleteMap.get(ed).suggestionInsertedOnce) {
|
||||
autocompleteMap.get(ed).insertingSuggestion = true;
|
||||
let {label, preLabel, text} = popup.getItemAtIndex(0);
|
||||
let cur = ed.getCursor();
|
||||
ed.replaceText(text.slice(preLabel.length), cur, cur);
|
||||
@ -157,10 +157,10 @@ function initializeAutoCompletion(ctx, options = {}) {
|
||||
cm.removeKeyMap(keyMap);
|
||||
popup.destroy();
|
||||
keyMap = popup = completer = null;
|
||||
privates.delete(ed);
|
||||
autocompleteMap.delete(ed);
|
||||
}
|
||||
|
||||
privates.set(ed, {
|
||||
autocompleteMap.set(ed, {
|
||||
popup: popup,
|
||||
completer: completer,
|
||||
keyMap: keyMap,
|
||||
@ -175,11 +175,11 @@ function initializeAutoCompletion(ctx, options = {}) {
|
||||
*/
|
||||
function destroyAutoCompletion(ctx) {
|
||||
let { ed } = ctx;
|
||||
if (!privates.has(ed)) {
|
||||
if (!autocompleteMap.has(ed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {destroy} = privates.get(ed);
|
||||
let {destroy} = autocompleteMap.get(ed);
|
||||
destroy();
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ function destroyAutoCompletion(ctx) {
|
||||
* Provides suggestions to autocomplete the current token/word being typed.
|
||||
*/
|
||||
function autoComplete({ ed, cm }) {
|
||||
let private = privates.get(ed);
|
||||
let private = autocompleteMap.get(ed);
|
||||
let { completer, popup } = private;
|
||||
if (!completer || private.insertingSuggestion || private.doNotAutocomplete) {
|
||||
private.insertingSuggestion = false;
|
||||
@ -223,7 +223,7 @@ function autoComplete({ ed, cm }) {
|
||||
* when `reverse` is not true. Opposite otherwise.
|
||||
*/
|
||||
function cycleSuggestions(ed, reverse) {
|
||||
let private = privates.get(ed);
|
||||
let private = autocompleteMap.get(ed);
|
||||
let { popup, completer } = private;
|
||||
let cur = ed.getCursor();
|
||||
private.insertingSuggestion = true;
|
||||
@ -263,7 +263,7 @@ function cycleSuggestions(ed, reverse) {
|
||||
* keypresses.
|
||||
*/
|
||||
function onEditorKeypress({ ed, Editor }, cm, event) {
|
||||
let private = privates.get(ed);
|
||||
let private = autocompleteMap.get(ed);
|
||||
|
||||
// Do not try to autocomplete with multiple selections.
|
||||
if (ed.hasMultipleSelections()) {
|
||||
@ -319,8 +319,8 @@ function onEditorKeypress({ ed, Editor }, cm, event) {
|
||||
* Returns the private popup. This method is used by tests to test the feature.
|
||||
*/
|
||||
function getPopup({ ed }) {
|
||||
if (privates.has(ed))
|
||||
return privates.get(ed).popup;
|
||||
if (autocompleteMap.has(ed))
|
||||
return autocompleteMap.get(ed).popup;
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -330,16 +330,25 @@ function getPopup({ ed }) {
|
||||
* implementation of completer supports it.
|
||||
*/
|
||||
function getInfoAt({ ed }, caret) {
|
||||
let completer = privates.get(ed).completer;
|
||||
let completer = autocompleteMap.get(ed).completer;
|
||||
if (completer && completer.getInfoAt)
|
||||
return completer.getInfoAt(ed.getText(), caret);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether autocompletion is enabled for this editor.
|
||||
* Used for testing
|
||||
*/
|
||||
function isAutocompletionEnabled({ ed }) {
|
||||
return autocompleteMap.has(ed);
|
||||
}
|
||||
|
||||
// Export functions
|
||||
|
||||
module.exports.initializeAutoCompletion = initializeAutoCompletion;
|
||||
module.exports.destroyAutoCompletion = destroyAutoCompletion;
|
||||
module.exports.getAutocompletionPopup = getPopup;
|
||||
module.exports.getInfoAt = getInfoAt;
|
||||
module.exports.isAutocompletionEnabled = isAutocompletionEnabled;
|
||||
|
@ -17,6 +17,7 @@ const DETECT_INDENT = "devtools.editor.detectindentation";
|
||||
const DETECT_INDENT_MAX_LINES = 500;
|
||||
const L10N_BUNDLE = "chrome://browser/locale/devtools/sourceeditor.properties";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const VALID_KEYMAPS = new Set(["emacs", "vim", "sublime"]);
|
||||
|
||||
// Maximum allowed margin (in number of lines) from top or bottom of the editor
|
||||
// while shifting to a line which was initially out of view.
|
||||
@ -29,6 +30,7 @@ const RE_JUMP_TO_LINE = /^(\d+):?(\d+)?/;
|
||||
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
const events = require("devtools/toolkit/event-emitter");
|
||||
const { PrefObserver } = require("devtools/styleeditor/utils");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
const L10N = Services.strings.createBundle(L10N_BUNDLE);
|
||||
@ -139,7 +141,6 @@ Editor.modes = {
|
||||
function Editor(config) {
|
||||
const tabSize = Services.prefs.getIntPref(TAB_SIZE);
|
||||
const useTabs = !Services.prefs.getBoolPref(EXPAND_TAB);
|
||||
const keyMap = Services.prefs.getCharPref(KEYMAP);
|
||||
const useAutoClose = Services.prefs.getBoolPref(AUTO_CLOSE);
|
||||
|
||||
this.version = null;
|
||||
@ -157,7 +158,8 @@ function Editor(config) {
|
||||
autoCloseEnabled: useAutoClose,
|
||||
theme: "mozilla",
|
||||
themeSwitching: true,
|
||||
autocomplete: false
|
||||
autocomplete: false,
|
||||
autocompleteOpts: {}
|
||||
};
|
||||
|
||||
// Additional shortcuts.
|
||||
@ -170,9 +172,6 @@ function Editor(config) {
|
||||
this.config.extraKeys[Editor.keyFor("indentLess")] = false;
|
||||
this.config.extraKeys[Editor.keyFor("indentMore")] = false;
|
||||
|
||||
// If alternative keymap is provided, use it.
|
||||
if (keyMap === "emacs" || keyMap === "vim" || keyMap === "sublime")
|
||||
this.config.keyMap = keyMap;
|
||||
|
||||
// Overwrite default config with user-provided, if needed.
|
||||
Object.keys(config).forEach((k) => {
|
||||
@ -199,9 +198,8 @@ function Editor(config) {
|
||||
}
|
||||
}
|
||||
|
||||
// Configure automatic bracket closing.
|
||||
if (!this.config.autoCloseEnabled)
|
||||
this.config.autoCloseBrackets = false;
|
||||
// Remember the initial value of autoCloseBrackets.
|
||||
this.config.autoCloseBracketsSaved = this.config.autoCloseBrackets;
|
||||
|
||||
// Overwrite default tab behavior. If something is selected,
|
||||
// indent those lines. If nothing is selected and we're
|
||||
@ -325,8 +323,16 @@ Editor.prototype = {
|
||||
this.container = env;
|
||||
editors.set(this, cm);
|
||||
|
||||
this.resetIndentUnit();
|
||||
this.reloadPreferences = this.reloadPreferences.bind(this);
|
||||
this._prefObserver = new PrefObserver("devtools.editor.");
|
||||
this._prefObserver.on(TAB_SIZE, this.reloadPreferences);
|
||||
this._prefObserver.on(EXPAND_TAB, this.reloadPreferences);
|
||||
this._prefObserver.on(KEYMAP, this.reloadPreferences);
|
||||
this._prefObserver.on(AUTO_CLOSE, this.reloadPreferences);
|
||||
this._prefObserver.on(AUTOCOMPLETE, this.reloadPreferences);
|
||||
this._prefObserver.on(DETECT_INDENT, this.reloadPreferences);
|
||||
|
||||
this.reloadPreferences();
|
||||
def.resolve();
|
||||
};
|
||||
|
||||
@ -338,6 +344,14 @@ Editor.prototype = {
|
||||
return def.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether the editor is ready to
|
||||
* use. Use appendTo(el).then(() => {}) for most cases
|
||||
*/
|
||||
isAppended: function() {
|
||||
return editors.has(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the currently active highlighting mode.
|
||||
* See Editor.modes for the list of all suppoert modes.
|
||||
@ -397,6 +411,28 @@ Editor.prototype = {
|
||||
this.resetIndentUnit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Reload the state of the editor based on all current preferences.
|
||||
* This is called automatically when any of the relevant preferences
|
||||
* change.
|
||||
*/
|
||||
reloadPreferences: function() {
|
||||
// Restore the saved autoCloseBrackets value if it is preffed on.
|
||||
let useAutoClose = Services.prefs.getBoolPref(AUTO_CLOSE);
|
||||
this.setOption("autoCloseBrackets",
|
||||
useAutoClose ? this.config.autoCloseBracketsSaved : false);
|
||||
|
||||
// If alternative keymap is provided, use it.
|
||||
const keyMap = Services.prefs.getCharPref(KEYMAP);
|
||||
if (VALID_KEYMAPS.has(keyMap))
|
||||
this.setOption("keyMap", keyMap)
|
||||
else
|
||||
this.setOption("keyMap", "default");
|
||||
|
||||
this.resetIndentUnit();
|
||||
this.setupAutoCompletion();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the editor's indentation based on the current prefs and
|
||||
* re-detect indentation if we should.
|
||||
@ -878,6 +914,13 @@ Editor.prototype = {
|
||||
*/
|
||||
setOption: function(o, v) {
|
||||
let cm = editors.get(this);
|
||||
|
||||
// Save the state of a valid autoCloseBrackets string, so we can reset
|
||||
// it if it gets preffed off and back on.
|
||||
if (o === "autoCloseBrackets" && v) {
|
||||
this.config.autoCloseBracketsSaved = v;
|
||||
}
|
||||
|
||||
if (o === "autocomplete") {
|
||||
this.config.autocomplete = v;
|
||||
this.setupAutoCompletion();
|
||||
@ -908,7 +951,7 @@ Editor.prototype = {
|
||||
* it just because it is preffed on (it still needs to be requested by the
|
||||
* editor), but we do want to always disable it if it is preffed off.
|
||||
*/
|
||||
setupAutoCompletion: function (options = {}) {
|
||||
setupAutoCompletion: function () {
|
||||
// The autocomplete module will overwrite this.initializeAutoCompletion
|
||||
// with a mode specific autocompletion handler.
|
||||
if (!this.initializeAutoCompletion) {
|
||||
@ -916,7 +959,7 @@ Editor.prototype = {
|
||||
}
|
||||
|
||||
if (this.config.autocomplete && Services.prefs.getBoolPref(AUTOCOMPLETE)) {
|
||||
this.initializeAutoCompletion(options);
|
||||
this.initializeAutoCompletion(this.config.autocompleteOpts);
|
||||
} else {
|
||||
this.destroyAutoCompletion();
|
||||
}
|
||||
@ -957,6 +1000,17 @@ Editor.prototype = {
|
||||
this.container = null;
|
||||
this.config = null;
|
||||
this.version = null;
|
||||
|
||||
if (this._prefObserver) {
|
||||
this._prefObserver.off(TAB_SIZE, this.reloadPreferences);
|
||||
this._prefObserver.off(EXPAND_TAB, this.reloadPreferences);
|
||||
this._prefObserver.off(KEYMAP, this.reloadPreferences);
|
||||
this._prefObserver.off(AUTO_CLOSE, this.reloadPreferences);
|
||||
this._prefObserver.off(AUTOCOMPLETE, this.reloadPreferences);
|
||||
this._prefObserver.off(DETECT_INDENT, this.reloadPreferences);
|
||||
this._prefObserver.destroy();
|
||||
}
|
||||
|
||||
this.emit("destroy");
|
||||
}
|
||||
};
|
||||
|
@ -28,6 +28,7 @@ support-files =
|
||||
[browser_editor_history.js]
|
||||
[browser_editor_markers.js]
|
||||
[browser_editor_movelines.js]
|
||||
[browser_editor_prefs.js]
|
||||
[browser_editor_addons.js]
|
||||
[browser_codemirror.js]
|
||||
[browser_css_autocompletion.js]
|
||||
|
@ -53,8 +53,6 @@ function testPref(ed, win) {
|
||||
info ("Preffing autocompletion off");
|
||||
Services.prefs.setBoolPref(AUTOCOMPLETION_PREF, false);
|
||||
|
||||
ed.setupAutoCompletion();
|
||||
|
||||
ok (ed.getOption("autocomplete"), "Autocompletion is still set");
|
||||
ok (!win.tern, "Tern is no longer defined on the window");
|
||||
|
||||
|
78
browser/devtools/sourceeditor/test/browser_editor_prefs.js
Normal file
78
browser/devtools/sourceeditor/test/browser_editor_prefs.js
Normal file
@ -0,0 +1,78 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test to make sure that the editor reacts to preference changes
|
||||
|
||||
const TAB_SIZE = "devtools.editor.tabsize";
|
||||
const EXPAND_TAB = "devtools.editor.expandtab";
|
||||
const KEYMAP = "devtools.editor.keymap";
|
||||
const AUTO_CLOSE = "devtools.editor.autoclosebrackets";
|
||||
const AUTOCOMPLETE = "devtools.editor.autocomplete";
|
||||
const DETECT_INDENT = "devtools.editor.detectindentation";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
setup((ed, win) => {
|
||||
|
||||
ed.setText("Checking preferences.");
|
||||
|
||||
info ("Turning prefs off");
|
||||
|
||||
ed.setOption("autocomplete", true);
|
||||
|
||||
Services.prefs.setIntPref(TAB_SIZE, 2);
|
||||
Services.prefs.setBoolPref(EXPAND_TAB, false);
|
||||
Services.prefs.setCharPref(KEYMAP, "default");
|
||||
Services.prefs.setBoolPref(AUTO_CLOSE, false);
|
||||
Services.prefs.setBoolPref(AUTOCOMPLETE, false);
|
||||
Services.prefs.setBoolPref(DETECT_INDENT, false);
|
||||
|
||||
is(ed.getOption("tabSize"), 2, "tabSize is correct");
|
||||
is(ed.getOption("indentUnit"), 2, "indentUnit is correct");
|
||||
is(ed.getOption("indentWithTabs"), true, "indentWithTabs is correct");
|
||||
is(ed.getOption("keyMap"), "default", "keyMap is correct");
|
||||
is(ed.getOption("autoCloseBrackets"), "", "autoCloseBrackets is correct");
|
||||
is(ed.getOption("autocomplete"), true, "autocomplete is correct");
|
||||
ok(!ed.isAutocompletionEnabled(), "Autocompletion is not enabled");
|
||||
|
||||
info ("Turning prefs on");
|
||||
|
||||
Services.prefs.setIntPref(TAB_SIZE, 4);
|
||||
Services.prefs.setBoolPref(EXPAND_TAB, true);
|
||||
Services.prefs.setCharPref(KEYMAP, "sublime");
|
||||
Services.prefs.setBoolPref(AUTO_CLOSE, true);
|
||||
Services.prefs.setBoolPref(AUTOCOMPLETE, true);
|
||||
|
||||
is(ed.getOption("tabSize"), 4, "tabSize is correct");
|
||||
is(ed.getOption("indentUnit"), 4, "indentUnit is correct");
|
||||
is(ed.getOption("indentWithTabs"), false, "indentWithTabs is correct");
|
||||
is(ed.getOption("keyMap"), "sublime", "keyMap is correct");
|
||||
is(ed.getOption("autoCloseBrackets"), "()[]{}''\"\"", "autoCloseBrackets is correct");
|
||||
is(ed.getOption("autocomplete"), true, "autocomplete is correct");
|
||||
ok(ed.isAutocompletionEnabled(), "Autocompletion is enabled");
|
||||
|
||||
info ("Checking indentation detection");
|
||||
|
||||
Services.prefs.setBoolPref(DETECT_INDENT, true);
|
||||
|
||||
ed.setText("Detecting\n\tTabs");
|
||||
is(ed.getOption("indentWithTabs"), true, "indentWithTabs is correct");
|
||||
is(ed.getOption("indentUnit"), 4, "indentUnit is correct");
|
||||
|
||||
ed.setText("body {\n color:red;\n a:b;\n}");
|
||||
is(ed.getOption("indentWithTabs"), false, "indentWithTabs is correct");
|
||||
is(ed.getOption("indentUnit"), 2, "indentUnit is correct");
|
||||
|
||||
Services.prefs.clearUserPref(TAB_SIZE);
|
||||
Services.prefs.clearUserPref(EXPAND_TAB);
|
||||
Services.prefs.clearUserPref(KEYMAP);
|
||||
Services.prefs.clearUserPref(AUTO_CLOSE);
|
||||
Services.prefs.clearUserPref(AUTOCOMPLETE);
|
||||
Services.prefs.clearUserPref(DETECT_INDENT);
|
||||
|
||||
teardown(ed, win);
|
||||
});
|
||||
}
|
@ -94,6 +94,8 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker) {
|
||||
this._onMediaRulesChanged = this._onMediaRulesChanged.bind(this)
|
||||
this.checkLinkedFileForChanges = this.checkLinkedFileForChanges.bind(this);
|
||||
this.markLinkedFileBroken = this.markLinkedFileBroken.bind(this);
|
||||
this.saveToFile = this.saveToFile.bind(this);
|
||||
this.updateStyleSheet = this.updateStyleSheet.bind(this);
|
||||
|
||||
this._focusOnSourceEditorReady = false;
|
||||
this.cssSheet.on("property-change", this._onPropertyChange);
|
||||
@ -347,23 +349,18 @@ StyleSheetEditor.prototype = {
|
||||
autoCloseBrackets: "{}()[]",
|
||||
extraKeys: this._getKeyBindings(),
|
||||
contextMenu: "sourceEditorContextMenu",
|
||||
autocomplete: Services.prefs.getBoolPref(AUTOCOMPLETION_PREF)
|
||||
autocomplete: Services.prefs.getBoolPref(AUTOCOMPLETION_PREF),
|
||||
autocompleteOpts: { walker: this.walker }
|
||||
};
|
||||
let sourceEditor = new Editor(config);
|
||||
let sourceEditor = this._sourceEditor = new Editor(config);
|
||||
|
||||
sourceEditor.on("dirty-change", this._onPropertyChange);
|
||||
|
||||
return sourceEditor.appendTo(inputElement).then(() => {
|
||||
sourceEditor.setupAutoCompletion({ walker: this.walker });
|
||||
|
||||
sourceEditor.on("save", () => {
|
||||
this.saveToFile();
|
||||
});
|
||||
sourceEditor.on("save", this.saveToFile);
|
||||
|
||||
if (this.styleSheet.update) {
|
||||
sourceEditor.on("change", () => {
|
||||
this.updateStyleSheet();
|
||||
});
|
||||
sourceEditor.on("change", this.updateStyleSheet);
|
||||
}
|
||||
|
||||
this.sourceEditor = sourceEditor;
|
||||
@ -631,8 +628,11 @@ StyleSheetEditor.prototype = {
|
||||
* Clean up for this editor.
|
||||
*/
|
||||
destroy: function() {
|
||||
if (this.sourceEditor) {
|
||||
this.sourceEditor.destroy();
|
||||
if (this._sourceEditor) {
|
||||
this._sourceEditor.off("dirty-change", this._onPropertyChange);
|
||||
this._sourceEditor.off("save", this.saveToFile);
|
||||
this._sourceEditor.off("change", this.updateStyleSheet);
|
||||
this._sourceEditor.destroy();
|
||||
}
|
||||
this.cssSheet.off("property-change", this._onPropertyChange);
|
||||
this.cssSheet.off("media-rules-changed", this._onMediaRulesChanged);
|
||||
|
@ -695,6 +695,7 @@ WebConsoleFrame.prototype = {
|
||||
}, this);
|
||||
|
||||
aButton.setAttribute("checked", someChecked);
|
||||
aButton.setAttribute("aria-pressed", someChecked);
|
||||
}, this);
|
||||
|
||||
if (!this.owner._browserConsole) {
|
||||
@ -834,12 +835,14 @@ WebConsoleFrame.prototype = {
|
||||
Array.forEach(buttons, (button) => {
|
||||
if (button !== target) {
|
||||
button.setAttribute("checked", false);
|
||||
button.setAttribute("aria-pressed", false);
|
||||
this._setMenuState(button, false);
|
||||
}
|
||||
});
|
||||
state = true;
|
||||
}
|
||||
target.setAttribute("checked", state);
|
||||
target.setAttribute("aria-pressed", state);
|
||||
|
||||
// This is a filter button with a drop-down, and the user clicked the
|
||||
// main part of the button. Go through all the severities and toggle
|
||||
@ -888,6 +891,7 @@ WebConsoleFrame.prototype = {
|
||||
}
|
||||
let toolbarButton = menuPopup.parentNode;
|
||||
toolbarButton.setAttribute("checked", someChecked);
|
||||
toolbarButton.setAttribute("aria-pressed", someChecked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ Cu.import("resource://gre/modules/Metrics.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
Cu.import("resource://testing-common/services/healthreport/utils.jsm");
|
||||
Cu.import("resource://testing-common/services-common/logging.js");
|
||||
Cu.import("resource://testing-common/services/common/logging.js");
|
||||
|
||||
const kMeasurementVersion = 2;
|
||||
|
||||
|
@ -83,6 +83,8 @@ _DEPRECATED_VARIABLES := \
|
||||
MOCHITEST_METRO_FILES \
|
||||
MOCHITEST_ROBOCOP_FILES \
|
||||
SHORT_LIBNAME \
|
||||
TESTING_JS_MODULES \
|
||||
TESTING_JS_MODULE_DIR \
|
||||
$(NULL)
|
||||
|
||||
ifndef EXTERNALLY_MANAGED_MAKE_FILE
|
||||
|
@ -1279,28 +1279,6 @@ PP_TARGETS += EXTRA_PP_JS_MODULES
|
||||
endif
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Copy testing-only JS modules to appropriate destination.
|
||||
#
|
||||
# For each file defined in TESTING_JS_MODULES, copy it to
|
||||
# objdir/_tests/modules/. If TESTING_JS_MODULE_DIR is defined, that path
|
||||
# wlll be appended to the output directory.
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
ifdef TESTING_JS_MODULES
|
||||
testmodulesdir = $(DEPTH)/_tests/modules/$(TESTING_JS_MODULE_DIR)
|
||||
|
||||
GENERATED_DIRS += $(testmodulesdir)
|
||||
|
||||
ifndef NO_DIST_INSTALL
|
||||
TESTING_JS_MODULES_FILES := $(TESTING_JS_MODULES)
|
||||
TESTING_JS_MODULES_DEST := $(testmodulesdir)
|
||||
INSTALL_TARGETS += TESTING_JS_MODULES
|
||||
endif
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# SDK
|
||||
|
||||
|
@ -277,16 +277,16 @@ public class GeckoView extends LayerView
|
||||
String hint = message.optString("hint");
|
||||
if ("alert".equals(hint)) {
|
||||
String text = message.optString("text");
|
||||
mChromeDelegate.onAlert(GeckoView.this, null, text, new PromptResult(message.optString("guid")));
|
||||
mChromeDelegate.onAlert(GeckoView.this, null, text, new PromptResult(message));
|
||||
} else if ("confirm".equals(hint)) {
|
||||
String text = message.optString("text");
|
||||
mChromeDelegate.onConfirm(GeckoView.this, null, text, new PromptResult(message.optString("guid")));
|
||||
mChromeDelegate.onConfirm(GeckoView.this, null, text, new PromptResult(message));
|
||||
} else if ("prompt".equals(hint)) {
|
||||
String text = message.optString("text");
|
||||
String defaultValue = message.optString("textbox0");
|
||||
mChromeDelegate.onPrompt(GeckoView.this, null, text, defaultValue, new PromptResult(message.optString("guid")));
|
||||
mChromeDelegate.onPrompt(GeckoView.this, null, text, defaultValue, new PromptResult(message));
|
||||
} else if ("remotedebug".equals(hint)) {
|
||||
mChromeDelegate.onDebugRequest(GeckoView.this, new PromptResult(message.optString("guid")));
|
||||
mChromeDelegate.onDebugRequest(GeckoView.this, new PromptResult(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -439,16 +439,15 @@ public class GeckoView extends LayerView
|
||||
private final int RESULT_OK = 0;
|
||||
private final int RESULT_CANCEL = 1;
|
||||
|
||||
private final String mGUID;
|
||||
private final JSONObject mMessage;
|
||||
|
||||
public PromptResult(String guid) {
|
||||
mGUID = guid;
|
||||
public PromptResult(JSONObject message) {
|
||||
mMessage = message;
|
||||
}
|
||||
|
||||
private JSONObject makeResult(int resultCode) {
|
||||
JSONObject result = new JSONObject();
|
||||
try {
|
||||
result.put("guid", mGUID);
|
||||
result.put("button", resultCode);
|
||||
} catch(JSONException ex) { }
|
||||
return result;
|
||||
@ -459,7 +458,7 @@ public class GeckoView extends LayerView
|
||||
*/
|
||||
public void confirm() {
|
||||
JSONObject result = makeResult(RESULT_OK);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString()));
|
||||
EventDispatcher.sendResponse(mMessage, result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -471,7 +470,7 @@ public class GeckoView extends LayerView
|
||||
try {
|
||||
result.put("textbox0", value);
|
||||
} catch(JSONException ex) { }
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString()));
|
||||
EventDispatcher.sendResponse(mMessage, result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,7 +478,7 @@ public class GeckoView extends LayerView
|
||||
*/
|
||||
public void cancel() {
|
||||
JSONObject result = makeResult(RESULT_CANCEL);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString()));
|
||||
EventDispatcher.sendResponse(mMessage, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,12 +216,8 @@ public class BrowserContract {
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined");
|
||||
|
||||
public static final int DISPLAY_NORMAL = 0;
|
||||
public static final int DISPLAY_READER = 1;
|
||||
|
||||
public static final String BOOKMARK_ID = "bookmark_id";
|
||||
public static final String HISTORY_ID = "history_id";
|
||||
public static final String DISPLAY = "display";
|
||||
}
|
||||
|
||||
public static final class Schema {
|
||||
@ -384,6 +380,10 @@ public class BrowserContract {
|
||||
private Combined() {}
|
||||
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String DISPLAY = "display";
|
||||
|
||||
public static final int DISPLAY_NORMAL = 0;
|
||||
public static final int DISPLAY_READER = 1;
|
||||
}
|
||||
|
||||
static final String TABLE_BOOKMARKS_JOIN_IMAGES = Bookmarks.TABLE_NAME + " LEFT OUTER JOIN " +
|
||||
|
@ -34,7 +34,7 @@ import android.util.Log;
|
||||
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String LOGTAG = "GeckoBrowserDBHelper";
|
||||
public static final int DATABASE_VERSION = 18;
|
||||
public static final int DATABASE_VERSION = 19;
|
||||
public static final String DATABASE_NAME = "browser.db";
|
||||
|
||||
final protected Context mContext;
|
||||
@ -349,7 +349,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Obsolete.Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
|
||||
@ -359,8 +359,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -378,8 +378,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -407,7 +407,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Obsolete.Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
|
||||
@ -417,8 +417,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -437,8 +437,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -466,7 +466,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Obsolete.Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " +
|
||||
qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL +
|
||||
@ -476,8 +476,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -495,12 +495,6 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
// customized the title for a bookmark.
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
|
||||
// Only use DISPLAY_READER if the matching bookmark entry inside reading
|
||||
// list folder is not marked as deleted.
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
|
||||
" THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -528,7 +522,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Obsolete.Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED +
|
||||
" FROM (" +
|
||||
// Bookmarks without history.
|
||||
@ -536,8 +530,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -551,16 +545,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
" SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
|
||||
// Prioritze bookmark titles over history titles, since the user may have
|
||||
// Prioritize bookmark titles over history titles, since the user may have
|
||||
// customized the title for a bookmark.
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
|
||||
// Only use DISPLAY_READER if the matching bookmark entry inside reading
|
||||
// list folder is not marked as deleted.
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
|
||||
" THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED +
|
||||
@ -596,7 +584,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Obsolete.Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED + ", " +
|
||||
Combined.FAVICON_ID +
|
||||
" FROM (" +
|
||||
@ -605,8 +593,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED + ", " +
|
||||
@ -629,8 +617,8 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
// list folder is not marked as deleted.
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
|
||||
" THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
" THEN " + Obsolete.Combined.DISPLAY_READER + " ELSE " + Obsolete.Combined.DISPLAY_NORMAL + " END ELSE " +
|
||||
Obsolete.Combined.DISPLAY_NORMAL + " END AS " + Obsolete.Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " +
|
||||
@ -653,73 +641,94 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
" ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID));
|
||||
}
|
||||
|
||||
private void createCombinedViewOn16(SQLiteDatabase db) {
|
||||
debug("Creating " + VIEW_COMBINED + " view");
|
||||
private void createCombinedViewOn19(SQLiteDatabase db) {
|
||||
/*
|
||||
The v19 combined view removes the redundant subquery from the v16
|
||||
combined view and reorders the columns as necessary to prevent this
|
||||
from breaking any code that might be referencing columns by index.
|
||||
|
||||
The rows in the ensuing view are, in order:
|
||||
|
||||
Combined.BOOKMARK_ID
|
||||
Combined.HISTORY_ID
|
||||
Combined._ID (always 0)
|
||||
Combined.URL
|
||||
Combined.TITLE
|
||||
Combined.VISITS
|
||||
Combined.DISPLAY
|
||||
Combined.DATE_LAST_VISITED
|
||||
Combined.FAVICON_ID
|
||||
|
||||
We need to return an _id column because CursorAdapter requires it for its
|
||||
default implementation for the getItemId() method. However, since
|
||||
we're not using this feature in the parts of the UI using this view,
|
||||
we can just use 0 for all rows.
|
||||
*/
|
||||
|
||||
db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" +
|
||||
" SELECT " + Combined.BOOKMARK_ID + ", " +
|
||||
Combined.HISTORY_ID + ", " +
|
||||
// We need to return an _id column because CursorAdapter requires it for its
|
||||
// default implementation for the getItemId() method. However, since
|
||||
// we're not using this feature in the parts of the UI using this view,
|
||||
// we can just use 0 for all rows.
|
||||
"0 AS " + Combined._ID + ", " +
|
||||
Combined.URL + ", " +
|
||||
Combined.TITLE + ", " +
|
||||
Combined.VISITS + ", " +
|
||||
Combined.DISPLAY + ", " +
|
||||
Combined.DATE_LAST_VISITED + ", " +
|
||||
Combined.FAVICON_ID +
|
||||
" FROM (" +
|
||||
// Bookmarks without history.
|
||||
" SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
"-1 AS " + Combined.HISTORY_ID + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
|
||||
" FROM " + TABLE_BOOKMARKS +
|
||||
" WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
|
||||
// Ignore pinned bookmarks.
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " <> " + Bookmarks.FIXED_PINNED_LIST_ID + " AND " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
|
||||
" NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
|
||||
" UNION ALL" +
|
||||
|
||||
// Bookmarks without history.
|
||||
" SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + "," +
|
||||
"-1 AS " + Combined.HISTORY_ID + "," +
|
||||
"0 AS " + Combined._ID + "," +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
|
||||
"-1 AS " + Combined.VISITS + ", " +
|
||||
"-1 AS " + Combined.DATE_LAST_VISITED + "," +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
|
||||
" FROM " + TABLE_BOOKMARKS +
|
||||
" WHERE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
|
||||
// Ignore pinned bookmarks.
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " <> " + Bookmarks.FIXED_PINNED_LIST_ID + " AND " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
|
||||
" NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
|
||||
" UNION ALL" +
|
||||
|
||||
// History with and without bookmark.
|
||||
" SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " +
|
||||
// Give pinned bookmarks a NULL ID so that they're not treated as bookmarks. We can't
|
||||
// completely ignore them here because they're joined with history entries we care about.
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " +
|
||||
Bookmarks.FIXED_PINNED_LIST_ID + " THEN NULL ELSE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " END " +
|
||||
"ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " +
|
||||
// Prioritize bookmark titles over history titles, since the user may have
|
||||
// customized the title for a bookmark.
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " +
|
||||
// Only use DISPLAY_READER if the matching bookmark entry inside reading
|
||||
// list folder is not marked as deleted.
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID +
|
||||
" THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " +
|
||||
Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
|
||||
" SELECT " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) +
|
||||
|
||||
// Give pinned bookmarks a NULL ID so that they're not treated as bookmarks. We can't
|
||||
// completely ignore them here because they're joined with history entries we care about.
|
||||
" WHEN 0 THEN " +
|
||||
"CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) +
|
||||
" WHEN " + Bookmarks.FIXED_PINNED_LIST_ID + " THEN " +
|
||||
"NULL " +
|
||||
"ELSE " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +
|
||||
" END " +
|
||||
"ELSE " +
|
||||
"NULL " +
|
||||
"END AS " + Combined.BOOKMARK_ID + "," +
|
||||
qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + "," +
|
||||
"0 AS " + Combined._ID + "," +
|
||||
qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + "," +
|
||||
|
||||
// Prioritize bookmark titles over history titles, since the user may have
|
||||
// customized the title for a bookmark.
|
||||
"COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
|
||||
qualifyColumn(TABLE_HISTORY, History.TITLE) +
|
||||
") AS " + Combined.TITLE + "," +
|
||||
qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + "," +
|
||||
qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + "," +
|
||||
qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID +
|
||||
|
||||
// We really shouldn't be selecting deleted bookmarks, but oh well.
|
||||
" FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS +
|
||||
" ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
|
||||
" WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " +
|
||||
qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ") " +
|
||||
")");
|
||||
" ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
|
||||
" WHERE " +
|
||||
qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND " +
|
||||
"(" +
|
||||
// The left outer join didn't match...
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
|
||||
|
||||
// ... or it's a bookmark. This is less efficient than filtering prior
|
||||
// to the join if you have lots of folders.
|
||||
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK +
|
||||
")"
|
||||
);
|
||||
|
||||
debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view");
|
||||
|
||||
@ -742,7 +751,7 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
createBookmarksWithFaviconsView(db);
|
||||
createHistoryWithFaviconsView(db);
|
||||
createCombinedViewOn16(db);
|
||||
createCombinedViewOn19(db);
|
||||
|
||||
createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
|
||||
R.string.bookmarks_folder_places, 0);
|
||||
@ -1298,10 +1307,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom15to16(SQLiteDatabase db) {
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
|
||||
|
||||
createCombinedViewOn16(db);
|
||||
// No harm in creating the v19 combined view here: means we don't need two almost-identical
|
||||
// functions to define both the v16 and v19 ones. The upgrade path will redundantly drop
|
||||
// and recreate the view again. *shrug*
|
||||
createV19CombinedView(db);
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom16to17(SQLiteDatabase db) {
|
||||
@ -1378,6 +1387,26 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom18to19(SQLiteDatabase db) {
|
||||
// Redefine the "combined" view...
|
||||
createV19CombinedView(db);
|
||||
|
||||
// Kill any history entries with NULL URL. This ostensibly can't happen...
|
||||
db.execSQL("DELETE FROM " + TABLE_HISTORY + " WHERE " + History.URL + " IS NULL");
|
||||
|
||||
// Similar for bookmark types. Replaces logic from the combined view, also shouldn't happen.
|
||||
db.execSQL("UPDATE " + TABLE_BOOKMARKS + " SET " +
|
||||
Bookmarks.TYPE + " = " + Bookmarks.TYPE_BOOKMARK +
|
||||
" WHERE " + Bookmarks.TYPE + " IS NULL");
|
||||
}
|
||||
|
||||
private void createV19CombinedView(SQLiteDatabase db) {
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
|
||||
|
||||
createCombinedViewOn19(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
debug("Upgrading browser.db: " + db.getPath() + " from " +
|
||||
@ -1454,6 +1483,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
case 18:
|
||||
upgradeDatabaseFrom17to18(db);
|
||||
break;
|
||||
|
||||
case 19:
|
||||
upgradeDatabaseFrom18to19(db);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1566,4 +1599,4 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
bookmark.remove("folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||
map.put(Combined._ID, Combined._ID);
|
||||
map.put(Combined.BOOKMARK_ID, Combined.BOOKMARK_ID);
|
||||
map.put(Combined.HISTORY_ID, Combined.HISTORY_ID);
|
||||
map.put(Combined.DISPLAY, "MAX(" + Combined.DISPLAY + ") AS " + Combined.DISPLAY);
|
||||
map.put(Combined.URL, Combined.URL);
|
||||
map.put(Combined.TITLE, Combined.TITLE);
|
||||
map.put(Combined.VISITS, Combined.VISITS);
|
||||
|
@ -526,7 +526,6 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
new String[] { Combined._ID,
|
||||
Combined.URL,
|
||||
Combined.TITLE,
|
||||
Combined.DISPLAY,
|
||||
Combined.BOOKMARK_ID,
|
||||
Combined.HISTORY_ID },
|
||||
constraint,
|
||||
@ -550,7 +549,6 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
new String[] { Combined._ID,
|
||||
Combined.URL,
|
||||
Combined.TITLE,
|
||||
Combined.DISPLAY,
|
||||
Combined.BOOKMARK_ID,
|
||||
Combined.HISTORY_ID },
|
||||
"",
|
||||
@ -639,7 +637,6 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
Combined.HISTORY_ID,
|
||||
Combined.URL,
|
||||
Combined.TITLE,
|
||||
Combined.DISPLAY,
|
||||
Combined.DATE_LAST_VISITED,
|
||||
Combined.VISITS },
|
||||
History.DATE_LAST_VISITED + " > 0",
|
||||
@ -783,16 +780,13 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
|
||||
@Override
|
||||
public boolean isBookmark(ContentResolver cr, String uri) {
|
||||
// This method is about normal bookmarks, not the Reading List.
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = cr.query(bookmarksUriWithLimit(1),
|
||||
new String[] { Bookmarks._ID },
|
||||
Bookmarks.URL + " = ? AND " +
|
||||
Bookmarks.PARENT + " != ? AND " +
|
||||
Bookmarks.PARENT + " != ?",
|
||||
new String[] { uri,
|
||||
String.valueOf(Bookmarks.FIXED_READING_LIST_ID),
|
||||
String.valueOf(Bookmarks.FIXED_PINNED_LIST_ID) },
|
||||
Bookmarks.URL);
|
||||
return c.getCount() > 0;
|
||||
@ -989,9 +983,8 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
// Do this now so that the items still exist!
|
||||
bumpParents(cr, Bookmarks.URL, uri);
|
||||
|
||||
// Toggling bookmark on an URL should not affect the items in the reading list or pinned sites.
|
||||
final String[] urlArgs = new String[] { uri, String.valueOf(Bookmarks.FIXED_READING_LIST_ID), String.valueOf(Bookmarks.FIXED_PINNED_LIST_ID) };
|
||||
final String urlEquals = Bookmarks.URL + " = ? AND " + Bookmarks.PARENT + " != ? AND " + Bookmarks.PARENT + " != ? ";
|
||||
final String[] urlArgs = new String[] { uri, String.valueOf(Bookmarks.FIXED_PINNED_LIST_ID) };
|
||||
final String urlEquals = Bookmarks.URL + " = ? AND " + Bookmarks.PARENT + " != ? ";
|
||||
|
||||
cr.delete(contentUri, urlEquals, urlArgs);
|
||||
}
|
||||
@ -1346,32 +1339,26 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
if (url != null) {
|
||||
// Bookmarks are defined by their URL and Folder.
|
||||
builder.withSelection(Bookmarks.URL + " = ? AND "
|
||||
+ Bookmarks.PARENT + " = ? AND "
|
||||
+ Bookmarks.PARENT + " != ?",
|
||||
+ Bookmarks.PARENT + " = ?",
|
||||
new String[] { url,
|
||||
Long.toString(parent),
|
||||
String.valueOf(Bookmarks.FIXED_READING_LIST_ID)
|
||||
Long.toString(parent)
|
||||
});
|
||||
} else if (title != null) {
|
||||
// Or their title and parent folder. (Folders!)
|
||||
builder.withSelection(Bookmarks.TITLE + " = ? AND "
|
||||
+ Bookmarks.PARENT + " = ? AND "
|
||||
+ Bookmarks.PARENT + " != ?",
|
||||
+ Bookmarks.PARENT + " = ?",
|
||||
new String[] { title,
|
||||
Long.toString(parent),
|
||||
String.valueOf(Bookmarks.FIXED_READING_LIST_ID)
|
||||
Long.toString(parent)
|
||||
});
|
||||
} else if (type == Bookmarks.TYPE_SEPARATOR) {
|
||||
// Or their their position (seperators)
|
||||
// Or their their position (separators)
|
||||
builder.withSelection(Bookmarks.POSITION + " = ? AND "
|
||||
+ Bookmarks.PARENT + " = ? AND "
|
||||
+ Bookmarks.PARENT + " != ?",
|
||||
+ Bookmarks.PARENT + " = ?",
|
||||
new String[] { Long.toString(position),
|
||||
Long.toString(parent),
|
||||
String.valueOf(Bookmarks.FIXED_READING_LIST_ID)
|
||||
Long.toString(parent)
|
||||
});
|
||||
} else {
|
||||
Log.e(LOGTAG, "Bookmark entry without url or title and not a seperator, not added.");
|
||||
Log.e(LOGTAG, "Bookmark entry without url or title and not a separator, not added.");
|
||||
}
|
||||
builder.withValues(values);
|
||||
|
||||
|
@ -111,7 +111,6 @@ public class HistoryPanel extends HomeFragment {
|
||||
final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id);
|
||||
info.url = cursor.getString(cursor.getColumnIndexOrThrow(Combined.URL));
|
||||
info.title = cursor.getString(cursor.getColumnIndexOrThrow(Combined.TITLE));
|
||||
info.display = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.DISPLAY));
|
||||
info.historyId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
|
||||
final int bookmarkIdCol = cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID);
|
||||
if (cursor.isNull(bookmarkIdCol)) {
|
||||
|
@ -21,7 +21,6 @@ public class HomeContextMenuInfo extends AdapterContextMenuInfo {
|
||||
public String url;
|
||||
public String title;
|
||||
public boolean isFolder = false;
|
||||
public int display = Combined.DISPLAY_NORMAL;
|
||||
public int historyId = -1;
|
||||
public int bookmarkId = -1;
|
||||
public int readingListItemId = -1;
|
||||
|
@ -98,7 +98,7 @@ abstract class HomeFragment extends Fragment {
|
||||
|
||||
menu.setHeaderTitle(info.getDisplayTitle());
|
||||
|
||||
// Hide ununsed menu items.
|
||||
// Hide unused menu items.
|
||||
menu.findItem(R.id.top_sites_edit).setVisible(false);
|
||||
menu.findItem(R.id.top_sites_pin).setVisible(false);
|
||||
menu.findItem(R.id.top_sites_unpin).setVisible(false);
|
||||
@ -117,9 +117,6 @@ abstract class HomeFragment extends Fragment {
|
||||
if (!StringUtils.isShareableUrl(info.url) || GeckoProfile.get(getActivity()).inGuestMode()) {
|
||||
menu.findItem(R.id.home_share).setVisible(false);
|
||||
}
|
||||
|
||||
final boolean canOpenInReader = (info.display == Combined.DISPLAY_READER);
|
||||
menu.findItem(R.id.home_open_in_reader).setVisible(canOpenInReader);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -226,12 +223,6 @@ abstract class HomeFragment extends Fragment {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == R.id.home_open_in_reader) {
|
||||
final String url = ReaderModeUtils.getAboutReaderForUrl(info.url);
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == R.id.home_remove) {
|
||||
if (info instanceof TopSitesGridContextMenuInfo) {
|
||||
(new RemoveItemByUrlTask(context, info.url, info.position)).execute();
|
||||
|
@ -279,8 +279,7 @@ public class TopSitesPanel extends HomeFragment {
|
||||
MenuInflater inflater = new MenuInflater(view.getContext());
|
||||
inflater.inflate(R.menu.home_contextmenu, menu);
|
||||
|
||||
// Hide ununsed menu items.
|
||||
menu.findItem(R.id.home_open_in_reader).setVisible(false);
|
||||
// Hide unused menu items.
|
||||
menu.findItem(R.id.home_edit_bookmark).setVisible(false);
|
||||
|
||||
TopSitesGridContextMenuInfo info = (TopSitesGridContextMenuInfo) menuInfo;
|
||||
|
@ -197,21 +197,11 @@ public class TwoLinePageRow extends LinearLayout
|
||||
final int bookmarkIdIndex = cursor.getColumnIndex(Combined.BOOKMARK_ID);
|
||||
if (bookmarkIdIndex != -1) {
|
||||
final long bookmarkId = cursor.getLong(bookmarkIdIndex);
|
||||
final int displayIndex = cursor.getColumnIndex(Combined.DISPLAY);
|
||||
|
||||
final int display;
|
||||
if (displayIndex != -1) {
|
||||
display = cursor.getInt(displayIndex);
|
||||
} else {
|
||||
display = Combined.DISPLAY_NORMAL;
|
||||
}
|
||||
|
||||
// The bookmark id will be 0 (null in database) when the url
|
||||
// is not a bookmark.
|
||||
if (bookmarkId == 0) {
|
||||
setPageTypeIcon(NO_ICON);
|
||||
} else if (display == Combined.DISPLAY_READER) {
|
||||
setPageTypeIcon(R.drawable.ic_url_bar_reader);
|
||||
} else {
|
||||
setPageTypeIcon(R.drawable.ic_url_bar_star);
|
||||
}
|
||||
|
@ -280,7 +280,6 @@ size. -->
|
||||
|
||||
<!ENTITY contextmenu_open_new_tab "Open in New Tab">
|
||||
<!ENTITY contextmenu_open_private_tab "Open in Private Tab">
|
||||
<!ENTITY contextmenu_open_in_reader "Open in Reader">
|
||||
<!ENTITY contextmenu_remove "Remove">
|
||||
<!ENTITY contextmenu_add_to_launcher "Add to Home Screen">
|
||||
<!ENTITY contextmenu_share "Share">
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
package org.mozilla.gecko.preferences;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.mozilla.gecko.BrowserLocaleManager;
|
||||
@ -27,7 +26,6 @@ import android.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/* A simple implementation of PreferenceFragment for large screen devices
|
||||
* This will strip category headers (so that they aren't shown to the user twice)
|
||||
@ -198,29 +196,4 @@ public class GeckoPreferenceFragment extends PreferenceFragment {
|
||||
PrefsHelper.removeObserver(mPrefsRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
showOverflowMenu(activity);
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the overflow 3-dot menu to be displayed if it isn't already displayed.
|
||||
*
|
||||
* This is an ugly hack for 4.0+ Android devices that don't have a dedicated menu button
|
||||
* because Android does not provide a public API to display the ActionBar overflow menu.
|
||||
*/
|
||||
private void showOverflowMenu(Activity activity) {
|
||||
try {
|
||||
ViewConfiguration config = ViewConfiguration.get(activity);
|
||||
Field menuOverflow = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
|
||||
if (menuOverflow != null) {
|
||||
menuOverflow.setAccessible(true);
|
||||
menuOverflow.setBoolean(config, false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(LOGTAG, "Failed to force overflow menu, ignoring.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/restore_defaults"
|
||||
android:title="@string/pref_search_restore_defaults" />
|
||||
|
||||
<item android:id="@+id/restore_defaults"
|
||||
android:drawable="@drawable/menu"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/pref_search_restore_defaults" />
|
||||
</menu>
|
||||
|
@ -11,9 +11,6 @@
|
||||
<item android:id="@+id/home_open_private_tab"
|
||||
android:title="@string/contextmenu_open_private_tab"/>
|
||||
|
||||
<item android:id="@+id/home_open_in_reader"
|
||||
android:title="@string/contextmenu_open_in_reader"/>
|
||||
|
||||
<item android:id="@+id/home_copyurl"
|
||||
android:title="@string/contextmenu_copyurl"/>
|
||||
|
||||
|
@ -274,7 +274,6 @@
|
||||
|
||||
<string name="contextmenu_open_new_tab">&contextmenu_open_new_tab;</string>
|
||||
<string name="contextmenu_open_private_tab">&contextmenu_open_private_tab;</string>
|
||||
<string name="contextmenu_open_in_reader">&contextmenu_open_in_reader;</string>
|
||||
<string name="contextmenu_remove">&contextmenu_remove;</string>
|
||||
<string name="contextmenu_add_to_launcher">&contextmenu_add_to_launcher;</string>
|
||||
<string name="contextmenu_share">&contextmenu_share;</string>
|
||||
|
@ -38,8 +38,15 @@ class RemoteTabsList extends ExpandableListView
|
||||
private final Context context;
|
||||
private TabsPanel tabsPanel;
|
||||
|
||||
private ArrayList <HashMap <String, String>> clients;
|
||||
private ArrayList <ArrayList <HashMap <String, String>>> tabsList;
|
||||
|
||||
// A list of the clients that are currently expanded.
|
||||
private List<String> expandedClientList = new ArrayList<String>();
|
||||
|
||||
// The client that previously had an item selected is used to restore the scroll position.
|
||||
private String clientScrollPosition;
|
||||
|
||||
public RemoteTabsList(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.context = context;
|
||||
@ -57,8 +64,18 @@ class RemoteTabsList extends ExpandableListView
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGroupClick(ExpandableListView parent, View view, int position, long id) {
|
||||
// By default, the group collapses/expands. Consume the event.
|
||||
public boolean onGroupClick(ExpandableListView parent, View view, int groupPosition, long id) {
|
||||
final String clientGuid = clients.get(groupPosition).get("guid");
|
||||
|
||||
if (isGroupExpanded(groupPosition)) {
|
||||
collapseGroup(groupPosition);
|
||||
expandedClientList.remove(clientGuid);
|
||||
} else {
|
||||
expandGroup(groupPosition);
|
||||
expandedClientList.add(clientGuid);
|
||||
}
|
||||
|
||||
clientScrollPosition = clientGuid;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -74,6 +91,8 @@ class RemoteTabsList extends ExpandableListView
|
||||
|
||||
Tabs.getInstance().loadUrl(tab.get("url"), Tabs.LOADURL_NEW_TAB);
|
||||
autoHidePanel();
|
||||
|
||||
clientScrollPosition = clients.get(groupPosition).get("guid");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -83,8 +102,7 @@ class RemoteTabsList extends ExpandableListView
|
||||
if (remoteTabs == null || remoteTabs.size() == 0)
|
||||
return;
|
||||
|
||||
ArrayList <HashMap <String, String>> clients = new ArrayList <HashMap <String, String>>();
|
||||
|
||||
clients = new ArrayList <HashMap <String, String>>();
|
||||
tabsList = new ArrayList <ArrayList <HashMap <String, String>>>();
|
||||
|
||||
String oldGuid = null;
|
||||
@ -95,16 +113,18 @@ class RemoteTabsList extends ExpandableListView
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
for (TabsAccessor.RemoteTab remoteTab : remoteTabs) {
|
||||
if (oldGuid == null || !TextUtils.equals(oldGuid, remoteTab.guid)) {
|
||||
final String clientGuid = remoteTab.guid;
|
||||
if (oldGuid == null || !TextUtils.equals(oldGuid, clientGuid)) {
|
||||
client = new HashMap <String, String>();
|
||||
client.put("name", remoteTab.name);
|
||||
client.put("last_synced", getLastSyncedString(now, remoteTab.lastModified));
|
||||
client.put("guid", clientGuid);
|
||||
clients.add(client);
|
||||
|
||||
tabsForClient = new ArrayList <HashMap <String, String>>();
|
||||
tabsList.add(tabsForClient);
|
||||
|
||||
oldGuid = new String(remoteTab.guid);
|
||||
oldGuid = new String(clientGuid);
|
||||
}
|
||||
|
||||
tab = new HashMap<String, String>();
|
||||
@ -123,9 +143,20 @@ class RemoteTabsList extends ExpandableListView
|
||||
TAB_KEY,
|
||||
TAB_RESOURCE));
|
||||
|
||||
// Expand the client groups, and restore the previous scroll position.
|
||||
List<String> newExpandedClientList = new ArrayList<String>();
|
||||
for (int i = 0; i < clients.size(); i++) {
|
||||
expandGroup(i);
|
||||
final String clientGuid = clients.get(i).get("guid");
|
||||
if (expandedClientList.contains(clientGuid)) {
|
||||
newExpandedClientList.add(clientGuid);
|
||||
expandGroup(i);
|
||||
}
|
||||
|
||||
if (clientGuid.equals(clientScrollPosition)) {
|
||||
setSelectedGroup(i);
|
||||
}
|
||||
}
|
||||
expandedClientList = newExpandedClientList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ package org.mozilla.gecko.tests;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
import org.mozilla.gecko.background.db.CursorDumper;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
@ -251,7 +252,6 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mTests.add(new TestCombinedView());
|
||||
mTests.add(new TestCombinedViewDisplay());
|
||||
mTests.add(new TestCombinedViewWithDeletedBookmark());
|
||||
mTests.add(new TestCombinedViewWithDeletedReadingListItem());
|
||||
mTests.add(new TestExpireHistory());
|
||||
|
||||
mTests.add(new TestBrowserProviderNotifications());
|
||||
@ -454,21 +454,18 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
BrowserContract.Bookmarks.GUID + " = ? OR " +
|
||||
BrowserContract.Bookmarks.GUID + " = ? OR " +
|
||||
BrowserContract.Bookmarks.GUID + " = ? OR " +
|
||||
BrowserContract.Bookmarks.GUID + " = ? OR " +
|
||||
BrowserContract.Bookmarks.GUID + " = ?",
|
||||
new String[] { BrowserContract.Bookmarks.PLACES_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.MOBILE_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.MENU_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.TAGS_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.TOOLBAR_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.UNFILED_FOLDER_GUID,
|
||||
BrowserContract.Bookmarks.READING_LIST_FOLDER_GUID },
|
||||
BrowserContract.Bookmarks.UNFILED_FOLDER_GUID},
|
||||
null);
|
||||
|
||||
mAsserter.is(c.getCount(), 7, "Right number of special folders");
|
||||
mAsserter.is(c.getCount(), 6, "Right number of special folders");
|
||||
|
||||
int rootId = BrowserContract.Bookmarks.FIXED_ROOT_ID;
|
||||
int readingListId = BrowserContract.Bookmarks.FIXED_READING_LIST_ID;
|
||||
|
||||
while (c.moveToNext()) {
|
||||
int id = c.getInt(c.getColumnIndex(BrowserContract.Bookmarks._ID));
|
||||
@ -476,12 +473,10 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
int parentId = c.getInt(c.getColumnIndex(BrowserContract.Bookmarks.PARENT));
|
||||
|
||||
if (guid.equals(BrowserContract.Bookmarks.PLACES_FOLDER_GUID)) {
|
||||
mAsserter.is(new Integer(id), new Integer(rootId), "The id of places folder is correct");
|
||||
} else if (guid.equals(BrowserContract.Bookmarks.READING_LIST_FOLDER_GUID)) {
|
||||
mAsserter.is(new Integer(id), new Integer(readingListId), "The id of reading list folder is correct");
|
||||
mAsserter.is(id, rootId, "The id of places folder is correct");
|
||||
}
|
||||
|
||||
mAsserter.is(new Integer(parentId), new Integer(rootId),
|
||||
mAsserter.is(parentId, rootId,
|
||||
"The PARENT of the " + guid + " special folder is correct");
|
||||
}
|
||||
|
||||
@ -506,61 +501,66 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
public void test() throws Exception {
|
||||
ContentValues b = createOneBookmark();
|
||||
long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||
Cursor c = getBookmarkById(id);
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
||||
final Cursor c = getBookmarkById(id);
|
||||
try {
|
||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
||||
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TITLE)), b.getAsString(BrowserContract.Bookmarks.TITLE),
|
||||
"Inserted bookmark has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), b.getAsString(BrowserContract.Bookmarks.URL),
|
||||
"Inserted bookmark has correct URL");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TAGS)), b.getAsString(BrowserContract.Bookmarks.TAGS),
|
||||
"Inserted bookmark has correct tags");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.KEYWORD)), b.getAsString(BrowserContract.Bookmarks.KEYWORD),
|
||||
"Inserted bookmark has correct keyword");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.DESCRIPTION)), b.getAsString(BrowserContract.Bookmarks.DESCRIPTION),
|
||||
"Inserted bookmark has correct description");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.POSITION)), b.getAsString(BrowserContract.Bookmarks.POSITION),
|
||||
"Inserted bookmark has correct position");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), b.getAsString(BrowserContract.Bookmarks.TYPE),
|
||||
"Inserted bookmark has correct type");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.PARENT)), b.getAsString(BrowserContract.Bookmarks.PARENT),
|
||||
"Inserted bookmark has correct parent ID");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.IS_DELETED)), String.valueOf(0),
|
||||
"Inserted bookmark has correct is-deleted state");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TITLE)), b.getAsString(BrowserContract.Bookmarks.TITLE),
|
||||
"Inserted bookmark has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), b.getAsString(BrowserContract.Bookmarks.URL),
|
||||
"Inserted bookmark has correct URL");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TAGS)), b.getAsString(BrowserContract.Bookmarks.TAGS),
|
||||
"Inserted bookmark has correct tags");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.KEYWORD)), b.getAsString(BrowserContract.Bookmarks.KEYWORD),
|
||||
"Inserted bookmark has correct keyword");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.DESCRIPTION)), b.getAsString(BrowserContract.Bookmarks.DESCRIPTION),
|
||||
"Inserted bookmark has correct description");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.POSITION)), b.getAsString(BrowserContract.Bookmarks.POSITION),
|
||||
"Inserted bookmark has correct position");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), b.getAsString(BrowserContract.Bookmarks.TYPE),
|
||||
"Inserted bookmark has correct type");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.PARENT)), b.getAsString(BrowserContract.Bookmarks.PARENT),
|
||||
"Inserted bookmark has correct parent ID");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.IS_DELETED)), String.valueOf(0),
|
||||
"Inserted bookmark has correct is-deleted state");
|
||||
|
||||
id = insertWithNullCol(BrowserContract.Bookmarks.POSITION);
|
||||
mAsserter.is(new Long(id), new Long(-1),
|
||||
"Should not be able to insert bookmark with null position");
|
||||
id = insertWithNullCol(BrowserContract.Bookmarks.POSITION);
|
||||
mAsserter.is(id, -1L,
|
||||
"Should not be able to insert bookmark with null position");
|
||||
|
||||
id = insertWithNullCol(BrowserContract.Bookmarks.TYPE);
|
||||
mAsserter.is(new Long(id), new Long(-1),
|
||||
"Should not be able to insert bookmark with null type");
|
||||
id = insertWithNullCol(BrowserContract.Bookmarks.TYPE);
|
||||
mAsserter.is(id, -1L,
|
||||
"Should not be able to insert bookmark with null type");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 8 &&
|
||||
Build.VERSION.SDK_INT < 16) {
|
||||
b = createOneBookmark();
|
||||
b.put(BrowserContract.Bookmarks.PARENT, -1);
|
||||
id = -1;
|
||||
|
||||
try {
|
||||
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||
} catch (Exception e) {}
|
||||
|
||||
mAsserter.is(id, -1L,
|
||||
"Should not be able to insert bookmark with invalid parent");
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 8 &&
|
||||
Build.VERSION.SDK_INT < 16) {
|
||||
b = createOneBookmark();
|
||||
b.put(BrowserContract.Bookmarks.PARENT, -1);
|
||||
id = -1;
|
||||
|
||||
b.remove(BrowserContract.Bookmarks.TYPE);
|
||||
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||
final Cursor c2 = getBookmarkById(id);
|
||||
try {
|
||||
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||
} catch (Exception e) {}
|
||||
|
||||
mAsserter.is(new Long(id), new Long(-1),
|
||||
"Should not be able to insert bookmark with invalid parent");
|
||||
mAsserter.is(c2.moveToFirst(), true, "Inserted bookmark found");
|
||||
mAsserter.is(c2.getString(c2.getColumnIndex(BrowserContract.Bookmarks.TYPE)), String.valueOf(BrowserContract.Bookmarks.TYPE_BOOKMARK),
|
||||
"Inserted bookmark has correct default type");
|
||||
} finally {
|
||||
c2.close();
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
b = createOneBookmark();
|
||||
b.remove(BrowserContract.Bookmarks.TYPE);
|
||||
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||
c = getBookmarkById(id);
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
||||
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), String.valueOf(BrowserContract.Bookmarks.TYPE_BOOKMARK),
|
||||
"Inserted bookmark has correct default type");
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -755,12 +755,12 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), u.getAsString(BrowserContract.Bookmarks.TYPE),
|
||||
"Inserted bookmark has correct type");
|
||||
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_CREATED))),
|
||||
new Long(dateCreated),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_CREATED)),
|
||||
dateCreated,
|
||||
"Updated bookmark has same creation date");
|
||||
|
||||
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_MODIFIED))),
|
||||
new Long(dateModified),
|
||||
mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_MODIFIED)),
|
||||
dateModified,
|
||||
"Updated bookmark has new modification date");
|
||||
|
||||
updated = updateWithNullCol(id, BrowserContract.Bookmarks.POSITION);
|
||||
@ -948,11 +948,11 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
"Inserted history entry has correct is-deleted state");
|
||||
|
||||
id = insertWithNullCol(BrowserContract.History.URL);
|
||||
mAsserter.is(new Long(id), new Long(-1),
|
||||
mAsserter.is(id, -1L,
|
||||
"Should not be able to insert history with null URL");
|
||||
|
||||
id = insertWithNullCol(BrowserContract.History.VISITS);
|
||||
mAsserter.is(new Long(id), new Long(-1),
|
||||
mAsserter.is(id, -1L,
|
||||
"Should not be able to insert history with null number of visits");
|
||||
c.close();
|
||||
}
|
||||
@ -1112,12 +1112,12 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.DATE_LAST_VISITED)), u.getAsString(BrowserContract.History.DATE_LAST_VISITED),
|
||||
"Updated history entry has correct last visited date");
|
||||
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED))),
|
||||
new Long(dateCreated),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)),
|
||||
dateCreated,
|
||||
"Updated history entry has same creation date");
|
||||
|
||||
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED))),
|
||||
new Long(dateModified),
|
||||
mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)),
|
||||
dateModified,
|
||||
"Updated history entry has new modification date");
|
||||
|
||||
updated = updateWithNullCol(id, BrowserContract.History.URL);
|
||||
@ -1228,7 +1228,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
long dateCreated = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED));
|
||||
long dateModified = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED));
|
||||
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS))), new Long(1),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 1L,
|
||||
"Inserted history entry has correct default number of visits");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_URL_1,
|
||||
"Inserted history entry has correct default title");
|
||||
@ -1249,11 +1249,11 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
|
||||
"Updated history entry has correct title");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS))), new Long(2),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 2L,
|
||||
"Updated history entry has correct number of visits");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED))), new Long(dateCreated),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)), dateCreated,
|
||||
"Updated history entry has same creation date");
|
||||
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED))), new Long(dateModified),
|
||||
mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)), dateModified,
|
||||
"Updated history entry has new modification date");
|
||||
|
||||
// Create a new history entry, specifying visits and history
|
||||
@ -1276,7 +1276,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
dateCreated = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED));
|
||||
dateModified = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED));
|
||||
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS))), new Long(10),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 10L,
|
||||
"Inserted history entry has correct specified number of visits");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
|
||||
"Inserted history entry has correct specified title");
|
||||
@ -1298,11 +1298,11 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
"Updated history entry has correct unchanged title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), TEST_URL_2,
|
||||
"Updated history entry has correct unchanged URL");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS))), new Long(20),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 20L,
|
||||
"Updated history entry has correct number of visits");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED))), new Long(dateCreated),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)), dateCreated,
|
||||
"Updated history entry has same creation date");
|
||||
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED))), new Long(dateModified),
|
||||
mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)), dateModified,
|
||||
"Updated history entry has new modification date");
|
||||
c.close();
|
||||
|
||||
@ -1433,66 +1433,69 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, folderBookmark);
|
||||
|
||||
// Sort entries by url so we can check them individually
|
||||
Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, BrowserContract.Combined.URL);
|
||||
final Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, BrowserContract.Combined.URL);
|
||||
|
||||
mAsserter.is(c.getCount(), 3, "3 combined entries found");
|
||||
|
||||
// First combined entry is basic history entry
|
||||
mAsserter.is(c.moveToFirst(), true, "Found basic history entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID))), new Long(0),
|
||||
"Combined _id column should always be 0");
|
||||
// TODO: Should we change BrowserProvider to make this return -1, not 0?
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(0),
|
||||
"Bookmark id should be 0 for basic history entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID))), new Long(basicHistoryId),
|
||||
"Basic history entry has correct history id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_1,
|
||||
"Basic history entry has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_1,
|
||||
"Basic history entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
|
||||
"Basic history entry has correct number of visits");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED))), new Long(LAST_VISITED),
|
||||
"Basic history entry has correct last visit time");
|
||||
|
||||
// Second combined entry is basic bookmark entry
|
||||
mAsserter.is(c.moveToNext(), true, "Found basic bookmark entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID))), new Long(0),
|
||||
"Combined _id column should always be 0");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(basicBookmarkId),
|
||||
"Basic bookmark entry has correct bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID))), new Long(-1),
|
||||
"History id should be -1 for basic bookmark entry");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_2,
|
||||
"Basic bookmark entry has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_2,
|
||||
"Basic bookmark entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), -1,
|
||||
"Visits should be -1 for basic bookmark entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED))), new Long(-1),
|
||||
"Basic entry has correct last visit time");
|
||||
|
||||
// Third combined entry is a combined history/bookmark entry
|
||||
mAsserter.is(c.moveToNext(), true, "Found third combined entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID))), new Long(0),
|
||||
"Combined _id column should always be 0");
|
||||
// The bookmark data (bookmark_id and title) associated with the combined entry is non-deterministic,
|
||||
// it might end up with data coming from any of the matching bookmark entries.
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId ||
|
||||
c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId2, true,
|
||||
"Combined entry has correct bookmark id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK) ||
|
||||
c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK2), true,
|
||||
"Combined entry has title corresponding to bookmark entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID))), new Long(combinedHistoryId),
|
||||
"Combined entry has correct history id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_3,
|
||||
"Combined entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
|
||||
"Combined entry has correct number of visits");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED))), new Long(LAST_VISITED),
|
||||
"Combined entry has correct last visit time");
|
||||
c.close();
|
||||
try {
|
||||
mAsserter.is(c.getCount(), 3, "3 combined entries found");
|
||||
|
||||
// First combined entry is basic history entry
|
||||
mAsserter.is(c.moveToFirst(), true, "Found basic history entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
|
||||
"Combined _id column should always be 0");
|
||||
// TODO: Should we change BrowserProvider to make this return -1, not 0?
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), 0L,
|
||||
"Bookmark id should be 0 for basic history entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), basicHistoryId,
|
||||
"Basic history entry has correct history id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_1,
|
||||
"Basic history entry has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_1,
|
||||
"Basic history entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
|
||||
"Basic history entry has correct number of visits");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), LAST_VISITED,
|
||||
"Basic history entry has correct last visit time");
|
||||
|
||||
// Second combined entry is basic bookmark entry
|
||||
mAsserter.is(c.moveToNext(), true, "Found basic bookmark entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
|
||||
"Combined _id column should always be 0");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), basicBookmarkId,
|
||||
"Basic bookmark entry has correct bookmark id");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), -1L,
|
||||
"History id should be -1 for basic bookmark entry");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_2,
|
||||
"Basic bookmark entry has correct title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_2,
|
||||
"Basic bookmark entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), -1,
|
||||
"Visits should be -1 for basic bookmark entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), -1L,
|
||||
"Basic entry has correct last visit time");
|
||||
|
||||
// Third combined entry is a combined history/bookmark entry
|
||||
mAsserter.is(c.moveToNext(), true, "Found third combined entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
|
||||
"Combined _id column should always be 0");
|
||||
// The bookmark data (bookmark_id and title) associated with the combined entry is non-deterministic,
|
||||
// it might end up with data coming from any of the matching bookmark entries.
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId ||
|
||||
c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId2, true,
|
||||
"Combined entry has correct bookmark id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK) ||
|
||||
c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK2), true,
|
||||
"Combined entry has title corresponding to bookmark entry");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), combinedHistoryId,
|
||||
"Combined entry has correct history id");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_3,
|
||||
"Combined entry has correct url");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
|
||||
"Combined entry has correct number of visits");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), LAST_VISITED,
|
||||
"Combined entry has correct last visit time");
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1503,12 +1506,10 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
final String TITLE_2 = "Test Page 2";
|
||||
final String TITLE_3_HISTORY = "Test Page 3 (History Entry)";
|
||||
final String TITLE_3_BOOKMARK = "Test Page 3 (Bookmark Entry)";
|
||||
final String TITLE_4 = "Test Page 4";
|
||||
|
||||
final String URL_1 = "http://example.com";
|
||||
final String URL_2 = "http://example.org";
|
||||
final String URL_3 = "http://examples2.com";
|
||||
final String URL_4 = "http://readinglist.com";
|
||||
|
||||
final int VISITS = 10;
|
||||
final long LAST_VISITED = System.currentTimeMillis();
|
||||
@ -1531,29 +1532,12 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
||||
mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedBookmark);
|
||||
|
||||
// Create a reading list entries
|
||||
int readingListId = BrowserContract.Bookmarks.FIXED_READING_LIST_ID;
|
||||
ContentValues readingListItem = createBookmark(TITLE_3_BOOKMARK, URL_3, readingListId,
|
||||
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
||||
long readingListItemId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, readingListItem));
|
||||
|
||||
ContentValues readingListItem2 = createBookmark(TITLE_4, URL_4, readingListId,
|
||||
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
||||
long readingListItemId2 = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, readingListItem2));
|
||||
|
||||
Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||
mAsserter.is(c.getCount(), 4, "4 combined entries found");
|
||||
|
||||
while (c.moveToNext()) {
|
||||
long id = c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID));
|
||||
|
||||
int display = c.getInt(c.getColumnIndex(BrowserContract.Combined.DISPLAY));
|
||||
int expectedDisplay = (id == readingListItemId || id == readingListItemId2 ? BrowserContract.Combined.DISPLAY_READER : BrowserContract.Combined.DISPLAY_NORMAL);
|
||||
|
||||
mAsserter.is(new Integer(display), new Integer(expectedDisplay),
|
||||
"Combined display column should always be DISPLAY_READER for the reading list item");
|
||||
final Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||
try {
|
||||
mAsserter.is(c.getCount(), 3, "3 combined entries found");
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1578,7 +1562,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Found combined entry with bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(combinedBookmarkId),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), combinedBookmarkId,
|
||||
"Bookmark id should be set correctly on combined entry");
|
||||
|
||||
int deleted = mProvider.delete(BrowserContract.Bookmarks.CONTENT_URI,
|
||||
@ -1592,58 +1576,12 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Found combined entry without bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(0),
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), 0L,
|
||||
"Bookmark id should not be set to removed bookmark id");
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestCombinedViewWithDeletedReadingListItem extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
final String TITLE = "Test Page 1";
|
||||
final String URL = "http://example.com";
|
||||
final int VISITS = 10;
|
||||
final long LAST_VISITED = System.currentTimeMillis();
|
||||
|
||||
// Create a combined history entry
|
||||
ContentValues combinedHistory = createHistoryEntry(TITLE, URL, VISITS, LAST_VISITED);
|
||||
mProvider.insert(BrowserContract.History.CONTENT_URI, combinedHistory);
|
||||
|
||||
// Create a combined bookmark entry
|
||||
int readingListId = BrowserContract.Bookmarks.FIXED_READING_LIST_ID;
|
||||
ContentValues combinedReadingListItem = createBookmark(TITLE, URL, readingListId,
|
||||
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
||||
long combinedReadingListItemId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedReadingListItem));
|
||||
|
||||
Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Found combined entry with bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(combinedReadingListItemId),
|
||||
"Bookmark id should be set correctly on combined entry");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DISPLAY))), new Long(BrowserContract.Combined.DISPLAY_READER),
|
||||
"Combined entry should have reader display type");
|
||||
|
||||
int deleted = mProvider.delete(BrowserContract.Bookmarks.CONTENT_URI,
|
||||
BrowserContract.Bookmarks._ID + " = ?",
|
||||
new String[] { String.valueOf(combinedReadingListItemId) });
|
||||
|
||||
mAsserter.is((deleted == 1), true, "Inserted combined reading list item was deleted");
|
||||
c.close();
|
||||
|
||||
c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||
|
||||
mAsserter.is(c.moveToFirst(), true, "Found combined entry without bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(0),
|
||||
"Bookmark id should not be set to removed bookmark id");
|
||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DISPLAY))), new Long(BrowserContract.Combined.DISPLAY_NORMAL),
|
||||
"Combined entry should have reader display type");
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestExpireHistory extends TestCase {
|
||||
private void createFakeHistory(long timeShift, int count) {
|
||||
// Insert a bunch of very new entries
|
||||
@ -1778,8 +1716,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
Log.w(LOGTAG, "after operation, notifyChangeList = " + mResolver.notifyChangeList);
|
||||
}
|
||||
|
||||
mAsserter.is(Long.valueOf(mResolver.notifyChangeList.size()),
|
||||
Long.valueOf(1),
|
||||
mAsserter.is((long) mResolver.notifyChangeList.size(),
|
||||
1L,
|
||||
"Content observer was notified exactly once by " + operation);
|
||||
|
||||
Uri uri = mResolver.notifyChangeList.poll();
|
||||
@ -1801,8 +1739,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mResolver.notifyChangeList.clear();
|
||||
long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
|
||||
|
||||
mAsserter.isnot(Long.valueOf(id),
|
||||
Long.valueOf(-1),
|
||||
mAsserter.isnot(id,
|
||||
-1L,
|
||||
"Inserted item has valid id");
|
||||
|
||||
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "insert");
|
||||
@ -1815,8 +1753,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
BrowserContract.History._ID + " = ?",
|
||||
new String[] { String.valueOf(id) });
|
||||
|
||||
mAsserter.is(Long.valueOf(numUpdated),
|
||||
Long.valueOf(1),
|
||||
mAsserter.is(numUpdated,
|
||||
1L,
|
||||
"Correct number of items are updated");
|
||||
|
||||
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "update");
|
||||
@ -1825,8 +1763,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mResolver.notifyChangeList.clear();
|
||||
long numDeleted = mProvider.delete(BrowserContract.History.CONTENT_URI, null, null);
|
||||
|
||||
mAsserter.is(Long.valueOf(numDeleted),
|
||||
Long.valueOf(1),
|
||||
mAsserter.is(numDeleted,
|
||||
1L,
|
||||
"Correct number of items are deleted");
|
||||
|
||||
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "delete");
|
||||
@ -1837,8 +1775,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
||||
mResolver.notifyChangeList.clear();
|
||||
long numBulkInserted = mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, hs);
|
||||
|
||||
mAsserter.is(Long.valueOf(numBulkInserted),
|
||||
Long.valueOf(1),
|
||||
mAsserter.is(numBulkInserted,
|
||||
1L,
|
||||
"Correct number of items are bulkInserted");
|
||||
|
||||
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "bulkInsert");
|
||||
|
BIN
mobile/android/branding/aurora/res/drawable-xxxhdpi/icon.png
Normal file
BIN
mobile/android/branding/aurora/res/drawable-xxxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
mobile/android/branding/beta/res/drawable-xxxhdpi/icon.png
Normal file
BIN
mobile/android/branding/beta/res/drawable-xxxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
mobile/android/branding/nightly/res/drawable-xxxhdpi/icon.png
Normal file
BIN
mobile/android/branding/nightly/res/drawable-xxxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
BIN
mobile/android/branding/official/res/drawable-xxxhdpi/icon.png
Normal file
BIN
mobile/android/branding/official/res/drawable-xxxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
@ -916,14 +916,16 @@ SessionStore.prototype = {
|
||||
|
||||
let closedTabs = this._windows[aWindow.__SSID].closedTabs;
|
||||
|
||||
let tabs = closedTabs.map(function (tab) {
|
||||
// Get the url and title for the last entry in the session history.
|
||||
let lastEntry = tab.entries[tab.entries.length - 1];
|
||||
return {
|
||||
url: lastEntry.url,
|
||||
title: lastEntry.title || ""
|
||||
};
|
||||
});
|
||||
let tabs = closedTabs
|
||||
.filter(tab => !tab.isPrivate)
|
||||
.map(function (tab) {
|
||||
// Get the url and title for the last entry in the session history.
|
||||
let lastEntry = tab.entries[tab.entries.length - 1];
|
||||
return {
|
||||
url: lastEntry.url,
|
||||
title: lastEntry.title || ""
|
||||
};
|
||||
});
|
||||
|
||||
sendMessageToJava({
|
||||
type: "ClosedTabs:Data",
|
||||
|
@ -22,7 +22,6 @@ public class TestTopSitesCursorWrapper extends BrowserTestCase {
|
||||
private String[] TOP_SITES_COLUMNS = new String[] { Combined._ID,
|
||||
Combined.URL,
|
||||
Combined.TITLE,
|
||||
Combined.DISPLAY,
|
||||
Combined.BOOKMARK_ID,
|
||||
Combined.HISTORY_ID };
|
||||
|
||||
@ -49,7 +48,6 @@ public class TestTopSitesCursorWrapper extends BrowserTestCase {
|
||||
row.add(-1);
|
||||
row.add(TOP_PREFIX + "url" + i);
|
||||
row.add(TOP_PREFIX + "title" + i);
|
||||
row.add(Combined.DISPLAY_NORMAL);
|
||||
row.add(i);
|
||||
row.add(i);
|
||||
}
|
||||
|
@ -14,5 +14,3 @@ EXTRA_COMPONENTS += \
|
||||
httpd.manifest \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
TESTING_JS_MODULES = httpd.js
|
||||
|
@ -16,4 +16,8 @@ EXTRA_COMPONENTS += [
|
||||
'httpd.js',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
TESTING_JS_MODULES += [
|
||||
'httpd.js',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -36,6 +36,7 @@ from ..frontend.data import (
|
||||
IPDLFile,
|
||||
JARManifest,
|
||||
JavaJarData,
|
||||
JavaScriptModules,
|
||||
LibraryDefinition,
|
||||
LocalInclude,
|
||||
PerSourceFlag,
|
||||
@ -450,6 +451,9 @@ class RecursiveMakeBackend(CommonBackend):
|
||||
elif isinstance(obj, InstallationTarget):
|
||||
self._process_installation_target(obj, backend_file)
|
||||
|
||||
elif isinstance(obj, JavaScriptModules):
|
||||
self._process_javascript_modules(obj, backend_file)
|
||||
|
||||
elif isinstance(obj, SandboxWrapped):
|
||||
# Process a rich build system object from the front-end
|
||||
# as-is. Please follow precedent and handle CamelCaseData
|
||||
@ -969,6 +973,20 @@ class RecursiveMakeBackend(CommonBackend):
|
||||
if not obj.enabled:
|
||||
backend_file.write('NO_DIST_INSTALL := 1\n')
|
||||
|
||||
def _process_javascript_modules(self, obj, backend_file):
|
||||
if obj.flavor != 'testing':
|
||||
raise Exception('We only support testing JavaScriptModules instances.')
|
||||
|
||||
if not self.environment.substs.get('ENABLE_TESTS', False):
|
||||
return
|
||||
|
||||
manifest = self._install_manifests['tests']
|
||||
|
||||
def onmodule(source, dest, flags):
|
||||
manifest.add_symlink(source, mozpath.join('modules', dest))
|
||||
|
||||
self._process_hierarchy(obj, obj.modules, '', onmodule)
|
||||
|
||||
def _handle_idl_manager(self, manager):
|
||||
build_files = self._install_manifests['xpidl']
|
||||
|
||||
|
@ -506,6 +506,21 @@ class JARManifest(SandboxDerived):
|
||||
self.path = path
|
||||
|
||||
|
||||
class JavaScriptModules(SandboxDerived):
|
||||
"""Describes a JavaScript module."""
|
||||
|
||||
__slots__ = (
|
||||
'modules',
|
||||
'flavor',
|
||||
)
|
||||
|
||||
def __init__(self, sandbox, modules, flavor):
|
||||
super(JavaScriptModules, self).__init__(sandbox)
|
||||
|
||||
self.modules = modules
|
||||
self.flavor = flavor
|
||||
|
||||
|
||||
class SandboxWrapped(SandboxDerived):
|
||||
"""Generic sandbox container object for a wrapped rich object.
|
||||
|
||||
|
@ -33,6 +33,7 @@ from .data import (
|
||||
InstallationTarget,
|
||||
IPDLFile,
|
||||
JARManifest,
|
||||
JavaScriptModules,
|
||||
LibraryDefinition,
|
||||
LocalInclude,
|
||||
PerSourceFlag,
|
||||
@ -349,6 +350,10 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
for program in sandbox['HOST_SIMPLE_PROGRAMS']:
|
||||
yield HostSimpleProgram(sandbox, program, sandbox['CONFIG']['HOST_BIN_SUFFIX'])
|
||||
|
||||
test_js_modules = sandbox.get('TESTING_JS_MODULES')
|
||||
if test_js_modules:
|
||||
yield JavaScriptModules(sandbox, test_js_modules, 'testing')
|
||||
|
||||
simple_lists = [
|
||||
('GENERATED_EVENTS_WEBIDL_FILES', GeneratedEventWebIDLFile),
|
||||
('GENERATED_WEBIDL_FILES', GeneratedWebIDLFile),
|
||||
|
@ -210,6 +210,18 @@ VARIABLES = {
|
||||
``JS_MODULES_PATH`` defaults to ``modules`` if left undefined.
|
||||
""", 'libs'),
|
||||
|
||||
'TESTING_JS_MODULES': (HierarchicalStringList, list,
|
||||
"""JavaScript modules to install in the test-only destination.
|
||||
|
||||
Some JavaScript modules (JSMs) are test-only and not distributed
|
||||
with Firefox. This variable defines them.
|
||||
|
||||
To install modules in a subdirectory, use properties of this
|
||||
variable to control the final destination. e.g.
|
||||
|
||||
``TESTING_JS_MODULES.foo += ['module.jsm']``.
|
||||
""", 'libs'),
|
||||
|
||||
'EXTRA_PP_COMPONENTS': (StrictOrderingOnAppendList, list,
|
||||
"""Javascript XPCOM files.
|
||||
|
||||
|
@ -18,13 +18,6 @@ pp_modules := \
|
||||
rest.js \
|
||||
$(NULL)
|
||||
|
||||
testing_modules := \
|
||||
bagheeraserver.js \
|
||||
logging.js \
|
||||
storageserver.js \
|
||||
utils.js \
|
||||
$(NULL)
|
||||
|
||||
JS_EXPORTS_FILES := $(srcdir)/services-common.js
|
||||
JS_EXPORTS_DEST = $(FINAL_TARGET)/$(PREF_DIR)
|
||||
INSTALL_TARGETS += JS_EXPORTS
|
||||
@ -33,9 +26,6 @@ MODULES_FILES := $(modules)
|
||||
MODULES_DEST = $(FINAL_TARGET)/modules/services-common
|
||||
INSTALL_TARGETS += MODULES
|
||||
|
||||
TESTING_JS_MODULES := $(addprefix modules-testing/,$(testing_modules))
|
||||
TESTING_JS_MODULE_DIR := services-common
|
||||
|
||||
PP_JS_MODULES := $(pp_modules)
|
||||
PP_JS_MODULES_PATH = $(FINAL_TARGET)/modules/services-common
|
||||
PP_TARGETS += PP_JS_MODULES
|
||||
|
@ -9,3 +9,10 @@ TEST_DIRS += ['tests']
|
||||
EXTRA_COMPONENTS += [
|
||||
'servicesComponents.manifest',
|
||||
]
|
||||
|
||||
TESTING_JS_MODULES.services.common += [
|
||||
'modules-testing/bagheeraserver.js',
|
||||
'modules-testing/logging.js',
|
||||
'modules-testing/storageserver.js',
|
||||
'modules-testing/utils.js',
|
||||
]
|
||||
|
@ -12,7 +12,7 @@
|
||||
* $ make bagheera-server
|
||||
*/
|
||||
|
||||
Cu.import("resource://testing-common/services-common/bagheeraserver.js");
|
||||
Cu.import("resource://testing-common/services/common/bagheeraserver.js");
|
||||
|
||||
initTestLogging();
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
* $ make storage-server
|
||||
*/
|
||||
|
||||
Cu.import("resource://testing-common/services-common/storageserver.js");
|
||||
Cu.import("resource://testing-common/services/common/storageserver.js");
|
||||
|
||||
initTestLogging();
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://testing-common/services-common/logging.js");
|
||||
Cu.import("resource://testing-common/services/common/logging.js");
|
||||
|
||||
let btoa = Cu.import("resource://gre/modules/Log.jsm").btoa;
|
||||
let atob = Cu.import("resource://gre/modules/Log.jsm").atob;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Cu.import("resource://services-common/bagheeraclient.js");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://testing-common/services-common/bagheeraserver.js");
|
||||
Cu.import("resource://testing-common/services/common/bagheeraserver.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/services-common/bagheeraserver.js");
|
||||
Cu.import("resource://testing-common/services/common/bagheeraserver.js");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
|
@ -24,7 +24,7 @@ function run_test() {
|
||||
}
|
||||
|
||||
for each (let m in test_modules) {
|
||||
let resource = "resource://testing-common/services-common/" + m;
|
||||
let resource = "resource://testing-common/services/common/" + m;
|
||||
Components.utils.import(resource, {});
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://testing-common/services-common/storageserver.js");
|
||||
Cu.import("resource://testing-common/services/common/storageserver.js");
|
||||
|
||||
const DEFAULT_USER = "123";
|
||||
const DEFAULT_PASSWORD = "password";
|
||||
|
@ -2,7 +2,7 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://services-common/storageservice.js");
|
||||
Cu.import("resource://testing-common/services-common/storageserver.js");
|
||||
Cu.import("resource://testing-common/services/common/storageserver.js");
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://testing-common/services-common/utils.js");
|
||||
Cu.import("resource://testing-common/services/common/utils.js");
|
||||
|
||||
function run_test() {
|
||||
let thing = {o: {foo: "foo", bar: ["bar"]}, a: ["foo", {bar: "bar"}]};
|
||||
|
@ -6,9 +6,6 @@ MODULES := policy.jsm sessions.jsm
|
||||
MODULES_PATH = $(FINAL_TARGET)/modules/services/datareporting
|
||||
PP_TARGETS += MODULES
|
||||
|
||||
TESTING_JS_MODULES := $(addprefix modules-testing/,mocks.jsm)
|
||||
TESTING_JS_MODULE_DIR := services/datareporting
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
$(FINAL_TARGET)/components/DataReportingService.js: policy.jsm sessions.jsm ../common/observers.js
|
||||
|
@ -13,3 +13,7 @@ EXTRA_COMPONENTS += [
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'DataReportingService.js',
|
||||
]
|
||||
|
||||
TESTING_JS_MODULES.services.datareporting += [
|
||||
'modules-testing/mocks.jsm',
|
||||
]
|
||||
|
@ -8,7 +8,7 @@ do_get_profile();
|
||||
|
||||
(function initTestingInfrastructure() {
|
||||
let ns = {};
|
||||
Components.utils.import("resource://testing-common/services-common/logging.js",
|
||||
Components.utils.import("resource://testing-common/services/common/logging.js",
|
||||
ns);
|
||||
|
||||
ns.initTestLogging();
|
||||
|
@ -11,7 +11,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
do_get_profile();
|
||||
|
||||
let ns = {};
|
||||
Cu.import("resource://testing-common/services-common/logging.js", ns);
|
||||
Cu.import("resource://testing-common/services/common/logging.js", ns);
|
||||
|
||||
ns.initTestLogging("Trace");
|
||||
}).call(this);
|
||||
|
@ -8,10 +8,6 @@ modules := \
|
||||
providers.jsm \
|
||||
$(NULL)
|
||||
|
||||
testing_modules := \
|
||||
utils.jsm \
|
||||
$(NULL)
|
||||
|
||||
healthreport_depends = \
|
||||
HealthReport.jsm \
|
||||
../common/async.js \
|
||||
@ -36,9 +32,6 @@ MODULES_PATH = $(FINAL_TARGET)/modules/services/healthreport
|
||||
MODULES_FLAGS := $(extra_pp_flags)
|
||||
PP_TARGETS += MODULES
|
||||
|
||||
TESTING_JS_MODULES := $(addprefix modules-testing/,$(testing_modules))
|
||||
TESTING_JS_MODULE_DIR := services/healthreport
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Add extra prerequisites until bug 837792 is addressed.
|
||||
|
@ -11,3 +11,7 @@ TEST_DIRS += ['tests']
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'HealthReportComponents.manifest',
|
||||
]
|
||||
|
||||
TESTING_JS_MODULES.services.healthreport += [
|
||||
'modules-testing/utils.jsm',
|
||||
]
|
||||
|
@ -8,7 +8,7 @@ do_get_profile();
|
||||
|
||||
(function initMetricsTestingInfrastructure() {
|
||||
let ns = {};
|
||||
Components.utils.import("resource://testing-common/services-common/logging.js",
|
||||
Components.utils.import("resource://testing-common/services/common/logging.js",
|
||||
ns);
|
||||
|
||||
ns.initTestLogging();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user