зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c
This commit is contained in:
Коммит
8730e90647
|
@ -920,3 +920,9 @@ pref("browser.autofocus", false);
|
|||
|
||||
// Enable wakelock
|
||||
pref("dom.wakelock.enabled", true);
|
||||
|
||||
// Enable sync and mozId with Firefox Accounts.
|
||||
#ifdef MOZ_SERVICES_FXACCOUNTS
|
||||
pref("services.sync.fxaccounts.enabled", true);
|
||||
pref("identity.fxaccounts.enabled", true);
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@ if CONFIG['ENABLE_MARIONETTE']:
|
|||
|
||||
DEFINES['XPCOM_GLUE'] = True
|
||||
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'):
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER', 'MOZ_SERVICES_FXACCOUNTS'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
GENERATED_INCLUDES += [
|
||||
|
|
|
@ -23,7 +23,10 @@ Cu.import('resource://gre/modules/NetworkStatsService.jsm');
|
|||
// Identity
|
||||
Cu.import('resource://gre/modules/SignInToWebsite.jsm');
|
||||
SignInToWebsiteController.init();
|
||||
|
||||
#ifdef MOZ_SERVICES_FXACCOUNTS
|
||||
Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm');
|
||||
#endif
|
||||
|
||||
Cu.import('resource://gre/modules/DownloadsAPI.jsm');
|
||||
|
||||
|
|
|
@ -72,9 +72,11 @@ component {637b0f77-2429-49a0-915f-abf5d0db8b9a} WebappsUpdateTimer.js
|
|||
contract @mozilla.org/b2g/webapps-update-timer;1 {637b0f77-2429-49a0-915f-abf5d0db8b9a}
|
||||
category update-timer WebappsUpdateTimer @mozilla.org/b2g/webapps-update-timer;1,getService,background-update-timer,webapps.update.interval,86400
|
||||
|
||||
#ifdef MOZ_SERVICES_FXACCOUNTS
|
||||
# FxAccountsUIGlue.js
|
||||
component {51875c14-91d7-4b8c-b65d-3549e101228c} FxAccountsUIGlue.js
|
||||
contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3549e101228c}
|
||||
#endif
|
||||
|
||||
# HelperAppDialog.js
|
||||
component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
|
||||
|
|
|
@ -13,7 +13,6 @@ EXTRA_COMPONENTS += [
|
|||
'ContentHandler.js',
|
||||
'ContentPermissionPrompt.js',
|
||||
'FilePicker.js',
|
||||
'FxAccountsUIGlue.js',
|
||||
'HelperAppDialog.js',
|
||||
'MailtoProtocolHandler.js',
|
||||
'PaymentGlue.js',
|
||||
|
@ -37,8 +36,15 @@ if CONFIG['MOZ_UPDATER']:
|
|||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ErrorPage.jsm',
|
||||
'FxAccountsMgmtService.jsm',
|
||||
'SignInToWebsite.jsm',
|
||||
'TelURIParser.jsm',
|
||||
'WebappsUpdater.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SERVICES_FXACCOUNTS']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'FxAccountsUIGlue.js'
|
||||
]
|
||||
EXTRA_JS_MODULES += [
|
||||
'FxAccountsMgmtService.jsm'
|
||||
]
|
||||
|
|
|
@ -63,3 +63,5 @@ fi
|
|||
MOZ_FOLD_LIBS=1
|
||||
|
||||
MOZ_JSDOWNLOADS=1
|
||||
|
||||
MOZ_SERVICES_FXACCOUNTS=1
|
||||
|
|
|
@ -783,16 +783,18 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
|||
@BINPATH@/components/TelProtocolHandler.js
|
||||
@BINPATH@/components/B2GAboutRedirector.js
|
||||
@BINPATH@/components/FilePicker.js
|
||||
@BINPATH@/components/FxAccountsUIGlue.js
|
||||
@BINPATH@/components/HelperAppDialog.js
|
||||
@BINPATH@/components/DownloadsUI.js
|
||||
|
||||
#ifdef MOZ_SERVICES_FXACCOUNTS
|
||||
@BINPATH@/components/FxAccountsUIGlue.js
|
||||
@BINPATH@/components/services_fxaccounts.xpt
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
||||
@BINPATH@/components/services_fxaccounts.xpt
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
@BINPATH@/components/dom_webspeechsynth.xpt
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@ MOZ_DISABLE_EXPORT_JS=1
|
|||
MOZ_SAFE_BROWSING=1
|
||||
MOZ_SERVICES_COMMON=1
|
||||
MOZ_SERVICES_CRYPTO=1
|
||||
MOZ_SERVICES_FXACCOUNTS=1
|
||||
MOZ_SERVICES_HEALTHREPORT=1
|
||||
MOZ_SERVICES_METRICS=1
|
||||
MOZ_SERVICES_SYNC=1
|
||||
|
@ -67,4 +68,3 @@ MOZ_JSDOWNLOADS=1
|
|||
MOZ_WEBM_ENCODER=1
|
||||
# Enable exact rooting on desktop.
|
||||
JSGC_USE_EXACT_ROOTING=1
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
var ProfilerController = devtools.require("devtools/profiler/controller");
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ const {Cu} = require("chrome");
|
|||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var promise = require("sdk/core/promise");
|
||||
var {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
var EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
var Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
|
||||
var promise = require("sdk/core/promise");
|
||||
var EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
|
||||
let promise = require("sdk/core/promise");
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
||||
|
||||
|
@ -217,6 +215,7 @@ WindowHost.prototype = {
|
|||
|
||||
let frameLoad = function(event) {
|
||||
win.removeEventListener("load", frameLoad, true);
|
||||
win.focus();
|
||||
this.frame = win.document.getElementById("toolbox-iframe");
|
||||
this.emit("ready", this.frame);
|
||||
|
||||
|
@ -226,8 +225,6 @@ WindowHost.prototype = {
|
|||
win.addEventListener("load", frameLoad, true);
|
||||
win.addEventListener("unload", this._boundUnload);
|
||||
|
||||
win.focus();
|
||||
|
||||
this._window = win;
|
||||
|
||||
return deferred.promise;
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
"use strict";
|
||||
|
||||
const {Cu, Cc, Ci} = require("chrome");
|
||||
|
||||
let promise = require("sdk/core/promise");
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ const MIN_ZOOM = 0.5;
|
|||
const MAX_ZOOM = 2;
|
||||
|
||||
let {Cc, Ci, Cu} = require("chrome");
|
||||
let promise = require("sdk/core/promise");
|
||||
let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
let HUDService = require("devtools/webconsole/hudservice");
|
||||
|
@ -1433,20 +1433,20 @@ ToolboxHighlighterUtils.prototype = {
|
|||
* @return a promise that resolves when the highlighter is hidden
|
||||
*/
|
||||
unhighlight: function(forceHide=false) {
|
||||
if (this.isRemoteHighlightable) {
|
||||
// If the remote highlighter exists on the target, use it
|
||||
return this.toolbox.initInspector().then(() => {
|
||||
let autohide = forceHide || !gDevTools.testing;
|
||||
let unhighlightPromise;
|
||||
forceHide = forceHide || !gDevTools.testing;
|
||||
|
||||
if (autohide) {
|
||||
return this.toolbox.highlighter.hideBoxModel();
|
||||
}
|
||||
return promise.resolve();
|
||||
});
|
||||
if (forceHide && this.isRemoteHighlightable && this.toolbox.highlighter) {
|
||||
// If the remote highlighter exists on the target, use it
|
||||
unhighlightPromise = this.toolbox.highlighter.hideBoxModel();
|
||||
} else {
|
||||
// If not, no need to unhighlight as the older highlight method uses a
|
||||
// setTimeout to hide itself
|
||||
return promise.resolve();
|
||||
unhighlightPromise = promise.resolve();
|
||||
}
|
||||
|
||||
return unhighlightPromise.then(() => {
|
||||
this.toolbox.emit("node-unhighlight");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -692,8 +692,10 @@ HTMLBreadcrumbs.prototype = {
|
|||
|
||||
// Make sure the selected node and its neighbours are visible.
|
||||
this.scroll();
|
||||
this.inspector.emit("breadcrumbs-updated", this.selection.nodeFront);
|
||||
doneUpdating();
|
||||
return resolveNextTick().then(() => {
|
||||
this.inspector.emit("breadcrumbs-updated", this.selection.nodeFront);
|
||||
doneUpdating();
|
||||
});
|
||||
}).then(null, err => {
|
||||
doneUpdating(this.selection.nodeFront);
|
||||
this.selectionGuardEnd(err);
|
||||
|
|
|
@ -470,9 +470,8 @@ InspectorPanel.prototype = {
|
|||
*/
|
||||
destroy: function InspectorPanel__destroy() {
|
||||
if (this._panelDestroyer) {
|
||||
return this._panelDestroyer.promise;
|
||||
return this._panelDestroyer;
|
||||
}
|
||||
this._panelDestroyer = promise.defer();
|
||||
|
||||
if (this.walker) {
|
||||
this.walker.off("new-root", this.onNewRoot);
|
||||
|
@ -506,7 +505,7 @@ InspectorPanel.prototype = {
|
|||
this.selection.off("before-new-node", this.onBeforeNewSelection);
|
||||
this.selection.off("before-new-node-front", this.onBeforeNewSelection);
|
||||
this.selection.off("detached-front", this.onDetached);
|
||||
this._destroyMarkup();
|
||||
this._panelDestroyer = this._destroyMarkup();
|
||||
this.panelWin.inspector = null;
|
||||
this.target = null;
|
||||
this.panelDoc = null;
|
||||
|
@ -517,8 +516,7 @@ InspectorPanel.prototype = {
|
|||
this.nodemenu = null;
|
||||
this._toolbox = null;
|
||||
|
||||
this._panelDestroyer.resolve(null);
|
||||
return this._panelDestroyer.promise;
|
||||
return this._panelDestroyer;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -643,14 +641,18 @@ InspectorPanel.prototype = {
|
|||
},
|
||||
|
||||
_destroyMarkup: function InspectorPanel__destroyMarkup() {
|
||||
let destroyPromise;
|
||||
|
||||
if (this._boundMarkupFrameLoad) {
|
||||
this._markupFrame.removeEventListener("load", this._boundMarkupFrameLoad, true);
|
||||
this._boundMarkupFrameLoad = null;
|
||||
}
|
||||
|
||||
if (this.markup) {
|
||||
this.markup.destroy();
|
||||
destroyPromise = this.markup.destroy();
|
||||
this.markup = null;
|
||||
} else {
|
||||
destroyPromise = promise.resolve();
|
||||
}
|
||||
|
||||
if (this._markupFrame) {
|
||||
|
@ -659,6 +661,8 @@ InspectorPanel.prototype = {
|
|||
}
|
||||
|
||||
this._markupBox = null;
|
||||
|
||||
return destroyPromise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,9 @@ function test()
|
|||
let nodes;
|
||||
let cursor;
|
||||
let inspector;
|
||||
let target;
|
||||
let panel;
|
||||
let container;
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
|
@ -43,6 +46,9 @@ function test()
|
|||
function runTests(aInspector)
|
||||
{
|
||||
inspector = aInspector;
|
||||
target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
panel = gDevTools.getToolbox(target).getPanel("inspector");
|
||||
container = panel.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
cursor = 0;
|
||||
inspector.on("breadcrumbs-updated", nodeSelected);
|
||||
executeSoon(function() {
|
||||
|
@ -69,9 +75,6 @@ function test()
|
|||
|
||||
function performTest()
|
||||
{
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let panel = gDevTools.getToolbox(target).getPanel("inspector");
|
||||
let container = panel.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
let buttonsLabelIds = nodes[cursor].result.split(" ");
|
||||
|
||||
// html > body > …
|
||||
|
|
|
@ -39,7 +39,7 @@ function createDocument() {
|
|||
inspector = aInspector;
|
||||
markupView = inspector.markup;
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", function() {
|
||||
waitForView("ruleview", () => {
|
||||
ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
inspector.sidebar.select("ruleview");
|
||||
startTests();
|
||||
|
|
|
@ -21,7 +21,8 @@ function test() {
|
|||
let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
let inlineStyles = ruleview._elementStyle.rules[0];
|
||||
|
||||
for each (let prop in inlineStyles.textProps) {
|
||||
for (let key in inlineStyles.textProps) {
|
||||
let prop = inlineStyles.textProps[key];
|
||||
if (prop.name == aName) {
|
||||
return prop;
|
||||
}
|
||||
|
@ -32,7 +33,8 @@ function test() {
|
|||
function runInspectorTests(aInspector)
|
||||
{
|
||||
inspector = aInspector;
|
||||
inspector.sidebar.once("computedview-ready", () => {
|
||||
|
||||
waitForView("computedview", () => {
|
||||
info("Computed View ready");
|
||||
inspector.sidebar.select("computedview");
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ function createDocument()
|
|||
function selectNode(aInspector)
|
||||
{
|
||||
inspector = aInspector;
|
||||
inspector.sidebar.once("ruleview-ready", function() {
|
||||
|
||||
waitForView("ruleview", () => {
|
||||
ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
inspector.sidebar.select("ruleview");
|
||||
inspector.selection.setNode(div, "test");
|
||||
|
|
|
@ -202,6 +202,15 @@ function getComputedView() {
|
|||
return inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
}
|
||||
|
||||
function waitForView(aName, aCallback) {
|
||||
let inspector = getActiveInspector();
|
||||
if (inspector.sidebar.getTab(aName)) {
|
||||
aCallback();
|
||||
} else {
|
||||
inspector.sidebar.once(aName + "-ready", aCallback);
|
||||
}
|
||||
}
|
||||
|
||||
function synthesizeKeyFromKeyTag(aKeyId) {
|
||||
let key = document.getElementById(aKeyId);
|
||||
isnot(key, null, "Successfully retrieved the <key> node");
|
||||
|
|
|
@ -177,7 +177,7 @@ MarkupView.prototype = {
|
|||
},
|
||||
|
||||
_hideBoxModel: function(forceHide) {
|
||||
this._inspector.toolbox.highlighterUtils.unhighlight(forceHide);
|
||||
return this._inspector.toolbox.highlighterUtils.unhighlight(forceHide);
|
||||
},
|
||||
|
||||
_briefBoxModelTimer: null,
|
||||
|
@ -1044,9 +1044,13 @@ MarkupView.prototype = {
|
|||
* Tear down the markup panel.
|
||||
*/
|
||||
destroy: function() {
|
||||
if (this._destroyer) {
|
||||
return this._destroyer;
|
||||
}
|
||||
|
||||
// Note that if the toolbox is closed, this will work fine, but will fail
|
||||
// in case the browser is closed and will trigger a noSuchActor message.
|
||||
this._hideBoxModel();
|
||||
this._destroyer = this._hideBoxModel();
|
||||
|
||||
this._hoveredNode = null;
|
||||
this._inspector.toolbox.off("picker-node-hovered", this._onToolboxPickerHover);
|
||||
|
@ -1100,6 +1104,8 @@ MarkupView.prototype = {
|
|||
|
||||
this.tooltip.destroy();
|
||||
this.tooltip = null;
|
||||
|
||||
return this._destroyer;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,7 +53,7 @@ function test() {
|
|||
|
||||
instance.setSize(500, 500);
|
||||
|
||||
openComputedView(onInspectorUIOpen);
|
||||
openView("computedview", onInspectorUIOpen);
|
||||
}
|
||||
|
||||
function onInspectorUIOpen(aInspector, aComputedView) {
|
||||
|
|
|
@ -49,7 +49,7 @@ function test() {
|
|||
|
||||
instance.setSize(500, 500);
|
||||
|
||||
openRuleView(onInspectorUIOpen);
|
||||
openView("ruleview", onInspectorUIOpen);
|
||||
}
|
||||
|
||||
function onInspectorUIOpen(aInspector, aRuleView) {
|
||||
|
|
|
@ -23,23 +23,19 @@ function openInspector(callback)
|
|||
});
|
||||
}
|
||||
|
||||
function openComputedView(callback)
|
||||
function openView(name, callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("computedview-ready", () => {
|
||||
inspector.sidebar.select("computedview");
|
||||
let ruleView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
callback(inspector, ruleView);
|
||||
})
|
||||
});
|
||||
}
|
||||
function openRuleView(callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("ruleview-ready", () => {
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
callback(inspector, ruleView);
|
||||
})
|
||||
function onReady() {
|
||||
inspector.sidebar.select(name);
|
||||
let { view } = inspector.sidebar.getWindowForTab(name)[name];
|
||||
callback(inspector, view);
|
||||
}
|
||||
|
||||
if (inspector.sidebar.getTab(name)) {
|
||||
onReady();
|
||||
} else {
|
||||
inspector.sidebar.once(name + "-ready", onReady);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ function test() {
|
|||
function createDocument() {
|
||||
contentDoc.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
openRuleView((aInspector, aRuleView) => {
|
||||
openView("ruleview", (aInspector, aRuleView) => {
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
inspector.sidebar.once("computedview-ready", () => {
|
||||
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
openView("computedview", (_, aComputedView) => {
|
||||
computedView = aComputedView;
|
||||
startTests();
|
||||
});
|
||||
});
|
||||
|
@ -66,7 +66,6 @@ function testComputedView() {
|
|||
info("Testing computed view tooltip closes on new selection");
|
||||
|
||||
inspector.sidebar.select("computedview");
|
||||
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
|
||||
// Show the computed view tooltip
|
||||
let tooltip = computedView.tooltip;
|
||||
|
|
|
@ -47,7 +47,7 @@ function highlightNode()
|
|||
// Highlight a node.
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
|
||||
inspector.selection.setNode(div);
|
||||
inspector.selection.setNode(div, "test");
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, div, "selection matches the div element");
|
||||
testRuleViewLink();
|
||||
|
|
|
@ -65,26 +65,31 @@ function getActiveInspector()
|
|||
return gDevTools.getToolbox(target).getPanel("inspector");
|
||||
}
|
||||
|
||||
function openRuleView(callback)
|
||||
function openView(name, callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("ruleview-ready", () => {
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
callback(inspector, ruleView);
|
||||
})
|
||||
function onReady() {
|
||||
inspector.sidebar.select(name);
|
||||
let { view } = inspector.sidebar.getWindowForTab(name)[name];
|
||||
callback(inspector, view);
|
||||
}
|
||||
|
||||
if (inspector.sidebar.getTab(name)) {
|
||||
onReady();
|
||||
} else {
|
||||
inspector.sidebar.once(name + "-ready", onReady);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openRuleView(callback)
|
||||
{
|
||||
openView("ruleview", callback);
|
||||
}
|
||||
|
||||
function openComputedView(callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("computedview-ready", () => {
|
||||
inspector.sidebar.select("computedview");
|
||||
let computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
callback(inspector, computedView);
|
||||
})
|
||||
});
|
||||
openView("computedview", callback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
||||
-moz-appearance: none;
|
||||
border: 0;
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
|
|
|
@ -506,7 +506,7 @@ toolbar .toolbarbutton-1[checked]:not(:active):hover {
|
|||
transition: background-color 250ms;
|
||||
}
|
||||
|
||||
.toolbarbutton-1[type="menu-button"] {
|
||||
.toolbarbutton-1[type="menu-button"]:not([overflowedItem=true]) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -946,7 +946,7 @@ toolbaritem[overflowedItem=true],
|
|||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-text,
|
||||
.widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text,
|
||||
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text {
|
||||
text-align: start;
|
||||
-moz-padding-start: .5em;
|
||||
|
|
|
@ -7409,6 +7409,14 @@ if test -n "$MOZ_AUDIO_CHANNEL_MANAGER"; then
|
|||
fi
|
||||
AC_SUBST(MOZ_AUDIO_CHANNEL_MANAGER)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for Firefox Accounts in B2G
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_SERVICES_FXACCOUNTS"; then
|
||||
AC_DEFINE(MOZ_SERVICES_FXACCOUNTS)
|
||||
fi
|
||||
AC_SUBST(MOZ_SERVICES_FXACCOUNTS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Support for demangling undefined symbols
|
||||
dnl ========================================================
|
||||
|
|
|
@ -22,7 +22,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
|
||||
|
|
|
@ -175,7 +175,7 @@ public class DynamicPanel extends HomeFragment {
|
|||
bundle.putParcelable(DATASET_REQUEST, request);
|
||||
|
||||
// Ensure one loader per dataset
|
||||
final int loaderId = generateLoaderId(request.datasetId);
|
||||
final int loaderId = generateLoaderId(request.getDatasetId());
|
||||
getLoaderManager().restartLoader(loaderId, bundle, mLoaderCallbacks);
|
||||
}
|
||||
|
||||
|
@ -218,12 +218,12 @@ public class DynamicPanel extends HomeFragment {
|
|||
final String[] selectionArgs;
|
||||
|
||||
// Null represents the root filter
|
||||
if (mRequest.filter == null) {
|
||||
if (mRequest.getFilter() == null) {
|
||||
selection = DBUtils.concatenateWhere(HomeItems.DATASET_ID + " = ?", HomeItems.FILTER + " IS NULL");
|
||||
selectionArgs = new String[] { mRequest.datasetId };
|
||||
selectionArgs = new String[] { mRequest.getDatasetId() };
|
||||
} else {
|
||||
selection = DBUtils.concatenateWhere(HomeItems.DATASET_ID + " = ?", HomeItems.FILTER + " = ?");
|
||||
selectionArgs = new String[] { mRequest.datasetId, mRequest.filter };
|
||||
selectionArgs = new String[] { mRequest.getDatasetId(), mRequest.getFilter() };
|
||||
}
|
||||
|
||||
// XXX: You can use CONTENT_FAKE_URI for development to pull items from fake_home_items.json.
|
||||
|
@ -256,7 +256,7 @@ public class DynamicPanel extends HomeFragment {
|
|||
final DatasetRequest request = getRequestFromLoader(loader);
|
||||
Log.d(LOGTAG, "Resetting loader for request: " + request);
|
||||
if (mLayout != null) {
|
||||
mLayout.releaseDataset(request.datasetId);
|
||||
mLayout.releaseDataset(request.getDatasetId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.mozilla.gecko.animation.ViewHelper;
|
|||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.widget.EllipsisTextView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -53,7 +54,9 @@ public class HomeBanner extends LinearLayout
|
|||
// switches back to the default page.
|
||||
private boolean mUserSwipedDown = false;
|
||||
|
||||
private final TextView mTextView;
|
||||
// We must use this custom TextView to address an issue on 2.3 and lower where ellipsized text
|
||||
// will not wrap more than 2 lines.
|
||||
private final EllipsisTextView mTextView;
|
||||
private final ImageView mIconView;
|
||||
|
||||
// Listener that gets called when the banner is dismissed from the close button.
|
||||
|
@ -72,7 +75,7 @@ public class HomeBanner extends LinearLayout
|
|||
|
||||
LayoutInflater.from(context).inflate(R.layout.home_banner_content, this);
|
||||
|
||||
mTextView = (TextView) findViewById(R.id.text);
|
||||
mTextView = (EllipsisTextView) findViewById(R.id.text);
|
||||
mIconView = (ImageView) findViewById(R.id.icon);
|
||||
}
|
||||
|
||||
|
@ -167,7 +170,7 @@ public class HomeBanner extends LinearLayout
|
|||
|
||||
// Store the current message id to pass back to JS in the view's OnClickListener.
|
||||
setTag(id);
|
||||
mTextView.setText(Html.fromHtml(text));
|
||||
mTextView.setOriginalText(Html.fromHtml(text));
|
||||
|
||||
BitmapUtils.getDrawable(getContext(), iconURI, new BitmapUtils.BitmapLoader() {
|
||||
@Override
|
||||
|
|
|
@ -583,17 +583,20 @@ public final class HomeConfig {
|
|||
private final String mDatasetId;
|
||||
private final ItemType mItemType;
|
||||
private final ItemHandler mItemHandler;
|
||||
private final String mBackImageUrl;
|
||||
|
||||
private static final String JSON_KEY_TYPE = "type";
|
||||
private static final String JSON_KEY_DATASET = "dataset";
|
||||
private static final String JSON_KEY_ITEM_TYPE = "itemType";
|
||||
private static final String JSON_KEY_ITEM_HANDLER = "itemHandler";
|
||||
private static final String JSON_KEY_BACK_IMAGE_URL = "backImageUrl";
|
||||
|
||||
public ViewConfig(JSONObject json) throws JSONException, IllegalArgumentException {
|
||||
mType = ViewType.fromId(json.getString(JSON_KEY_TYPE));
|
||||
mDatasetId = json.getString(JSON_KEY_DATASET);
|
||||
mItemType = ItemType.fromId(json.getString(JSON_KEY_ITEM_TYPE));
|
||||
mItemHandler = ItemHandler.fromId(json.getString(JSON_KEY_ITEM_HANDLER));
|
||||
mBackImageUrl = json.optString(JSON_KEY_BACK_IMAGE_URL, null);
|
||||
|
||||
validate();
|
||||
}
|
||||
|
@ -604,6 +607,7 @@ public final class HomeConfig {
|
|||
mDatasetId = in.readString();
|
||||
mItemType = (ItemType) in.readParcelable(getClass().getClassLoader());
|
||||
mItemHandler = (ItemHandler) in.readParcelable(getClass().getClassLoader());
|
||||
mBackImageUrl = in.readString();
|
||||
|
||||
validate();
|
||||
}
|
||||
|
@ -613,15 +617,18 @@ public final class HomeConfig {
|
|||
mDatasetId = viewConfig.mDatasetId;
|
||||
mItemType = viewConfig.mItemType;
|
||||
mItemHandler = viewConfig.mItemHandler;
|
||||
mBackImageUrl = viewConfig.mBackImageUrl;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
public ViewConfig(ViewType type, String datasetId, ItemType itemType, ItemHandler itemHandler) {
|
||||
public ViewConfig(ViewType type, String datasetId, ItemType itemType,
|
||||
ItemHandler itemHandler, String backImageUrl) {
|
||||
mType = type;
|
||||
mDatasetId = datasetId;
|
||||
mItemType = itemType;
|
||||
mItemHandler = itemHandler;
|
||||
mBackImageUrl = backImageUrl;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
@ -660,6 +667,10 @@ public final class HomeConfig {
|
|||
return mItemHandler;
|
||||
}
|
||||
|
||||
public String getBackImageUrl() {
|
||||
return mBackImageUrl;
|
||||
}
|
||||
|
||||
public JSONObject toJSON() throws JSONException {
|
||||
final JSONObject json = new JSONObject();
|
||||
|
||||
|
@ -668,6 +679,10 @@ public final class HomeConfig {
|
|||
json.put(JSON_KEY_ITEM_TYPE, mItemType.toString());
|
||||
json.put(JSON_KEY_ITEM_HANDLER, mItemHandler.toString());
|
||||
|
||||
if (!TextUtils.isEmpty(mBackImageUrl)) {
|
||||
json.put(JSON_KEY_BACK_IMAGE_URL, mBackImageUrl);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
|
@ -682,6 +697,7 @@ public final class HomeConfig {
|
|||
dest.writeString(mDatasetId);
|
||||
dest.writeParcelable(mItemType, 0);
|
||||
dest.writeParcelable(mItemHandler, 0);
|
||||
dest.writeString(mBackImageUrl);
|
||||
}
|
||||
|
||||
public static final Creator<ViewConfig> CREATOR = new Creator<ViewConfig>() {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterDetail;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
class PanelBackItemView extends LinearLayout {
|
||||
private final TextView title;
|
||||
|
||||
public PanelBackItemView(Context context, String backImageUrl) {
|
||||
super(context);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.panel_back_item, this);
|
||||
setOrientation(HORIZONTAL);
|
||||
|
||||
title = (TextView) findViewById(R.id.title);
|
||||
|
||||
final ImageView image = (ImageView) findViewById(R.id.image);
|
||||
Picasso.with(getContext())
|
||||
.load(backImageUrl)
|
||||
.placeholder(R.drawable.folder_up)
|
||||
.into(image);
|
||||
}
|
||||
|
||||
public void updateFromFilter(FilterDetail filter) {
|
||||
final String backText = getResources()
|
||||
.getString(R.string.home_move_up_to_filter, filter.title);
|
||||
title.setText(backText);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ import org.mozilla.gecko.home.HomeConfig.ItemHandler;
|
|||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.DatasetBacked;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterManager;
|
||||
import org.mozilla.gecko.home.PanelLayout.OnItemOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.PanelView;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -27,15 +29,15 @@ public class PanelGridView extends GridView
|
|||
|
||||
private final ViewConfig mViewConfig;
|
||||
private final PanelViewAdapter mAdapter;
|
||||
private PanelViewUrlHandler mUrlHandler;
|
||||
private PanelViewItemHandler mItemHandler;
|
||||
|
||||
public PanelGridView(Context context, ViewConfig viewConfig) {
|
||||
super(context, null, R.attr.panelGridViewStyle);
|
||||
|
||||
mViewConfig = viewConfig;
|
||||
mUrlHandler = new PanelViewUrlHandler(viewConfig);
|
||||
mItemHandler = new PanelViewItemHandler(viewConfig);
|
||||
|
||||
mAdapter = new PanelViewAdapter(context, viewConfig.getItemType());
|
||||
mAdapter = new PanelViewAdapter(context, viewConfig);
|
||||
setAdapter(mAdapter);
|
||||
|
||||
setOnItemClickListener(new PanelGridItemClickListener());
|
||||
|
@ -44,7 +46,7 @@ public class PanelGridView extends GridView
|
|||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mUrlHandler.setOnUrlOpenListener(null);
|
||||
mItemHandler.setOnItemOpenListener(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,14 +55,20 @@ public class PanelGridView extends GridView
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
|
||||
mUrlHandler.setOnUrlOpenListener(listener);
|
||||
public void setOnItemOpenListener(OnItemOpenListener listener) {
|
||||
mItemHandler.setOnItemOpenListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilterManager(FilterManager filterManager) {
|
||||
mAdapter.setFilterManager(filterManager);
|
||||
mItemHandler.setFilterManager(filterManager);
|
||||
}
|
||||
|
||||
private class PanelGridItemClickListener implements AdapterView.OnItemClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mUrlHandler.openUrlAtPosition(mAdapter.getCursor(), position);
|
||||
mItemHandler.openItemAtPosition(mAdapter.getCursor(), position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.HomeConfig.ItemHandler;
|
||||
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
|
||||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
|
@ -20,7 +22,6 @@ import android.view.KeyEvent;
|
|||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
@ -65,6 +66,7 @@ abstract class PanelLayout extends FrameLayout {
|
|||
private static final String LOGTAG = "GeckoPanelLayout";
|
||||
|
||||
protected final Map<View, ViewState> mViewStateMap;
|
||||
private final PanelConfig mPanelConfig;
|
||||
private final DatasetHandler mDatasetHandler;
|
||||
private final OnUrlOpenListener mUrlOpenListener;
|
||||
|
||||
|
@ -74,6 +76,7 @@ abstract class PanelLayout extends FrameLayout {
|
|||
*/
|
||||
public interface DatasetBacked {
|
||||
public void setDataset(Cursor cursor);
|
||||
public void setFilterManager(FilterManager manager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,17 +84,68 @@ abstract class PanelLayout extends FrameLayout {
|
|||
* filter for queries on the database.
|
||||
*/
|
||||
public static class DatasetRequest implements Parcelable {
|
||||
public final String datasetId;
|
||||
public final String filter;
|
||||
public enum Type implements Parcelable {
|
||||
DATASET_LOAD,
|
||||
FILTER_PUSH,
|
||||
FILTER_POP;
|
||||
|
||||
private DatasetRequest(Parcel in) {
|
||||
this.datasetId = in.readString();
|
||||
this.filter = in.readString();
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(ordinal());
|
||||
}
|
||||
|
||||
public static final Creator<Type> CREATOR = new Creator<Type>() {
|
||||
@Override
|
||||
public Type createFromParcel(final Parcel source) {
|
||||
return Type.values()[source.readInt()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type[] newArray(final int size) {
|
||||
return new Type[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public DatasetRequest(String datasetId, String filter) {
|
||||
this.datasetId = datasetId;
|
||||
this.filter = filter;
|
||||
private final Type mType;
|
||||
private final String mDatasetId;
|
||||
private final FilterDetail mFilterDetail;
|
||||
|
||||
private DatasetRequest(Parcel in) {
|
||||
this.mType = (Type) in.readParcelable(getClass().getClassLoader());
|
||||
this.mDatasetId = in.readString();
|
||||
this.mFilterDetail = (FilterDetail) in.readParcelable(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
public DatasetRequest(String datasetId, FilterDetail filterDetail) {
|
||||
this(Type.DATASET_LOAD, datasetId, filterDetail);
|
||||
}
|
||||
|
||||
public DatasetRequest(Type type, String datasetId, FilterDetail filterDetail) {
|
||||
this.mType = type;
|
||||
this.mDatasetId = datasetId;
|
||||
this.mFilterDetail = filterDetail;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public String getDatasetId() {
|
||||
return mDatasetId;
|
||||
}
|
||||
|
||||
public String getFilter() {
|
||||
return (mFilterDetail != null ? mFilterDetail.filter : null);
|
||||
}
|
||||
|
||||
public FilterDetail getFilterDetail() {
|
||||
return mFilterDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,12 +155,13 @@ abstract class PanelLayout extends FrameLayout {
|
|||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(datasetId);
|
||||
dest.writeString(filter);
|
||||
dest.writeParcelable(mType, 0);
|
||||
dest.writeString(mDatasetId);
|
||||
dest.writeParcelable(mFilterDetail, 0);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "{dataset: " + datasetId + ", filter: " + filter + "}";
|
||||
return "{type: " + mType + " dataset: " + mDatasetId + ", filter: " + mFilterDetail + "}";
|
||||
}
|
||||
|
||||
public static final Creator<DatasetRequest> CREATOR = new Creator<DatasetRequest>() {
|
||||
|
@ -140,12 +195,20 @@ abstract class PanelLayout extends FrameLayout {
|
|||
}
|
||||
|
||||
public interface PanelView {
|
||||
public void setOnUrlOpenListener(OnUrlOpenListener listener);
|
||||
public void setOnItemOpenListener(OnItemOpenListener listener);
|
||||
public void setOnKeyListener(OnKeyListener listener);
|
||||
}
|
||||
|
||||
public interface FilterManager {
|
||||
public FilterDetail getPreviousFilter();
|
||||
public boolean canGoBack();
|
||||
public void goBack();
|
||||
}
|
||||
|
||||
public PanelLayout(Context context, PanelConfig panelConfig, DatasetHandler datasetHandler, OnUrlOpenListener urlOpenListener) {
|
||||
super(context);
|
||||
mViewStateMap = new WeakHashMap<View, ViewState>();
|
||||
mPanelConfig = panelConfig;
|
||||
mDatasetHandler = datasetHandler;
|
||||
mUrlOpenListener = urlOpenListener;
|
||||
}
|
||||
|
@ -157,7 +220,7 @@ abstract class PanelLayout extends FrameLayout {
|
|||
*/
|
||||
public final void deliverDataset(DatasetRequest request, Cursor cursor) {
|
||||
Log.d(LOGTAG, "Delivering request: " + request);
|
||||
updateViewsWithDataset(request.datasetId, cursor);
|
||||
updateViewsFromRequest(request, cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,8 +228,8 @@ abstract class PanelLayout extends FrameLayout {
|
|||
* existing panel views.
|
||||
*/
|
||||
public final void releaseDataset(String datasetId) {
|
||||
Log.d(LOGTAG, "Resetting dataset: " + datasetId);
|
||||
updateViewsWithDataset(datasetId, null);
|
||||
Log.d(LOGTAG, "Releasing dataset: " + datasetId);
|
||||
releaseViewsWithDataset(datasetId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,8 +277,14 @@ abstract class PanelLayout extends FrameLayout {
|
|||
// TODO: Push initial filter here onto ViewState
|
||||
mViewStateMap.put(view, state);
|
||||
|
||||
((PanelView) view).setOnUrlOpenListener(new PanelUrlOpenListener(state));
|
||||
view.setOnKeyListener(new PanelKeyListener(state));
|
||||
PanelView panelView = (PanelView) view;
|
||||
panelView.setOnItemOpenListener(new PanelOnItemOpenListener(state));
|
||||
panelView.setOnKeyListener(new PanelKeyListener(state));
|
||||
|
||||
if (view instanceof DatasetBacked) {
|
||||
DatasetBacked datasetBacked = (DatasetBacked) view;
|
||||
datasetBacked.setFilterManager(new PanelFilterManager(state));
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -236,18 +305,39 @@ abstract class PanelLayout extends FrameLayout {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateViewsWithDataset(String datasetId, Cursor cursor) {
|
||||
private void updateViewsFromRequest(DatasetRequest request, Cursor cursor) {
|
||||
for (Map.Entry<View, ViewState> entry : mViewStateMap.entrySet()) {
|
||||
final ViewState detail = entry.getValue();
|
||||
|
||||
// Update any views associated with the given dataset ID
|
||||
if (TextUtils.equals(detail.getDatasetId(), datasetId)) {
|
||||
if (TextUtils.equals(detail.getDatasetId(), request.getDatasetId())) {
|
||||
switch (request.getType()) {
|
||||
case FILTER_PUSH:
|
||||
detail.pushFilter(request.getFilterDetail());
|
||||
break;
|
||||
case FILTER_POP:
|
||||
detail.popFilter();
|
||||
break;
|
||||
}
|
||||
|
||||
final View view = entry.getKey();
|
||||
maybeSetDataset(view, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseViewsWithDataset(String datasetId) {
|
||||
for (Map.Entry<View, ViewState> entry : mViewStateMap.entrySet()) {
|
||||
final ViewState detail = entry.getValue();
|
||||
|
||||
// Release the cursor on views associated with the given dataset ID
|
||||
if (TextUtils.equals(detail.getDatasetId(), datasetId)) {
|
||||
final View view = entry.getKey();
|
||||
maybeSetDataset(view, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeSetDataset(View view, Cursor cursor) {
|
||||
if (view instanceof DatasetBacked) {
|
||||
final DatasetBacked dsb = (DatasetBacked) view;
|
||||
|
@ -266,9 +356,9 @@ abstract class PanelLayout extends FrameLayout {
|
|||
* Represents a 'live' instance of a panel view associated with
|
||||
* the {@code PanelLayout}. Is responsible for tracking the history stack of filters.
|
||||
*/
|
||||
protected static class ViewState {
|
||||
protected class ViewState {
|
||||
private final ViewConfig mViewConfig;
|
||||
private Deque<String> mFilterStack;
|
||||
private LinkedList<FilterDetail> mFilterStack;
|
||||
|
||||
public ViewState(ViewConfig viewConfig) {
|
||||
mViewConfig = viewConfig;
|
||||
|
@ -278,10 +368,14 @@ abstract class PanelLayout extends FrameLayout {
|
|||
return mViewConfig.getDatasetId();
|
||||
}
|
||||
|
||||
public ItemHandler getItemHandler() {
|
||||
return mViewConfig.getItemHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to find the current filter that this view is displaying, or null if none.
|
||||
* Get the current filter that this view is displaying, or null if none.
|
||||
*/
|
||||
public String getCurrentFilter() {
|
||||
public FilterDetail getCurrentFilter() {
|
||||
if (mFilterStack == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -289,32 +383,94 @@ abstract class PanelLayout extends FrameLayout {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous filter that this view was displaying, or null if none.
|
||||
*/
|
||||
public FilterDetail getPreviousFilter() {
|
||||
if (!canPopFilter()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mFilterStack.get(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a filter to the history stack for this view.
|
||||
*/
|
||||
public void pushFilter(String filter) {
|
||||
public void pushFilter(FilterDetail filter) {
|
||||
if (mFilterStack == null) {
|
||||
mFilterStack = new LinkedList<String>();
|
||||
mFilterStack = new LinkedList<FilterDetail>();
|
||||
|
||||
// Initialize with a null filter.
|
||||
// TODO: use initial filter from ViewConfig
|
||||
mFilterStack.push(new FilterDetail(null, mPanelConfig.getTitle()));
|
||||
}
|
||||
|
||||
mFilterStack.push(filter);
|
||||
}
|
||||
|
||||
public String popFilter() {
|
||||
if (getCurrentFilter() != null) {
|
||||
mFilterStack.pop();
|
||||
/**
|
||||
* Remove the most recent filter from the stack.
|
||||
*
|
||||
* @return whether the filter was popped
|
||||
*/
|
||||
public boolean popFilter() {
|
||||
if (!canPopFilter()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getCurrentFilter();
|
||||
mFilterStack.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canPopFilter() {
|
||||
return (mFilterStack != null && mFilterStack.size() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
static class FilterDetail implements Parcelable {
|
||||
final String filter;
|
||||
final String title;
|
||||
|
||||
private FilterDetail(Parcel in) {
|
||||
this.filter = in.readString();
|
||||
this.title = in.readString();
|
||||
}
|
||||
|
||||
public FilterDetail(String filter, String title) {
|
||||
this.filter = filter;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(filter);
|
||||
dest.writeString(title);
|
||||
}
|
||||
|
||||
public static final Creator<FilterDetail> CREATOR = new Creator<FilterDetail>() {
|
||||
public FilterDetail createFromParcel(Parcel in) {
|
||||
return new FilterDetail(in);
|
||||
}
|
||||
|
||||
public FilterDetail[] newArray(int size) {
|
||||
return new FilterDetail[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes filter to {@code ViewState}'s stack and makes request for new filter value.
|
||||
*/
|
||||
private void pushFilterOnView(ViewState viewState, String filter) {
|
||||
viewState.pushFilter(filter);
|
||||
mDatasetHandler.requestDataset(new DatasetRequest(viewState.getDatasetId(), filter));
|
||||
private void pushFilterOnView(ViewState viewState, FilterDetail filterDetail) {
|
||||
final String datasetId = viewState.getDatasetId();
|
||||
mDatasetHandler.requestDataset(
|
||||
new DatasetRequest(DatasetRequest.Type.FILTER_PUSH, datasetId, filterDetail));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,33 +479,39 @@ abstract class PanelLayout extends FrameLayout {
|
|||
* @return whether the filter has changed
|
||||
*/
|
||||
private boolean popFilterOnView(ViewState viewState) {
|
||||
String currentFilter = viewState.getCurrentFilter();
|
||||
String filter = viewState.popFilter();
|
||||
|
||||
if (!TextUtils.equals(currentFilter, filter)) {
|
||||
mDatasetHandler.requestDataset(new DatasetRequest(viewState.getDatasetId(), filter));
|
||||
if (viewState.canPopFilter()) {
|
||||
final FilterDetail filterDetail = viewState.getPreviousFilter();
|
||||
final String datasetId = viewState.getDatasetId();
|
||||
mDatasetHandler.requestDataset(
|
||||
new DatasetRequest(DatasetRequest.Type.FILTER_POP, datasetId, filterDetail));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom listener so that we can intercept any filter URLs and make a new dataset request
|
||||
* rather than forwarding them to the default listener.
|
||||
*/
|
||||
private class PanelUrlOpenListener implements OnUrlOpenListener {
|
||||
public interface OnItemOpenListener {
|
||||
public void onItemOpen(String url, String title);
|
||||
}
|
||||
|
||||
private class PanelOnItemOpenListener implements OnItemOpenListener {
|
||||
private ViewState mViewState;
|
||||
|
||||
public PanelUrlOpenListener(ViewState viewState) {
|
||||
public PanelOnItemOpenListener(ViewState viewState) {
|
||||
mViewState = viewState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUrlOpen(String url, EnumSet<Flags> flags) {
|
||||
public void onItemOpen(String url, String title) {
|
||||
if (StringUtils.isFilterUrl(url)) {
|
||||
pushFilterOnView(mViewState, StringUtils.getFilterFromUrl(url));
|
||||
FilterDetail filterDetail = new FilterDetail(StringUtils.getFilterFromUrl(url), title);
|
||||
pushFilterOnView(mViewState, filterDetail);
|
||||
} else {
|
||||
EnumSet<OnUrlOpenListener.Flags> flags = EnumSet.noneOf(OnUrlOpenListener.Flags.class);
|
||||
if (mViewState.getItemHandler() == ItemHandler.INTENT) {
|
||||
flags.add(OnUrlOpenListener.Flags.OPEN_WITH_INTENT);
|
||||
}
|
||||
|
||||
mUrlOpenListener.onUrlOpen(url, flags);
|
||||
}
|
||||
}
|
||||
|
@ -371,4 +533,27 @@ abstract class PanelLayout extends FrameLayout {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class PanelFilterManager implements FilterManager {
|
||||
private final ViewState mViewState;
|
||||
|
||||
public PanelFilterManager(ViewState viewState) {
|
||||
mViewState = viewState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterDetail getPreviousFilter() {
|
||||
return mViewState.getPreviousFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canGoBack() {
|
||||
return mViewState.canPopFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void goBack() {
|
||||
popFilterOnView(mViewState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.mozilla.gecko.home.HomeConfig.ItemHandler;
|
|||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.DatasetBacked;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterManager;
|
||||
import org.mozilla.gecko.home.PanelLayout.OnItemOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.PanelView;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -27,20 +29,26 @@ public class PanelListView extends HomeListView
|
|||
|
||||
private final PanelViewAdapter mAdapter;
|
||||
private final ViewConfig mViewConfig;
|
||||
private final PanelViewUrlHandler mUrlHandler;
|
||||
private final PanelViewItemHandler mItemHandler;
|
||||
|
||||
public PanelListView(Context context, ViewConfig viewConfig) {
|
||||
super(context);
|
||||
|
||||
mViewConfig = viewConfig;
|
||||
mUrlHandler = new PanelViewUrlHandler(viewConfig);
|
||||
mItemHandler = new PanelViewItemHandler(viewConfig);
|
||||
|
||||
mAdapter = new PanelViewAdapter(context, viewConfig.getItemType());
|
||||
mAdapter = new PanelViewAdapter(context, viewConfig);
|
||||
setAdapter(mAdapter);
|
||||
|
||||
setOnItemClickListener(new PanelListItemClickListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mItemHandler.setOnItemOpenListener(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataset(Cursor cursor) {
|
||||
Log.d(LOGTAG, "Setting dataset: " + mViewConfig.getDatasetId());
|
||||
|
@ -48,15 +56,20 @@ public class PanelListView extends HomeListView
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
|
||||
super.setOnUrlOpenListener(listener);
|
||||
mUrlHandler.setOnUrlOpenListener(listener);
|
||||
public void setOnItemOpenListener(OnItemOpenListener listener) {
|
||||
mItemHandler.setOnItemOpenListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilterManager(FilterManager filterManager) {
|
||||
mAdapter.setFilterManager(filterManager);
|
||||
mItemHandler.setFilterManager(filterManager);
|
||||
}
|
||||
|
||||
private class PanelListItemClickListener implements AdapterView.OnItemClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mUrlHandler.openUrlAtPosition(mAdapter.getCursor(), position);
|
||||
mItemHandler.openItemAtPosition(mAdapter.getCursor(), position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.home.HomeConfig.ItemType;
|
||||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterManager;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
@ -14,23 +18,96 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
class PanelViewAdapter extends CursorAdapter {
|
||||
private final Context mContext;
|
||||
private final ItemType mItemType;
|
||||
private static final int VIEW_TYPE_ITEM = 0;
|
||||
private static final int VIEW_TYPE_BACK = 1;
|
||||
|
||||
public PanelViewAdapter(Context context, ItemType itemType) {
|
||||
private final Context mContext;
|
||||
private final ViewConfig mViewConfig;
|
||||
private FilterManager mFilterManager;
|
||||
|
||||
public PanelViewAdapter(Context context, ViewConfig viewConfig) {
|
||||
super(context, null, 0);
|
||||
mContext = context;
|
||||
mItemType = itemType;
|
||||
mViewConfig = viewConfig;
|
||||
}
|
||||
|
||||
public void setFilterManager(FilterManager manager) {
|
||||
mFilterManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
public final int getViewTypeCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return super.getCount() + (isShowingBack() ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (isShowingBack() && position == 0) {
|
||||
return VIEW_TYPE_BACK;
|
||||
} else {
|
||||
return VIEW_TYPE_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = newView(parent.getContext(), position, parent);
|
||||
}
|
||||
|
||||
bindView(convertView, position);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private View newView(Context context, int position, ViewGroup parent) {
|
||||
if (getItemViewType(position) == VIEW_TYPE_BACK) {
|
||||
return new PanelBackItemView(context, mViewConfig.getBackImageUrl());
|
||||
} else {
|
||||
return PanelItemView.create(context, mViewConfig.getItemType());
|
||||
}
|
||||
}
|
||||
|
||||
private void bindView(View view, int position) {
|
||||
if (isShowingBack()) {
|
||||
if (position == 0) {
|
||||
final PanelBackItemView item = (PanelBackItemView) view;
|
||||
item.updateFromFilter(mFilterManager.getPreviousFilter());
|
||||
return;
|
||||
}
|
||||
|
||||
position--;
|
||||
}
|
||||
|
||||
final Cursor cursor = getCursor(position);
|
||||
final PanelItemView item = (PanelItemView) view;
|
||||
item.updateFromCursor(cursor);
|
||||
}
|
||||
|
||||
private boolean isShowingBack() {
|
||||
return (mFilterManager != null ? mFilterManager.canGoBack() : false);
|
||||
}
|
||||
|
||||
private final Cursor getCursor(int position) {
|
||||
final Cursor cursor = getCursor();
|
||||
if (cursor == null || !cursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return PanelItemView.create(mContext, mItemType);
|
||||
public final void bindView(View view, Context context, Cursor cursor) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.HomeItems;
|
||||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterManager;
|
||||
import org.mozilla.gecko.home.PanelLayout.OnItemOpenListener;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
class PanelViewItemHandler {
|
||||
private final ViewConfig mViewConfig;
|
||||
private OnItemOpenListener mItemOpenListener;
|
||||
private FilterManager mFilterManager;
|
||||
|
||||
public PanelViewItemHandler(ViewConfig viewConfig) {
|
||||
mViewConfig = viewConfig;
|
||||
}
|
||||
|
||||
public void setOnItemOpenListener(OnItemOpenListener listener) {
|
||||
mItemOpenListener = listener;
|
||||
}
|
||||
|
||||
public void setFilterManager(FilterManager manager) {
|
||||
mFilterManager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* If item at this position is a back item, perform the go back action via the
|
||||
* {@code FilterManager}. Otherwise, prepare the url to be opened by the
|
||||
* {@code OnUrlOpenListener}.
|
||||
*/
|
||||
public void openItemAtPosition(Cursor cursor, int position) {
|
||||
if (mFilterManager != null && mFilterManager.canGoBack()) {
|
||||
if (position == 0) {
|
||||
mFilterManager.goBack();
|
||||
return;
|
||||
}
|
||||
|
||||
position--;
|
||||
}
|
||||
|
||||
if (cursor == null || !cursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
int urlIndex = cursor.getColumnIndexOrThrow(HomeItems.URL);
|
||||
final String url = cursor.getString(urlIndex);
|
||||
|
||||
int titleIndex = cursor.getColumnIndexOrThrow(HomeItems.TITLE);
|
||||
final String title = cursor.getString(titleIndex);
|
||||
|
||||
if (mItemOpenListener != null) {
|
||||
mItemOpenListener.onItemOpen(url, title);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.HomeItems;
|
||||
import org.mozilla.gecko.home.HomeConfig.ItemHandler;
|
||||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
class PanelViewUrlHandler {
|
||||
private final ViewConfig mViewConfig;
|
||||
private OnUrlOpenListener mUrlOpenListener;
|
||||
|
||||
public PanelViewUrlHandler(ViewConfig viewConfig) {
|
||||
mViewConfig = viewConfig;
|
||||
}
|
||||
|
||||
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
|
||||
mUrlOpenListener = listener;
|
||||
}
|
||||
|
||||
public void openUrlAtPosition(Cursor cursor, int position) {
|
||||
if (cursor == null || !cursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
int urlIndex = cursor.getColumnIndexOrThrow(HomeItems.URL);
|
||||
final String url = cursor.getString(urlIndex);
|
||||
|
||||
EnumSet<OnUrlOpenListener.Flags> flags = EnumSet.noneOf(OnUrlOpenListener.Flags.class);
|
||||
if (mViewConfig.getItemHandler() == ItemHandler.INTENT) {
|
||||
flags.add(OnUrlOpenListener.Flags.OPEN_WITH_INTENT);
|
||||
}
|
||||
|
||||
if (mUrlOpenListener != null) {
|
||||
mUrlOpenListener.onUrlOpen(url, flags);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -339,6 +339,10 @@ size. -->
|
|||
is no data to show in an about:home panel that was created by an add-on. -->
|
||||
<!ENTITY home_default_empty "No content could be found for this panel.">
|
||||
|
||||
<!-- Localization note (home_move_up_to_filter): The variable is replaced by the name of the
|
||||
previous location in the navigation, such as the previous folder -->
|
||||
<!ENTITY home_move_up_to_filter "Up to &formatS;">
|
||||
|
||||
<!ENTITY pin_site_dialog_hint "Enter a search keyword">
|
||||
|
||||
<!ENTITY filepicker_title "Choose File">
|
||||
|
@ -418,6 +422,12 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
<!ENTITY exit_guest_session_title "&brandShortName; will now restart">
|
||||
<!ENTITY exit_guest_session_text "The browsing data from this session will be deleted.">
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<!-- LOCALIZATION NOTE (ellipsis): This text is appended to a piece of text that does not fit in the
|
||||
designated space. Use the unicode ellipsis char, \u2026, or use "..." if \u2026 doesn't suit
|
||||
traditions in your locale. -->
|
||||
<!ENTITY ellipsis "…">
|
||||
|
||||
<!-- These are only used for accessiblity for the done and overflow-menu buttons in the actionbar.
|
||||
They are never shown to users -->
|
||||
<!ENTITY actionbar_menu "Menu">
|
||||
|
|
|
@ -246,13 +246,14 @@ gbjar.sources += [
|
|||
'home/LastTabsPanel.java',
|
||||
'home/MostRecentPanel.java',
|
||||
'home/MultiTypeCursorAdapter.java',
|
||||
'home/PanelBackItemView.java',
|
||||
'home/PanelGridView.java',
|
||||
'home/PanelItemView.java',
|
||||
'home/PanelLayout.java',
|
||||
'home/PanelListView.java',
|
||||
'home/PanelManager.java',
|
||||
'home/PanelViewAdapter.java',
|
||||
'home/PanelViewUrlHandler.java',
|
||||
'home/PanelViewItemHandler.java',
|
||||
'home/PinSiteDialog.java',
|
||||
'home/ReadingListPanel.java',
|
||||
'home/SearchEngine.java',
|
||||
|
@ -381,6 +382,7 @@ gbjar.sources += [
|
|||
'widget/DateTimePicker.java',
|
||||
'widget/Divider.java',
|
||||
'widget/DoorHanger.java',
|
||||
'widget/EllipsisTextView.java',
|
||||
'widget/FaviconView.java',
|
||||
'widget/FlowLayout.java',
|
||||
'widget/GeckoActionProvider.java',
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.4 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.6 KiB |
|
@ -1 +0,0 @@
|
|||
blassey@flyingfox.local.319
|
|
@ -3,7 +3,8 @@
|
|||
- 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/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dip"
|
||||
|
@ -11,19 +12,18 @@
|
|||
android:layout_marginLeft="10dp"
|
||||
android:scaleType="centerInside"/>
|
||||
|
||||
<TextView android:id="@+id/text"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:textAppearance="@style/TextAppearance.Widget.HomeBanner"
|
||||
android:layout_gravity="bottom"
|
||||
android:singleLine="false"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"/>
|
||||
<org.mozilla.gecko.widget.EllipsisTextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:textAppearance="@style/TextAppearance.Widget.HomeBanner"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center_vertical"
|
||||
gecko:ellipsizeAtLine="3"/>
|
||||
|
||||
<ImageButton android:id="@+id/close"
|
||||
android:layout_width="34dip"
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<ImageView android:id="@+id/image"
|
||||
android:layout_width="54dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<TextView android:id="@+id/title"
|
||||
style="@style/Widget.PanelItemView.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dip"
|
||||
android:paddingBottom="5dip"
|
||||
android:paddingLeft="10dip"
|
||||
android:paddingRight="10dip"
|
||||
android:minHeight="@dimen/page_row_height"
|
||||
android:gravity="center_vertical"/>
|
||||
|
||||
</merge>
|
|
@ -236,5 +236,9 @@
|
|||
<attr name="strip" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="EllipsisTextView">
|
||||
<attr name="ellipsizeAtLine" format="integer"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
||||
|
|
|
@ -305,6 +305,7 @@
|
|||
<string name="home_reading_list_hint">&home_reading_list_hint2;</string>
|
||||
<string name="home_reading_list_hint_accessible">&home_reading_list_hint_accessible;</string>
|
||||
<string name="home_default_empty">&home_default_empty;</string>
|
||||
<string name="home_move_up_to_filter">&home_move_up_to_filter;</string>
|
||||
<string name="pin_site_dialog_hint">&pin_site_dialog_hint;</string>
|
||||
|
||||
<string name="filepicker_title">&filepicker_title;</string>
|
||||
|
@ -397,4 +398,7 @@
|
|||
<string name="actionbar_menu">&actionbar_menu;</string>
|
||||
<string name="actionbar_done">&actionbar_done;</string>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<string name="ellipsis">&ellipsis;</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Text view that correctly handles maxLines and ellipsizing for Android < 2.3.
|
||||
*/
|
||||
public class EllipsisTextView extends TextView {
|
||||
private final String ellipsis;
|
||||
|
||||
private int maxLines;
|
||||
private CharSequence originalText;
|
||||
|
||||
public EllipsisTextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public EllipsisTextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, android.R.attr.textViewStyle);
|
||||
}
|
||||
|
||||
public EllipsisTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
ellipsis = getResources().getString(R.string.ellipsis);
|
||||
|
||||
TypedArray a = context.getTheme()
|
||||
.obtainStyledAttributes(attrs, R.styleable.EllipsisTextView, 0, 0);
|
||||
maxLines = a.getInteger(R.styleable.EllipsisTextView_ellipsizeAtLine, 1);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setOriginalText(CharSequence text) {
|
||||
originalText = text;
|
||||
setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
// There is extra space, start over with the original text
|
||||
if (getLineCount() < maxLines) {
|
||||
setText(originalText);
|
||||
}
|
||||
|
||||
// If we are over the max line attribute, ellipsize
|
||||
if (getLineCount() > maxLines) {
|
||||
final int endIndex = getLayout().getLineEnd(maxLines - 1) - 1 - ellipsis.length();
|
||||
final String text = getText().subSequence(0, endIndex) + ellipsis;
|
||||
// Make sure that we don't change originalText
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,9 @@ MOZ_PAY=1
|
|||
# Enable UI for healthreporter
|
||||
MOZ_SERVICES_HEALTHREPORT=1
|
||||
|
||||
# Enable FirefoxAccounts
|
||||
MOZ_SERVICES_FXACCOUNTS=1
|
||||
|
||||
# Wifi-AP/cell tower data reporting is enabled on non-release builds.
|
||||
if test ! "$RELEASE_BUILD"; then
|
||||
MOZ_DATA_REPORTING=1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
let cs = Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService);
|
||||
|
|
|
@ -17,7 +17,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Componen
|
|||
let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
|
||||
let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
|
||||
let { ctypes } = Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
PARALLEL_DIRS += [
|
||||
'common',
|
||||
'crypto',
|
||||
'fxaccounts',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
|
||||
|
@ -22,6 +21,9 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
|
|||
if CONFIG['MOZ_SERVICES_METRICS']:
|
||||
PARALLEL_DIRS += ['metrics']
|
||||
|
||||
if CONFIG['MOZ_SERVICES_FXACCOUNTS']:
|
||||
PARALLEL_DIRS += ['fxaccounts']
|
||||
|
||||
if CONFIG['MOZ_SERVICES_SYNC']:
|
||||
PARALLEL_DIRS += ['sync']
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const Cu = Components.utils;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
|
||||
do_get_profile();
|
||||
|
|
|
@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
var downloadUtils = { };
|
||||
XPCOMUtils.defineLazyServiceGetter(downloadUtils,
|
||||
|
|
|
@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче