зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound a=merge
This commit is contained in:
Коммит
3c1f665b48
|
@ -287,9 +287,8 @@ let gSyncUI = {
|
||||||
// Commands
|
// Commands
|
||||||
doSync: function SUI_doSync() {
|
doSync: function SUI_doSync() {
|
||||||
let needsSetup = this._needsSetup();
|
let needsSetup = this._needsSetup();
|
||||||
let loginFailed = this._loginFailed();
|
|
||||||
|
|
||||||
if (!(loginFailed || needsSetup)) {
|
if (!needsSetup) {
|
||||||
setTimeout(function () Weave.Service.errorHandler.syncAndReportErrors(), 0);
|
setTimeout(function () Weave.Service.errorHandler.syncAndReportErrors(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,10 +448,13 @@ this.GoogleImporter.prototype = {
|
||||||
if (phoneNodes.length) {
|
if (phoneNodes.length) {
|
||||||
contact.tel = [];
|
contact.tel = [];
|
||||||
for (let [,phoneNode] of Iterator(phoneNodes)) {
|
for (let [,phoneNode] of Iterator(phoneNodes)) {
|
||||||
|
let phoneNumber = phoneNode.hasAttribute("uri") ?
|
||||||
|
phoneNode.getAttribute("uri").replace("tel:", "") :
|
||||||
|
phoneNode.firstChild.nodeValue;
|
||||||
contact.tel.push({
|
contact.tel.push({
|
||||||
pref: (phoneNode.getAttribute("primary") == "true"),
|
pref: (phoneNode.getAttribute("primary") == "true"),
|
||||||
type: [getFieldType(phoneNode)],
|
type: [getFieldType(phoneNode)],
|
||||||
value: phoneNode.getAttribute("uri").replace("tel:", "")
|
value: phoneNumber
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -790,16 +790,85 @@ let LoopContactsInternal = Object.freeze({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search through the data store for contacts that match a certain (sub-)string.
|
* Search through the data store for contacts that match a certain (sub-)string.
|
||||||
|
* NB: The current implementation is very simple, naive if you will; we fetch
|
||||||
|
* _all_ the contacts via `getAll()` and iterate over all of them to find
|
||||||
|
* the contacts matching the supplied query (brute-force search in
|
||||||
|
* exponential time).
|
||||||
*
|
*
|
||||||
* @param {String} query Needle to search for in our haystack of contacts
|
* @param {Object} query Needle to search for in our haystack of contacts
|
||||||
* @param {Function} callback Function that will be invoked once the operation
|
* @param {Function} callback Function that will be invoked once the operation
|
||||||
* finished. The first argument passed will be an
|
* finished. The first argument passed will be an
|
||||||
* `Error` object or `null`. The second argument will
|
* `Error` object or `null`. The second argument will
|
||||||
* be an `Array` of contact objects, if successfull.
|
* be an `Array` of contact objects, if successfull.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* LoopContacts.search({
|
||||||
|
* q: "foo@bar.com",
|
||||||
|
* field: "email" // 'email' is the default.
|
||||||
|
* }, function(err, contacts) {
|
||||||
|
* if (err) {
|
||||||
|
* throw err;
|
||||||
|
* }
|
||||||
|
* console.dir(contacts);
|
||||||
|
* });
|
||||||
*/
|
*/
|
||||||
search: function(query, callback) {
|
search: function(query, callback) {
|
||||||
//TODO in bug 1037114.
|
if (!("q" in query) || !query.q) {
|
||||||
callback(new Error("Not implemented yet!"));
|
callback(new Error("Nothing to search for. 'q' is required."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!("field" in query)) {
|
||||||
|
query.field = "email";
|
||||||
|
}
|
||||||
|
let queryValue = query.q;
|
||||||
|
if (query.field == "tel") {
|
||||||
|
queryValue = queryValue.replace(/[\D]+/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkForMatch = function(fieldValue) {
|
||||||
|
if (typeof fieldValue == "string") {
|
||||||
|
if (query.field == "tel") {
|
||||||
|
return fieldValue.replace(/[\D]+/g, "").endsWith(queryValue);
|
||||||
|
}
|
||||||
|
return fieldValue == queryValue;
|
||||||
|
}
|
||||||
|
if (typeof fieldValue == "number" || typeof fieldValue == "boolean") {
|
||||||
|
return fieldValue == queryValue;
|
||||||
|
}
|
||||||
|
if ("value" in fieldValue) {
|
||||||
|
return checkForMatch(fieldValue.value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let foundContacts = [];
|
||||||
|
this.getAll((err, contacts) => {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let contact of contacts) {
|
||||||
|
let matchWith = contact[query.field];
|
||||||
|
if (!matchWith) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Many fields are defined as Arrays.
|
||||||
|
if (Array.isArray(matchWith)) {
|
||||||
|
for (let fieldValue of matchWith) {
|
||||||
|
if (checkForMatch(fieldValue)) {
|
||||||
|
foundContacts.push(contact);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (checkForMatch(matchWith)) {
|
||||||
|
foundContacts.push(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, foundContacts);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ const LOOP_SESSION_TYPE = {
|
||||||
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
|
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
|
||||||
const PREF_LOG_LEVEL = "loop.debug.loglevel";
|
const PREF_LOG_LEVEL = "loop.debug.loglevel";
|
||||||
|
|
||||||
|
const EMAIL_OR_PHONE_RE = /^(:?\S+@\S+|\+\d+)$/;
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/Promise.jsm");
|
Cu.import("resource://gre/modules/Promise.jsm");
|
||||||
|
@ -56,6 +58,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "HawkClient",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "deriveHawkCredentials",
|
XPCOMUtils.defineLazyModuleGetter(this, "deriveHawkCredentials",
|
||||||
"resource://services-common/hawkrequest.js");
|
"resource://services-common/hawkrequest.js");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
|
||||||
|
"resource:///modules/loop/LoopContacts.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage",
|
XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage",
|
||||||
"resource:///modules/loop/LoopStorage.jsm");
|
"resource:///modules/loop/LoopStorage.jsm");
|
||||||
|
|
||||||
|
@ -786,17 +791,46 @@ let MozLoopServiceInternal = {
|
||||||
* Starts a call, saves the call data, and opens a chat window.
|
* Starts a call, saves the call data, and opens a chat window.
|
||||||
*
|
*
|
||||||
* @param {Object} callData The data associated with the call including an id.
|
* @param {Object} callData The data associated with the call including an id.
|
||||||
* @param {Boolean} conversationType Whether or not the call is "incoming"
|
* @param {String} conversationType Whether or not the call is "incoming"
|
||||||
* or "outgoing"
|
* or "outgoing"
|
||||||
*/
|
*/
|
||||||
_startCall: function(callData, conversationType) {
|
_startCall: function(callData, conversationType) {
|
||||||
this.callsData.inUse = true;
|
const openChat = () => {
|
||||||
this.callsData.data = callData;
|
this.callsData.inUse = true;
|
||||||
this.openChatWindow(
|
this.callsData.data = callData;
|
||||||
null,
|
|
||||||
// No title, let the page set that, to avoid flickering.
|
this.openChatWindow(
|
||||||
"",
|
null,
|
||||||
"about:loopconversation#" + conversationType + "/" + callData.callId);
|
// No title, let the page set that, to avoid flickering.
|
||||||
|
"",
|
||||||
|
"about:loopconversation#" + conversationType + "/" + callData.callId);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (conversationType == "incoming" && ("callerId" in callData) &&
|
||||||
|
EMAIL_OR_PHONE_RE.test(callData.callerId)) {
|
||||||
|
LoopContacts.search({
|
||||||
|
q: callData.callerId,
|
||||||
|
field: callData.callerId.contains("@") ? "email" : "tel"
|
||||||
|
}, (err, contacts) => {
|
||||||
|
if (err) {
|
||||||
|
// Database error, helas!
|
||||||
|
openChat();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let contact of contacts) {
|
||||||
|
if (contact.blocked) {
|
||||||
|
// Blocked! Send a busy signal back to the caller.
|
||||||
|
this._returnBusy(callData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openChat();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
openChat();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -86,12 +86,15 @@ loop.contacts = (function(_, mozL10n) {
|
||||||
return (
|
return (
|
||||||
React.DOM.ul({className: cx({ "dropdown-menu": true,
|
React.DOM.ul({className: cx({ "dropdown-menu": true,
|
||||||
"dropdown-menu-up": this.state.openDirUp })},
|
"dropdown-menu-up": this.state.openDirUp })},
|
||||||
React.DOM.li({className: cx({ "dropdown-menu-item": true }),
|
React.DOM.li({className: cx({ "dropdown-menu-item": true,
|
||||||
onClick: this.onItemClick, 'data-action': "video-call"},
|
"disabled": this.props.blocked }),
|
||||||
|
onClick: this.onItemClick,
|
||||||
|
'data-action': "video-call"},
|
||||||
React.DOM.i({className: "icon icon-video-call"}),
|
React.DOM.i({className: "icon icon-video-call"}),
|
||||||
mozL10n.get("video_call_menu_button")
|
mozL10n.get("video_call_menu_button")
|
||||||
),
|
),
|
||||||
React.DOM.li({className: cx({ "dropdown-menu-item": true }),
|
React.DOM.li({className: cx({ "dropdown-menu-item": true,
|
||||||
|
"disabled": this.props.blocked }),
|
||||||
onClick: this.onItemClick, 'data-action': "audio-call"},
|
onClick: this.onItemClick, 'data-action': "audio-call"},
|
||||||
React.DOM.i({className: "icon icon-audio-call"}),
|
React.DOM.i({className: "icon icon-audio-call"}),
|
||||||
mozL10n.get("audio_call_menu_button")
|
mozL10n.get("audio_call_menu_button")
|
||||||
|
@ -388,10 +391,14 @@ loop.contacts = (function(_, mozL10n) {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "video-call":
|
case "video-call":
|
||||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
if (!contact.blocked) {
|
||||||
|
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "audio-call":
|
case "audio-call":
|
||||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
if (!contact.blocked) {
|
||||||
|
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("Unrecognized action: " + actionName);
|
console.error("Unrecognized action: " + actionName);
|
||||||
|
|
|
@ -86,12 +86,15 @@ loop.contacts = (function(_, mozL10n) {
|
||||||
return (
|
return (
|
||||||
<ul className={cx({ "dropdown-menu": true,
|
<ul className={cx({ "dropdown-menu": true,
|
||||||
"dropdown-menu-up": this.state.openDirUp })}>
|
"dropdown-menu-up": this.state.openDirUp })}>
|
||||||
<li className={cx({ "dropdown-menu-item": true })}
|
<li className={cx({ "dropdown-menu-item": true,
|
||||||
onClick={this.onItemClick} data-action="video-call">
|
"disabled": this.props.blocked })}
|
||||||
|
onClick={this.onItemClick}
|
||||||
|
data-action="video-call">
|
||||||
<i className="icon icon-video-call" />
|
<i className="icon icon-video-call" />
|
||||||
{mozL10n.get("video_call_menu_button")}
|
{mozL10n.get("video_call_menu_button")}
|
||||||
</li>
|
</li>
|
||||||
<li className={cx({ "dropdown-menu-item": true })}
|
<li className={cx({ "dropdown-menu-item": true,
|
||||||
|
"disabled": this.props.blocked })}
|
||||||
onClick={this.onItemClick} data-action="audio-call">
|
onClick={this.onItemClick} data-action="audio-call">
|
||||||
<i className="icon icon-audio-call" />
|
<i className="icon icon-audio-call" />
|
||||||
{mozL10n.get("audio_call_menu_button")}
|
{mozL10n.get("audio_call_menu_button")}
|
||||||
|
@ -388,10 +391,14 @@ loop.contacts = (function(_, mozL10n) {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "video-call":
|
case "video-call":
|
||||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
if (!contact.blocked) {
|
||||||
|
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "audio-call":
|
case "audio-call":
|
||||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
if (!contact.blocked) {
|
||||||
|
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("Unrecognized action: " + actionName);
|
console.error("Unrecognized action: " + actionName);
|
||||||
|
|
|
@ -406,6 +406,12 @@ loop.store.ConversationStore = (function() {
|
||||||
this._websocket.close();
|
this._websocket.close();
|
||||||
delete this._websocket;
|
delete this._websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX: The internal callId is different from
|
||||||
|
// this.get("callId"), see bug 1084228 for more info.
|
||||||
|
var locationHash = new loop.shared.utils.Helper().locationHash();
|
||||||
|
var callId = locationHash.match(/\#outgoing\/(.*)/)[1];
|
||||||
|
navigator.mozLoop.releaseCallData(callId);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,19 +17,25 @@ function promiseImport() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const kContactsCount = 7;
|
||||||
|
|
||||||
add_task(function* test_GoogleImport() {
|
add_task(function* test_GoogleImport() {
|
||||||
let stats;
|
let stats;
|
||||||
// An error may throw and the test will fail when that happens.
|
// An error may throw and the test will fail when that happens.
|
||||||
stats = yield promiseImport();
|
stats = yield promiseImport();
|
||||||
|
|
||||||
|
let contactsCount = mockDb.size;
|
||||||
|
|
||||||
// Assert the world.
|
// Assert the world.
|
||||||
Assert.equal(stats.total, 6, "Five contacts should get processed");
|
Assert.equal(stats.total, contactsCount, "Five contacts should get processed");
|
||||||
Assert.equal(stats.success, 6, "Five contacts should be imported");
|
Assert.equal(stats.success, contactsCount, "Five contacts should be imported");
|
||||||
|
|
||||||
yield promiseImport();
|
yield promiseImport();
|
||||||
Assert.equal(Object.keys(mockDb._store).length, 6, "Database should contain only five contact after reimport");
|
Assert.equal(Object.keys(mockDb._store).length, contactsCount, "Database should be the same size after reimport");
|
||||||
|
|
||||||
let c = mockDb._store[mockDb._next_guid - 6];
|
let currentContact = contactsCount;
|
||||||
|
|
||||||
|
let c = mockDb._store[mockDb._next_guid - currentContact];
|
||||||
Assert.equal(c.name[0], "John Smith", "Full name should match");
|
Assert.equal(c.name[0], "John Smith", "Full name should match");
|
||||||
Assert.equal(c.givenName[0], "John", "Given name should match");
|
Assert.equal(c.givenName[0], "John", "Given name should match");
|
||||||
Assert.equal(c.familyName[0], "Smith", "Family name should match");
|
Assert.equal(c.familyName[0], "Smith", "Family name should match");
|
||||||
|
@ -39,7 +45,7 @@ add_task(function* test_GoogleImport() {
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/0", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/0", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
c = mockDb._store[mockDb._next_guid - 5];
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
Assert.equal(c.name[0], "Jane Smith", "Full name should match");
|
Assert.equal(c.name[0], "Jane Smith", "Full name should match");
|
||||||
Assert.equal(c.givenName[0], "Jane", "Given name should match");
|
Assert.equal(c.givenName[0], "Jane", "Given name should match");
|
||||||
Assert.equal(c.familyName[0], "Smith", "Family name should match");
|
Assert.equal(c.familyName[0], "Smith", "Family name should match");
|
||||||
|
@ -49,7 +55,7 @@ add_task(function* test_GoogleImport() {
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/1", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/1", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
c = mockDb._store[mockDb._next_guid - 4];
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
Assert.equal(c.name[0], "Davy Randall Jones", "Full name should match");
|
Assert.equal(c.name[0], "Davy Randall Jones", "Full name should match");
|
||||||
Assert.equal(c.givenName[0], "Davy Randall", "Given name should match");
|
Assert.equal(c.givenName[0], "Davy Randall", "Given name should match");
|
||||||
Assert.equal(c.familyName[0], "Jones", "Family name should match");
|
Assert.equal(c.familyName[0], "Jones", "Family name should match");
|
||||||
|
@ -59,7 +65,7 @@ add_task(function* test_GoogleImport() {
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/2", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/2", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
c = mockDb._store[mockDb._next_guid - 3];
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
Assert.equal(c.name[0], "noname@example.com", "Full name should match");
|
Assert.equal(c.name[0], "noname@example.com", "Full name should match");
|
||||||
Assert.equal(c.email[0].type, "other", "Email type should match");
|
Assert.equal(c.email[0].type, "other", "Email type should match");
|
||||||
Assert.equal(c.email[0].value, "noname@example.com", "Email should match");
|
Assert.equal(c.email[0].value, "noname@example.com", "Email should match");
|
||||||
|
@ -67,7 +73,7 @@ add_task(function* test_GoogleImport() {
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/3", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/3", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
c = mockDb._store[mockDb._next_guid - 2];
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
Assert.equal(c.name[0], "lycnix", "Full name should match");
|
Assert.equal(c.name[0], "lycnix", "Full name should match");
|
||||||
Assert.equal(c.email[0].type, "other", "Email type should match");
|
Assert.equal(c.email[0].type, "other", "Email type should match");
|
||||||
Assert.equal(c.email[0].value, "lycnix", "Email should match");
|
Assert.equal(c.email[0].value, "lycnix", "Email should match");
|
||||||
|
@ -75,11 +81,19 @@ add_task(function* test_GoogleImport() {
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/7", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/7", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
c = mockDb._store[mockDb._next_guid - 1];
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
Assert.equal(c.name[0], "+31-6-12345678", "Full name should match");
|
Assert.equal(c.name[0], "+31-6-12345678", "Full name should match");
|
||||||
Assert.equal(c.tel[0].type, "mobile", "Email type should match");
|
Assert.equal(c.tel[0].type, "mobile", "Phone type should match");
|
||||||
Assert.equal(c.tel[0].value, "+31-6-12345678", "Email should match");
|
Assert.equal(c.tel[0].value, "+31-6-12345678", "Phone should match");
|
||||||
Assert.equal(c.tel[0].pref, false, "Pref should match");
|
Assert.equal(c.tel[0].pref, false, "Pref should match");
|
||||||
Assert.equal(c.category[0], "google", "Category should match");
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/8", "UID should match and be scoped to provider");
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/8", "UID should match and be scoped to provider");
|
||||||
|
|
||||||
|
c = mockDb._store[mockDb._next_guid - (--currentContact)];
|
||||||
|
Assert.equal(c.name[0], "215234523452345", "Full name should match");
|
||||||
|
Assert.equal(c.tel[0].type, "mobile", "Phone type should match");
|
||||||
|
Assert.equal(c.tel[0].value, "215234523452345", "Phone should match");
|
||||||
|
Assert.equal(c.tel[0].pref, false, "Pref should match");
|
||||||
|
Assert.equal(c.category[0], "google", "Category should match");
|
||||||
|
Assert.equal(c.id, "http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/6", "UID should match and be scoped to provider");
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,6 +16,11 @@ const kContacts = [{
|
||||||
"type": ["work"],
|
"type": ["work"],
|
||||||
"value": "ally@mail.com"
|
"value": "ally@mail.com"
|
||||||
}],
|
}],
|
||||||
|
tel: [{
|
||||||
|
"pref": true,
|
||||||
|
"type": ["mobile"],
|
||||||
|
"value": "+31-6-12345678"
|
||||||
|
}],
|
||||||
category: ["google"],
|
category: ["google"],
|
||||||
published: 1406798311748,
|
published: 1406798311748,
|
||||||
updated: 1406798311748
|
updated: 1406798311748
|
||||||
|
@ -27,6 +32,11 @@ const kContacts = [{
|
||||||
"type": ["work"],
|
"type": ["work"],
|
||||||
"value": "bob@gmail.com"
|
"value": "bob@gmail.com"
|
||||||
}],
|
}],
|
||||||
|
tel: [{
|
||||||
|
"pref": true,
|
||||||
|
"type": ["mobile"],
|
||||||
|
"value": "+1-214-5551234"
|
||||||
|
}],
|
||||||
category: ["local"],
|
category: ["local"],
|
||||||
published: 1406798311748,
|
published: 1406798311748,
|
||||||
updated: 1406798311748
|
updated: 1406798311748
|
||||||
|
@ -425,11 +435,50 @@ add_task(function* () {
|
||||||
LoopStorage.switchDatabase();
|
LoopStorage.switchDatabase();
|
||||||
Assert.equal(LoopStorage.databaseName, "default", "The active partition should have changed");
|
Assert.equal(LoopStorage.databaseName, "default", "The active partition should have changed");
|
||||||
|
|
||||||
LoopContacts.getAll(function(err, contacts) {
|
contacts = yield LoopContacts.promise("getAll");
|
||||||
Assert.equal(err, null, "There shouldn't be an error");
|
for (let i = 0, l = contacts.length; i < l; ++i) {
|
||||||
|
compareContacts(contacts[i], kContacts[i]);
|
||||||
for (let i = 0, l = contacts.length; i < l; ++i) {
|
}
|
||||||
compareContacts(contacts[i], kContacts[i]);
|
});
|
||||||
}
|
|
||||||
});
|
// Test searching for contacts.
|
||||||
|
add_task(function* () {
|
||||||
|
yield promiseLoadContacts();
|
||||||
|
|
||||||
|
let contacts = yield LoopContacts.promise("search", {
|
||||||
|
q: "bob@gmail.com"
|
||||||
|
});
|
||||||
|
Assert.equal(contacts.length, 1, "There should be one contact found");
|
||||||
|
compareContacts(contacts[0], kContacts[1]);
|
||||||
|
|
||||||
|
// Test searching by name.
|
||||||
|
contacts = yield LoopContacts.promise("search", {
|
||||||
|
q: "Ally Avocado",
|
||||||
|
field: "name"
|
||||||
|
});
|
||||||
|
Assert.equal(contacts.length, 1, "There should be one contact found");
|
||||||
|
compareContacts(contacts[0], kContacts[0]);
|
||||||
|
|
||||||
|
// Test searching for multiple contacts.
|
||||||
|
contacts = yield LoopContacts.promise("search", {
|
||||||
|
q: "google",
|
||||||
|
field: "category"
|
||||||
|
});
|
||||||
|
Assert.equal(contacts.length, 2, "There should be two contacts found");
|
||||||
|
|
||||||
|
// Test searching for telephone numbers.
|
||||||
|
contacts = yield LoopContacts.promise("search", {
|
||||||
|
q: "+31612345678",
|
||||||
|
field: "tel"
|
||||||
|
});
|
||||||
|
Assert.equal(contacts.length, 1, "There should be one contact found");
|
||||||
|
compareContacts(contacts[0], kContacts[0]);
|
||||||
|
|
||||||
|
// Test searching for telephone numbers without prefixes.
|
||||||
|
contacts = yield LoopContacts.promise("search", {
|
||||||
|
q: "5551234",
|
||||||
|
field: "tel"
|
||||||
|
});
|
||||||
|
Assert.equal(contacts.length, 1, "There should be one contact found");
|
||||||
|
compareContacts(contacts[0], kContacts[1]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -102,4 +102,16 @@
|
||||||
<link href="https://www.google.com/m8/feeds/contacts/tester%40mochi.com/full/8" rel="edit" type="application/atom+xml"/>
|
<link href="https://www.google.com/m8/feeds/contacts/tester%40mochi.com/full/8" rel="edit" type="application/atom+xml"/>
|
||||||
<gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile" uri="tel:+31-6-12345678">0612345678</gd:phoneNumber>
|
<gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile" uri="tel:+31-6-12345678">0612345678</gd:phoneNumber>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry gd:etag=""SX8-ejVSLit7I2A9XRdQFUkDRgY."">
|
||||||
|
<id>http://www.google.com/m8/feeds/contacts/tester%40mochi.com/base/6</id>
|
||||||
|
<updated>2014-10-17T12:32:08.152Z</updated>
|
||||||
|
<app:edited xmlns:app="http://www.w3.org/2007/app">2014-10-17T12:32:08.152Z</app:edited>
|
||||||
|
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/contact/2008#contact"/>
|
||||||
|
<title/>
|
||||||
|
<link href="https://www.google.com/m8/feeds/photos/media/tester%40mochi.com/6" rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*"/>
|
||||||
|
<link href="https://www.google.com/m8/feeds/contacts/tester%40mochi.com/full/6" rel="self" type="application/atom+xml"/>
|
||||||
|
<link href="https://www.google.com/m8/feeds/contacts/tester%40mochi.com/full/6" rel="edit" type="application/atom+xml"/>
|
||||||
|
<gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile">215234523452345</gd:phoneNumber>
|
||||||
|
<gContact:groupMembershipInfo deleted="false" href="http://www.google.com/m8/feeds/groups/tester%40mochi.com/base/6"/>
|
||||||
|
</entry>
|
||||||
</feed>
|
</feed>
|
||||||
|
|
|
@ -218,6 +218,10 @@ const mockDb = {
|
||||||
_store: { },
|
_store: { },
|
||||||
_next_guid: 1,
|
_next_guid: 1,
|
||||||
|
|
||||||
|
get size() {
|
||||||
|
return Object.getOwnPropertyNames(this._store).length;
|
||||||
|
},
|
||||||
|
|
||||||
add: function(details, callback) {
|
add: function(details, callback) {
|
||||||
if (!("id" in details)) {
|
if (!("id" in details)) {
|
||||||
callback(new Error("No 'id' field present"));
|
callback(new Error("No 'id' field present"));
|
||||||
|
|
|
@ -36,6 +36,11 @@ describe("loop.store.ConversationStore", function () {
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
navigator.mozLoop = {
|
||||||
|
getLoopBoolPref: sandbox.stub(),
|
||||||
|
releaseCallData: sandbox.stub()
|
||||||
|
};
|
||||||
|
|
||||||
dispatcher = new loop.Dispatcher();
|
dispatcher = new loop.Dispatcher();
|
||||||
client = {
|
client = {
|
||||||
setupOutgoingCall: sinon.stub(),
|
setupOutgoingCall: sinon.stub(),
|
||||||
|
@ -120,6 +125,8 @@ describe("loop.store.ConversationStore", function () {
|
||||||
describe("#connectionFailure", function() {
|
describe("#connectionFailure", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
store._websocket = fakeWebsocket;
|
store._websocket = fakeWebsocket;
|
||||||
|
sandbox.stub(loop.shared.utils.Helper.prototype, "locationHash")
|
||||||
|
.returns("#outgoing/42");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disconnect the session", function() {
|
it("should disconnect the session", function() {
|
||||||
|
@ -145,6 +152,14 @@ describe("loop.store.ConversationStore", function () {
|
||||||
expect(store.get("callState")).eql(CALL_STATES.TERMINATED);
|
expect(store.get("callState")).eql(CALL_STATES.TERMINATED);
|
||||||
expect(store.get("callStateReason")).eql("fake");
|
expect(store.get("callStateReason")).eql("fake");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should release mozLoop callsData", function() {
|
||||||
|
dispatcher.dispatch(
|
||||||
|
new sharedActions.ConnectionFailure({reason: "fake"}));
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(navigator.mozLoop.releaseCallData);
|
||||||
|
sinon.assert.calledWithExactly(navigator.mozLoop.releaseCallData, "42");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#connectionProgress", function() {
|
describe("#connectionProgress", function() {
|
||||||
|
@ -481,6 +496,8 @@ describe("loop.store.ConversationStore", function () {
|
||||||
close: wsCloseSpy
|
close: wsCloseSpy
|
||||||
};
|
};
|
||||||
store.set({callState: CALL_STATES.ONGOING});
|
store.set({callState: CALL_STATES.ONGOING});
|
||||||
|
sandbox.stub(loop.shared.utils.Helper.prototype, "locationHash")
|
||||||
|
.returns("#outgoing/42");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disconnect the session", function() {
|
it("should disconnect the session", function() {
|
||||||
|
@ -506,6 +523,13 @@ describe("loop.store.ConversationStore", function () {
|
||||||
|
|
||||||
expect(store.get("callState")).eql(CALL_STATES.FINISHED);
|
expect(store.get("callState")).eql(CALL_STATES.FINISHED);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should release mozLoop callsData", function() {
|
||||||
|
dispatcher.dispatch(new sharedActions.HangupCall());
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(navigator.mozLoop.releaseCallData);
|
||||||
|
sinon.assert.calledWithExactly(navigator.mozLoop.releaseCallData, "42");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#peerHungupCall", function() {
|
describe("#peerHungupCall", function() {
|
||||||
|
@ -519,6 +543,8 @@ describe("loop.store.ConversationStore", function () {
|
||||||
close: wsCloseSpy
|
close: wsCloseSpy
|
||||||
};
|
};
|
||||||
store.set({callState: CALL_STATES.ONGOING});
|
store.set({callState: CALL_STATES.ONGOING});
|
||||||
|
sandbox.stub(loop.shared.utils.Helper.prototype, "locationHash")
|
||||||
|
.returns("#outgoing/42");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disconnect the session", function() {
|
it("should disconnect the session", function() {
|
||||||
|
@ -538,6 +564,13 @@ describe("loop.store.ConversationStore", function () {
|
||||||
|
|
||||||
expect(store.get("callState")).eql(CALL_STATES.FINISHED);
|
expect(store.get("callState")).eql(CALL_STATES.FINISHED);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should release mozLoop callsData", function() {
|
||||||
|
dispatcher.dispatch(new sharedActions.PeerHungupCall());
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(navigator.mozLoop.releaseCallData);
|
||||||
|
sinon.assert.calledWithExactly(navigator.mozLoop.releaseCallData, "42");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#cancelCall", function() {
|
describe("#cancelCall", function() {
|
||||||
|
@ -545,6 +578,8 @@ describe("loop.store.ConversationStore", function () {
|
||||||
store._websocket = fakeWebsocket;
|
store._websocket = fakeWebsocket;
|
||||||
|
|
||||||
store.set({callState: CALL_STATES.CONNECTING});
|
store.set({callState: CALL_STATES.CONNECTING});
|
||||||
|
sandbox.stub(loop.shared.utils.Helper.prototype, "locationHash")
|
||||||
|
.returns("#outgoing/42");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disconnect the session", function() {
|
it("should disconnect the session", function() {
|
||||||
|
@ -579,6 +614,12 @@ describe("loop.store.ConversationStore", function () {
|
||||||
expect(store.get("callState")).eql(CALL_STATES.CLOSE);
|
expect(store.get("callState")).eql(CALL_STATES.CLOSE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should release mozLoop callsData", function() {
|
||||||
|
dispatcher.dispatch(new sharedActions.CancelCall());
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(navigator.mozLoop.releaseCallData);
|
||||||
|
sinon.assert.calledWithExactly(navigator.mozLoop.releaseCallData, "42");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#retryCall", function() {
|
describe("#retryCall", function() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||||
|
|
||||||
Current extension version is: 1.0.801
|
Current extension version is: 1.0.907
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,9 @@ var DEFAULT_PREFERENCES = {
|
||||||
sidebarViewOnLoad: 0,
|
sidebarViewOnLoad: 0,
|
||||||
enableHandToolOnLoad: false,
|
enableHandToolOnLoad: false,
|
||||||
enableWebGL: false,
|
enableWebGL: false,
|
||||||
|
pdfBugEnabled: false,
|
||||||
disableRange: false,
|
disableRange: false,
|
||||||
|
disableStream: false,
|
||||||
disableAutoFetch: false,
|
disableAutoFetch: false,
|
||||||
disableFontFace: false,
|
disableFontFace: false,
|
||||||
disableTextLayer: false,
|
disableTextLayer: false,
|
||||||
|
|
|
@ -77,7 +77,8 @@ function getFindBar(domWindow) {
|
||||||
var browser = getContainingBrowser(domWindow);
|
var browser = getContainingBrowser(domWindow);
|
||||||
try {
|
try {
|
||||||
var tabbrowser = browser.getTabBrowser();
|
var tabbrowser = browser.getTabBrowser();
|
||||||
var tab = tabbrowser.getTabForBrowser(browser);
|
var tab;
|
||||||
|
tab = tabbrowser.getTabForBrowser(browser);
|
||||||
return tabbrowser.getFindBar(tab);
|
return tabbrowser.getFindBar(tab);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// FF22 has no _getTabForBrowser, and FF24 has no getFindBar
|
// FF22 has no _getTabForBrowser, and FF24 has no getFindBar
|
||||||
|
@ -162,40 +163,38 @@ function makeContentReadable(obj, window) {
|
||||||
// PDF data storage
|
// PDF data storage
|
||||||
function PdfDataListener(length) {
|
function PdfDataListener(length) {
|
||||||
this.length = length; // less than 0, if length is unknown
|
this.length = length; // less than 0, if length is unknown
|
||||||
this.data = new Uint8Array(length >= 0 ? length : 0x10000);
|
this.buffer = null;
|
||||||
this.loaded = 0;
|
this.loaded = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PdfDataListener.prototype = {
|
PdfDataListener.prototype = {
|
||||||
append: function PdfDataListener_append(chunk) {
|
append: function PdfDataListener_append(chunk) {
|
||||||
var willBeLoaded = this.loaded + chunk.length;
|
// In most of the cases we will pass data as we receive it, but at the
|
||||||
if (this.length >= 0 && this.length < willBeLoaded) {
|
// beginning of the loading we may accumulate some data.
|
||||||
|
if (!this.buffer) {
|
||||||
|
this.buffer = new Uint8Array(chunk);
|
||||||
|
} else {
|
||||||
|
var buffer = this.buffer;
|
||||||
|
var newBuffer = new Uint8Array(buffer.length + chunk.length);
|
||||||
|
newBuffer.set(buffer);
|
||||||
|
newBuffer.set(chunk, buffer.length);
|
||||||
|
this.buffer = newBuffer;
|
||||||
|
}
|
||||||
|
this.loaded += chunk.length;
|
||||||
|
if (this.length >= 0 && this.length < this.loaded) {
|
||||||
this.length = -1; // reset the length, server is giving incorrect one
|
this.length = -1; // reset the length, server is giving incorrect one
|
||||||
}
|
}
|
||||||
if (this.length < 0 && this.data.length < willBeLoaded) {
|
|
||||||
// data length is unknown and new chunk will not fit in the existing
|
|
||||||
// buffer, resizing the buffer by doubling the its last length
|
|
||||||
var newLength = this.data.length;
|
|
||||||
for (; newLength < willBeLoaded; newLength *= 2) {}
|
|
||||||
var newData = new Uint8Array(newLength);
|
|
||||||
newData.set(this.data);
|
|
||||||
this.data = newData;
|
|
||||||
}
|
|
||||||
this.data.set(chunk, this.loaded);
|
|
||||||
this.loaded = willBeLoaded;
|
|
||||||
this.onprogress(this.loaded, this.length >= 0 ? this.length : void(0));
|
this.onprogress(this.loaded, this.length >= 0 ? this.length : void(0));
|
||||||
},
|
},
|
||||||
getData: function PdfDataListener_getData() {
|
readData: function PdfDataListener_readData() {
|
||||||
var data = this.data;
|
var result = this.buffer;
|
||||||
if (this.loaded != data.length)
|
this.buffer = null;
|
||||||
data = data.subarray(0, this.loaded);
|
return result;
|
||||||
delete this.data; // releasing temporary storage
|
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
finish: function PdfDataListener_finish() {
|
finish: function PdfDataListener_finish() {
|
||||||
this.isDataReady = true;
|
this.isDataReady = true;
|
||||||
if (this.oncompleteCallback) {
|
if (this.oncompleteCallback) {
|
||||||
this.oncompleteCallback(this.getData());
|
this.oncompleteCallback(this.readData());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function PdfDataListener_error(errorCode) {
|
error: function PdfDataListener_error(errorCode) {
|
||||||
|
@ -211,7 +210,7 @@ PdfDataListener.prototype = {
|
||||||
set oncomplete(value) {
|
set oncomplete(value) {
|
||||||
this.oncompleteCallback = value;
|
this.oncompleteCallback = value;
|
||||||
if (this.isDataReady) {
|
if (this.isDataReady) {
|
||||||
value(this.getData());
|
value(this.readData());
|
||||||
}
|
}
|
||||||
if (this.errorCode) {
|
if (this.errorCode) {
|
||||||
value(null, this.errorCode);
|
value(null, this.errorCode);
|
||||||
|
@ -234,7 +233,7 @@ function ChromeActions(domWindow, contentDispositionFilename) {
|
||||||
|
|
||||||
ChromeActions.prototype = {
|
ChromeActions.prototype = {
|
||||||
isInPrivateBrowsing: function() {
|
isInPrivateBrowsing: function() {
|
||||||
return PrivateBrowsingUtils.isWindowPrivate(this.domWindow);
|
return PrivateBrowsingUtils.isContentWindowPrivate(this.domWindow);
|
||||||
},
|
},
|
||||||
download: function(data, sendResponse) {
|
download: function(data, sendResponse) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -329,9 +328,6 @@ ChromeActions.prototype = {
|
||||||
return 'null';
|
return 'null';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pdfBugEnabled: function() {
|
|
||||||
return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
|
|
||||||
},
|
|
||||||
supportsIntegratedFind: function() {
|
supportsIntegratedFind: function() {
|
||||||
// Integrated find is only supported when we're not in a frame
|
// Integrated find is only supported when we're not in a frame
|
||||||
if (this.domWindow.frameElement !== null) {
|
if (this.domWindow.frameElement !== null) {
|
||||||
|
@ -511,11 +507,13 @@ var RangedChromeActions = (function RangedChromeActionsClosure() {
|
||||||
*/
|
*/
|
||||||
function RangedChromeActions(
|
function RangedChromeActions(
|
||||||
domWindow, contentDispositionFilename, originalRequest,
|
domWindow, contentDispositionFilename, originalRequest,
|
||||||
dataListener) {
|
rangeEnabled, streamingEnabled, dataListener) {
|
||||||
|
|
||||||
ChromeActions.call(this, domWindow, contentDispositionFilename);
|
ChromeActions.call(this, domWindow, contentDispositionFilename);
|
||||||
this.dataListener = dataListener;
|
this.dataListener = dataListener;
|
||||||
this.originalRequest = originalRequest;
|
this.originalRequest = originalRequest;
|
||||||
|
this.rangeEnabled = rangeEnabled;
|
||||||
|
this.streamingEnabled = streamingEnabled;
|
||||||
|
|
||||||
this.pdfUrl = originalRequest.URI.spec;
|
this.pdfUrl = originalRequest.URI.spec;
|
||||||
this.contentLength = originalRequest.contentLength;
|
this.contentLength = originalRequest.contentLength;
|
||||||
|
@ -534,7 +532,9 @@ var RangedChromeActions = (function RangedChromeActionsClosure() {
|
||||||
this.headers[aHeader] = aValue;
|
this.headers[aHeader] = aValue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
originalRequest.visitRequestHeaders(httpHeaderVisitor);
|
if (originalRequest.visitRequestHeaders) {
|
||||||
|
originalRequest.visitRequestHeaders(httpHeaderVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var xhr_onreadystatechange = function xhr_onreadystatechange() {
|
var xhr_onreadystatechange = function xhr_onreadystatechange() {
|
||||||
|
@ -573,20 +573,46 @@ var RangedChromeActions = (function RangedChromeActionsClosure() {
|
||||||
proto.constructor = RangedChromeActions;
|
proto.constructor = RangedChromeActions;
|
||||||
|
|
||||||
proto.initPassiveLoading = function RangedChromeActions_initPassiveLoading() {
|
proto.initPassiveLoading = function RangedChromeActions_initPassiveLoading() {
|
||||||
this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
|
var self = this;
|
||||||
this.originalRequest = null;
|
var data;
|
||||||
|
if (!this.streamingEnabled) {
|
||||||
|
this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
|
||||||
|
this.originalRequest = null;
|
||||||
|
data = this.dataListener.readData();
|
||||||
|
this.dataListener = null;
|
||||||
|
} else {
|
||||||
|
data = this.dataListener.readData();
|
||||||
|
|
||||||
|
this.dataListener.onprogress = function (loaded, total) {
|
||||||
|
self.domWindow.postMessage({
|
||||||
|
pdfjsLoadAction: 'progressiveRead',
|
||||||
|
loaded: loaded,
|
||||||
|
total: total,
|
||||||
|
chunk: self.dataListener.readData()
|
||||||
|
}, '*');
|
||||||
|
};
|
||||||
|
this.dataListener.oncomplete = function () {
|
||||||
|
delete self.dataListener;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.domWindow.postMessage({
|
this.domWindow.postMessage({
|
||||||
pdfjsLoadAction: 'supportsRangedLoading',
|
pdfjsLoadAction: 'supportsRangedLoading',
|
||||||
|
rangeEnabled: this.rangeEnabled,
|
||||||
|
streamingEnabled: this.streamingEnabled,
|
||||||
pdfUrl: this.pdfUrl,
|
pdfUrl: this.pdfUrl,
|
||||||
length: this.contentLength,
|
length: this.contentLength,
|
||||||
data: this.dataListener.getData()
|
data: data
|
||||||
}, '*');
|
}, '*');
|
||||||
this.dataListener = null;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
proto.requestDataRange = function RangedChromeActions_requestDataRange(args) {
|
proto.requestDataRange = function RangedChromeActions_requestDataRange(args) {
|
||||||
|
if (!this.rangeEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var begin = args.begin;
|
var begin = args.begin;
|
||||||
var end = args.end;
|
var end = args.end;
|
||||||
var domWindow = this.domWindow;
|
var domWindow = this.domWindow;
|
||||||
|
@ -828,6 +854,7 @@ PdfStreamConverter.prototype = {
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
var rangeRequest = false;
|
var rangeRequest = false;
|
||||||
|
var streamRequest = false;
|
||||||
if (isHttpRequest) {
|
if (isHttpRequest) {
|
||||||
var contentEncoding = 'identity';
|
var contentEncoding = 'identity';
|
||||||
try {
|
try {
|
||||||
|
@ -840,10 +867,18 @@ PdfStreamConverter.prototype = {
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
var hash = aRequest.URI.ref;
|
var hash = aRequest.URI.ref;
|
||||||
|
var isPDFBugEnabled = getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
|
||||||
rangeRequest = contentEncoding === 'identity' &&
|
rangeRequest = contentEncoding === 'identity' &&
|
||||||
acceptRanges === 'bytes' &&
|
acceptRanges === 'bytes' &&
|
||||||
aRequest.contentLength >= 0 &&
|
aRequest.contentLength >= 0 &&
|
||||||
hash.indexOf('disableRange=true') < 0;
|
!getBoolPref(PREF_PREFIX + '.disableRange', false) &&
|
||||||
|
(!isPDFBugEnabled ||
|
||||||
|
hash.toLowerCase().indexOf('disablerange=true') < 0);
|
||||||
|
streamRequest = contentEncoding === 'identity' &&
|
||||||
|
aRequest.contentLength >= 0 &&
|
||||||
|
!getBoolPref(PREF_PREFIX + '.disableStream', false) &&
|
||||||
|
(!isPDFBugEnabled ||
|
||||||
|
hash.toLowerCase().indexOf('disablestream=true') < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
aRequest.QueryInterface(Ci.nsIChannel);
|
aRequest.QueryInterface(Ci.nsIChannel);
|
||||||
|
@ -897,12 +932,13 @@ PdfStreamConverter.prototype = {
|
||||||
// may have changed during a redirect.
|
// may have changed during a redirect.
|
||||||
var domWindow = getDOMWindow(channel);
|
var domWindow = getDOMWindow(channel);
|
||||||
var actions;
|
var actions;
|
||||||
if (rangeRequest) {
|
if (rangeRequest || streamRequest) {
|
||||||
actions = new RangedChromeActions(
|
actions = new RangedChromeActions(
|
||||||
domWindow, contentDispositionFilename, aRequest, dataListener);
|
domWindow, contentDispositionFilename, aRequest,
|
||||||
|
rangeRequest, streamRequest, dataListener);
|
||||||
} else {
|
} else {
|
||||||
actions = new StandardChromeActions(
|
actions = new StandardChromeActions(
|
||||||
domWindow, contentDispositionFilename, dataListener);
|
domWindow, contentDispositionFilename, dataListener);
|
||||||
}
|
}
|
||||||
var requestListener = new RequestListener(actions);
|
var requestListener = new RequestListener(actions);
|
||||||
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
|
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
|
||||||
|
|
|
@ -43,7 +43,9 @@ var DEFAULT_PREFERENCES = {
|
||||||
sidebarViewOnLoad: 0,
|
sidebarViewOnLoad: 0,
|
||||||
enableHandToolOnLoad: false,
|
enableHandToolOnLoad: false,
|
||||||
enableWebGL: false,
|
enableWebGL: false,
|
||||||
|
pdfBugEnabled: false,
|
||||||
disableRange: false,
|
disableRange: false,
|
||||||
|
disableStream: false,
|
||||||
disableAutoFetch: false,
|
disableAutoFetch: false,
|
||||||
disableFontFace: false,
|
disableFontFace: false,
|
||||||
disableTextLayer: false,
|
disableTextLayer: false,
|
||||||
|
@ -285,7 +287,8 @@ let PdfjsChromeUtils = {
|
||||||
*/
|
*/
|
||||||
function PdfjsFindbarWrapper(aBrowser) {
|
function PdfjsFindbarWrapper(aBrowser) {
|
||||||
let tabbrowser = aBrowser.getTabBrowser();
|
let tabbrowser = aBrowser.getTabBrowser();
|
||||||
let tab = tabbrowser.getTabForBrowser(aBrowser);
|
let tab;
|
||||||
|
tab = tabbrowser.getTabForBrowser(aBrowser);
|
||||||
this._findbar = tabbrowser.getFindBar(tab);
|
this._findbar = tabbrowser.getFindBar(tab);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') {
|
||||||
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFJS.version = '1.0.801';
|
PDFJS.version = '1.0.907';
|
||||||
PDFJS.build = 'e77e5c4';
|
PDFJS.build = 'e9072ac';
|
||||||
|
|
||||||
(function pdfjsWrapper() {
|
(function pdfjsWrapper() {
|
||||||
// Use strict in our context only - users might not want it
|
// Use strict in our context only - users might not want it
|
||||||
|
@ -1362,6 +1362,14 @@ PDFJS.workerSrc = (PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc);
|
||||||
PDFJS.disableRange = (PDFJS.disableRange === undefined ?
|
PDFJS.disableRange = (PDFJS.disableRange === undefined ?
|
||||||
false : PDFJS.disableRange);
|
false : PDFJS.disableRange);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable streaming of PDF file data. By default PDF.js attempts to load PDF
|
||||||
|
* in chunks. This default behavior can be disabled.
|
||||||
|
* @var {boolean}
|
||||||
|
*/
|
||||||
|
PDFJS.disableStream = (PDFJS.disableStream === undefined ?
|
||||||
|
false : PDFJS.disableStream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable pre-fetching of PDF file data. When range requests are enabled PDF.js
|
* Disable pre-fetching of PDF file data. When range requests are enabled PDF.js
|
||||||
* will automatically keep fetching more data even if it isn't needed to display
|
* will automatically keep fetching more data even if it isn't needed to display
|
||||||
|
@ -1560,10 +1568,20 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
|
||||||
/**
|
/**
|
||||||
* @return {Promise} A promise that is resolved with a lookup table for
|
* @return {Promise} A promise that is resolved with a lookup table for
|
||||||
* mapping named destinations to reference numbers.
|
* mapping named destinations to reference numbers.
|
||||||
|
*
|
||||||
|
* This can be slow for large documents: use getDestination instead
|
||||||
*/
|
*/
|
||||||
getDestinations: function PDFDocumentProxy_getDestinations() {
|
getDestinations: function PDFDocumentProxy_getDestinations() {
|
||||||
return this.transport.getDestinations();
|
return this.transport.getDestinations();
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @param {string} id The named destination to get.
|
||||||
|
* @return {Promise} A promise that is resolved with all information
|
||||||
|
* of the given named destination.
|
||||||
|
*/
|
||||||
|
getDestination: function PDFDocumentProxy_getDestination(id) {
|
||||||
|
return this.transport.getDestination(id);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @return {Promise} A promise that is resolved with a lookup table for
|
* @return {Promise} A promise that is resolved with a lookup table for
|
||||||
* mapping named attachments to their content.
|
* mapping named attachments to their content.
|
||||||
|
@ -2117,6 +2135,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pdfDataRangeTransport.addProgressiveReadListener(function(chunk) {
|
||||||
|
messageHandler.send('OnDataRange', {
|
||||||
|
chunk: chunk
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
messageHandler.on('RequestDataRange',
|
messageHandler.on('RequestDataRange',
|
||||||
function transportDataRange(data) {
|
function transportDataRange(data) {
|
||||||
pdfDataRangeTransport.requestDataRange(data.begin, data.end);
|
pdfDataRangeTransport.requestDataRange(data.begin, data.end);
|
||||||
|
@ -2177,6 +2201,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||||
this.downloadInfoCapability.resolve(data);
|
this.downloadInfoCapability.resolve(data);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
messageHandler.on('PDFManagerReady', function transportPage(data) {
|
||||||
|
if (this.pdfDataRangeTransport) {
|
||||||
|
this.pdfDataRangeTransport.transportReady();
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
messageHandler.on('StartRenderPage', function transportRender(data) {
|
messageHandler.on('StartRenderPage', function transportRender(data) {
|
||||||
var page = this.pageCache[data.pageIndex];
|
var page = this.pageCache[data.pageIndex];
|
||||||
|
|
||||||
|
@ -2208,7 +2238,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||||
this.commonObjs.resolve(id, error);
|
this.commonObjs.resolve(id, error);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
font = new FontFace(exportedData);
|
font = new FontFaceObject(exportedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontLoader.bind(
|
FontLoader.bind(
|
||||||
|
@ -2321,6 +2351,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||||
|
|
||||||
fetchDocument: function WorkerTransport_fetchDocument(source) {
|
fetchDocument: function WorkerTransport_fetchDocument(source) {
|
||||||
source.disableAutoFetch = PDFJS.disableAutoFetch;
|
source.disableAutoFetch = PDFJS.disableAutoFetch;
|
||||||
|
source.disableStream = PDFJS.disableStream;
|
||||||
source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
|
source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
|
||||||
this.messageHandler.send('GetDocRequest', {
|
this.messageHandler.send('GetDocRequest', {
|
||||||
source: source,
|
source: source,
|
||||||
|
@ -2372,6 +2403,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
||||||
return this.messageHandler.sendWithPromise('GetDestinations', null);
|
return this.messageHandler.sendWithPromise('GetDestinations', null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDestination: function WorkerTransport_getDestination(id) {
|
||||||
|
return this.messageHandler.sendWithPromise('GetDestination', { id: id } );
|
||||||
|
},
|
||||||
|
|
||||||
getAttachments: function WorkerTransport_getAttachments() {
|
getAttachments: function WorkerTransport_getAttachments() {
|
||||||
return this.messageHandler.sendWithPromise('GetAttachments', null);
|
return this.messageHandler.sendWithPromise('GetAttachments', null);
|
||||||
},
|
},
|
||||||
|
@ -5731,8 +5766,8 @@ var FontLoader = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var FontFace = (function FontFaceClosure() {
|
var FontFaceObject = (function FontFaceObjectClosure() {
|
||||||
function FontFace(name, file, properties) {
|
function FontFaceObject(name, file, properties) {
|
||||||
this.compiledGlyphs = {};
|
this.compiledGlyphs = {};
|
||||||
if (arguments.length === 1) {
|
if (arguments.length === 1) {
|
||||||
// importing translated data
|
// importing translated data
|
||||||
|
@ -5743,8 +5778,9 @@ var FontFace = (function FontFaceClosure() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FontFace.prototype = {
|
FontFaceObject.prototype = {
|
||||||
bindDOM: function FontFace_bindDOM() {
|
|
||||||
|
bindDOM: function FontFaceObject_bindDOM() {
|
||||||
if (!this.data) {
|
if (!this.data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -5771,7 +5807,7 @@ var FontFace = (function FontFaceClosure() {
|
||||||
return rule;
|
return rule;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPathGenerator: function (objs, character) {
|
getPathGenerator: function FontLoader_getPathGenerator(objs, character) {
|
||||||
if (!(character in this.compiledGlyphs)) {
|
if (!(character in this.compiledGlyphs)) {
|
||||||
var js = objs.get(this.loadedName + '_path_' + character);
|
var js = objs.get(this.loadedName + '_path_' + character);
|
||||||
/*jshint -W054 */
|
/*jshint -W054 */
|
||||||
|
@ -5780,7 +5816,7 @@ var FontFace = (function FontFaceClosure() {
|
||||||
return this.compiledGlyphs[character];
|
return this.compiledGlyphs[character];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return FontFace;
|
return FontFaceObject;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') {
|
||||||
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFJS.version = '1.0.801';
|
PDFJS.version = '1.0.907';
|
||||||
PDFJS.build = 'e77e5c4';
|
PDFJS.build = 'e9072ac';
|
||||||
|
|
||||||
(function pdfjsWrapper() {
|
(function pdfjsWrapper() {
|
||||||
// Use strict in our context only - users might not want it
|
// Use strict in our context only - users might not want it
|
||||||
|
@ -1309,7 +1309,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
this.numChunksLoaded = 0;
|
this.numChunksLoaded = 0;
|
||||||
this.numChunks = Math.ceil(length / chunkSize);
|
this.numChunks = Math.ceil(length / chunkSize);
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.initialDataLength = 0;
|
this.progressiveDataLength = 0;
|
||||||
this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache
|
this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1320,7 +1320,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
getMissingChunks: function ChunkedStream_getMissingChunks() {
|
getMissingChunks: function ChunkedStream_getMissingChunks() {
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
|
for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
chunks.push(chunk);
|
chunks.push(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1352,21 +1352,29 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
var curChunk;
|
var curChunk;
|
||||||
|
|
||||||
for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
||||||
if (!(curChunk in this.loadedChunks)) {
|
if (!this.loadedChunks[curChunk]) {
|
||||||
this.loadedChunks[curChunk] = true;
|
this.loadedChunks[curChunk] = true;
|
||||||
++this.numChunksLoaded;
|
++this.numChunksLoaded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onReceiveInitialData: function ChunkedStream_onReceiveInitialData(data) {
|
onReceiveProgressiveData:
|
||||||
this.bytes.set(data);
|
function ChunkedStream_onReceiveProgressiveData(data) {
|
||||||
this.initialDataLength = data.length;
|
var position = this.progressiveDataLength;
|
||||||
var endChunk = (this.end === data.length ?
|
var beginChunk = Math.floor(position / this.chunkSize);
|
||||||
this.numChunks : Math.floor(data.length / this.chunkSize));
|
|
||||||
for (var i = 0; i < endChunk; i++) {
|
this.bytes.set(new Uint8Array(data), position);
|
||||||
this.loadedChunks[i] = true;
|
position += data.byteLength;
|
||||||
++this.numChunksLoaded;
|
this.progressiveDataLength = position;
|
||||||
|
var endChunk = position >= this.end ? this.numChunks :
|
||||||
|
Math.floor(position / this.chunkSize);
|
||||||
|
var curChunk;
|
||||||
|
for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
|
||||||
|
if (!this.loadedChunks[curChunk]) {
|
||||||
|
this.loadedChunks[curChunk] = true;
|
||||||
|
++this.numChunksLoaded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1376,7 +1384,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
throw new MissingDataException(pos, pos + 1);
|
throw new MissingDataException(pos, pos + 1);
|
||||||
}
|
}
|
||||||
this.lastSuccessfulEnsureByteChunk = chunk;
|
this.lastSuccessfulEnsureByteChunk = chunk;
|
||||||
|
@ -1387,7 +1395,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end <= this.initialDataLength) {
|
if (end <= this.progressiveDataLength) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,7 +1403,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
var beginChunk = Math.floor(begin / chunkSize);
|
var beginChunk = Math.floor(begin / chunkSize);
|
||||||
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
|
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
|
||||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
throw new MissingDataException(begin, end);
|
throw new MissingDataException(begin, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1404,13 +1412,13 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
|
nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
|
||||||
var chunk, n;
|
var chunk, n;
|
||||||
for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
|
for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Wrap around to beginning
|
// Wrap around to beginning
|
||||||
for (chunk = 0; chunk < beginChunk; ++chunk) {
|
for (chunk = 0; chunk < beginChunk; ++chunk) {
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1418,7 +1426,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
},
|
},
|
||||||
|
|
||||||
hasChunk: function ChunkedStream_hasChunk(chunk) {
|
hasChunk: function ChunkedStream_hasChunk(chunk) {
|
||||||
return chunk in this.loadedChunks;
|
return !!this.loadedChunks[chunk];
|
||||||
},
|
},
|
||||||
|
|
||||||
get length() {
|
get length() {
|
||||||
|
@ -1517,7 +1525,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
|
||||||
var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
|
var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
|
||||||
var missingChunks = [];
|
var missingChunks = [];
|
||||||
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
|
||||||
if (!(chunk in this.loadedChunks)) {
|
if (!this.loadedChunks[chunk]) {
|
||||||
missingChunks.push(chunk);
|
missingChunks.push(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1575,28 +1583,16 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
|
||||||
this.chunksNeededByRequest = {};
|
this.chunksNeededByRequest = {};
|
||||||
this.requestsByChunk = {};
|
this.requestsByChunk = {};
|
||||||
this.callbacksByRequest = {};
|
this.callbacksByRequest = {};
|
||||||
|
this.progressiveDataLength = 0;
|
||||||
|
|
||||||
this._loadedStreamCapability = createPromiseCapability();
|
this._loadedStreamCapability = createPromiseCapability();
|
||||||
|
|
||||||
if (args.initialData) {
|
if (args.initialData) {
|
||||||
this.setInitialData(args.initialData);
|
this.onReceiveData({chunk: args.initialData});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkedStreamManager.prototype = {
|
ChunkedStreamManager.prototype = {
|
||||||
|
|
||||||
setInitialData: function ChunkedStreamManager_setInitialData(data) {
|
|
||||||
this.stream.onReceiveInitialData(data);
|
|
||||||
if (this.stream.allChunksLoaded()) {
|
|
||||||
this._loadedStreamCapability.resolve(this.stream);
|
|
||||||
} else if (this.msgHandler) {
|
|
||||||
this.msgHandler.send('DocProgress', {
|
|
||||||
loaded: data.length,
|
|
||||||
total: this.length
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
|
onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
|
||||||
return this._loadedStreamCapability.promise;
|
return this._loadedStreamCapability.promise;
|
||||||
},
|
},
|
||||||
|
@ -1734,13 +1730,21 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
|
||||||
|
|
||||||
onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
|
onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
|
||||||
var chunk = args.chunk;
|
var chunk = args.chunk;
|
||||||
var begin = args.begin;
|
var isProgressive = args.begin === undefined;
|
||||||
|
var begin = isProgressive ? this.progressiveDataLength : args.begin;
|
||||||
var end = begin + chunk.byteLength;
|
var end = begin + chunk.byteLength;
|
||||||
|
|
||||||
var beginChunk = this.getBeginChunk(begin);
|
var beginChunk = Math.floor(begin / this.chunkSize);
|
||||||
var endChunk = this.getEndChunk(end);
|
var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
|
||||||
|
Math.ceil(end / this.chunkSize);
|
||||||
|
|
||||||
|
if (isProgressive) {
|
||||||
|
this.stream.onReceiveProgressiveData(chunk);
|
||||||
|
this.progressiveDataLength = end;
|
||||||
|
} else {
|
||||||
|
this.stream.onReceiveData(begin, chunk);
|
||||||
|
}
|
||||||
|
|
||||||
this.stream.onReceiveData(begin, chunk);
|
|
||||||
if (this.stream.allChunksLoaded()) {
|
if (this.stream.allChunksLoaded()) {
|
||||||
this._loadedStreamCapability.resolve(this.stream);
|
this._loadedStreamCapability.resolve(this.stream);
|
||||||
}
|
}
|
||||||
|
@ -1877,6 +1881,10 @@ var BasePdfManager = (function BasePdfManagerClosure() {
|
||||||
return new NotImplementedException();
|
return new NotImplementedException();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {
|
||||||
|
return new NotImplementedException();
|
||||||
|
},
|
||||||
|
|
||||||
updatePassword: function BasePdfManager_updatePassword(password) {
|
updatePassword: function BasePdfManager_updatePassword(password) {
|
||||||
this.pdfDocument.xref.password = this.password = password;
|
this.pdfDocument.xref.password = this.password = password;
|
||||||
if (this._passwordChangedCapability) {
|
if (this._passwordChangedCapability) {
|
||||||
|
@ -2013,6 +2021,11 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
|
||||||
this.streamManager.requestAllChunks();
|
this.streamManager.requestAllChunks();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NetworkPdfManager.prototype.sendProgressiveData =
|
||||||
|
function NetworkPdfManager_sendProgressiveData(chunk) {
|
||||||
|
this.streamManager.onReceiveData({ chunk: chunk });
|
||||||
|
};
|
||||||
|
|
||||||
NetworkPdfManager.prototype.onLoadedStream =
|
NetworkPdfManager.prototype.onLoadedStream =
|
||||||
function NetworkPdfManager_getLoadedStream() {
|
function NetworkPdfManager_getLoadedStream() {
|
||||||
return this.streamManager.onLoadedStream();
|
return this.streamManager.onLoadedStream();
|
||||||
|
@ -2959,6 +2972,38 @@ var Catalog = (function CatalogClosure() {
|
||||||
}
|
}
|
||||||
return shadow(this, 'destinations', dests);
|
return shadow(this, 'destinations', dests);
|
||||||
},
|
},
|
||||||
|
getDestination: function Catalog_getDestination(destinationId) {
|
||||||
|
function fetchDestination(dest) {
|
||||||
|
return isDict(dest) ? dest.get('D') : dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xref = this.xref;
|
||||||
|
var dest, nameTreeRef, nameDictionaryRef;
|
||||||
|
var obj = this.catDict.get('Names');
|
||||||
|
if (obj && obj.has('Dests')) {
|
||||||
|
nameTreeRef = obj.getRaw('Dests');
|
||||||
|
} else if (this.catDict.has('Dests')) {
|
||||||
|
nameDictionaryRef = this.catDict.get('Dests');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameDictionaryRef) {
|
||||||
|
// reading simple destination dictionary
|
||||||
|
obj = nameDictionaryRef;
|
||||||
|
obj.forEach(function catalogForEach(key, value) {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key === destinationId) {
|
||||||
|
dest = fetchDestination(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (nameTreeRef) {
|
||||||
|
var nameTree = new NameTree(nameTreeRef, xref);
|
||||||
|
dest = fetchDestination(nameTree.get(destinationId));
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
},
|
||||||
get attachments() {
|
get attachments() {
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var attachments = null, nameTreeRef;
|
var attachments = null, nameTreeRef;
|
||||||
|
@ -3860,6 +3905,76 @@ var NameTree = (function NameTreeClosure() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dict;
|
return dict;
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function NameTree_get(destinationId) {
|
||||||
|
if (!this.root) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xref = this.xref;
|
||||||
|
var kidsOrNames = xref.fetchIfRef(this.root);
|
||||||
|
var loopCount = 0;
|
||||||
|
var MAX_NAMES_LEVELS = 10;
|
||||||
|
var l, r, m;
|
||||||
|
|
||||||
|
// Perform a binary search to quickly find the entry that
|
||||||
|
// contains the named destination we are looking for.
|
||||||
|
while (kidsOrNames.has('Kids')) {
|
||||||
|
loopCount++;
|
||||||
|
if (loopCount > MAX_NAMES_LEVELS) {
|
||||||
|
warn('Search depth limit for named destionations has been reached.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var kids = kidsOrNames.get('Kids');
|
||||||
|
if (!isArray(kids)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
r = kids.length - 1;
|
||||||
|
while (l <= r) {
|
||||||
|
m = (l + r) >> 1;
|
||||||
|
var kid = xref.fetchIfRef(kids[m]);
|
||||||
|
var limits = kid.get('Limits');
|
||||||
|
|
||||||
|
if (destinationId < limits[0]) {
|
||||||
|
r = m - 1;
|
||||||
|
} else if (destinationId > limits[1]) {
|
||||||
|
l = m + 1;
|
||||||
|
} else {
|
||||||
|
kidsOrNames = xref.fetchIfRef(kids[m]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l > r) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, then we have found the right entry. Now
|
||||||
|
// go through the named destinations in the Named dictionary
|
||||||
|
// until we find the exact destination we're looking for.
|
||||||
|
var names = kidsOrNames.get('Names');
|
||||||
|
if (isArray(names)) {
|
||||||
|
// Perform a binary search to reduce the lookup time.
|
||||||
|
l = 0;
|
||||||
|
r = names.length - 2;
|
||||||
|
while (l <= r) {
|
||||||
|
// Check only even indices (0, 2, 4, ...) because the
|
||||||
|
// odd indices contain the actual D array.
|
||||||
|
m = (l + r) & ~1;
|
||||||
|
if (destinationId < names[m]) {
|
||||||
|
r = m - 2;
|
||||||
|
} else if (destinationId > names[m]) {
|
||||||
|
l = m + 2;
|
||||||
|
} else {
|
||||||
|
return xref.fetchIfRef(names[m + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return NameTree;
|
return NameTree;
|
||||||
|
@ -15857,6 +15972,12 @@ var Font = (function FontClosure() {
|
||||||
for (var code in GlyphMapForStandardFonts) {
|
for (var code in GlyphMapForStandardFonts) {
|
||||||
map[+code] = GlyphMapForStandardFonts[code];
|
map[+code] = GlyphMapForStandardFonts[code];
|
||||||
}
|
}
|
||||||
|
var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
|
||||||
|
if (!isIdentityUnicode) {
|
||||||
|
this.toUnicode.forEach(function(charCode, unicodeCharCode) {
|
||||||
|
map[+charCode] = unicodeCharCode;
|
||||||
|
});
|
||||||
|
}
|
||||||
this.toFontChar = map;
|
this.toFontChar = map;
|
||||||
this.toUnicode = new ToUnicodeMap(map);
|
this.toUnicode = new ToUnicodeMap(map);
|
||||||
} else if (/Symbol/i.test(fontName)) {
|
} else if (/Symbol/i.test(fontName)) {
|
||||||
|
@ -15868,6 +15989,13 @@ var Font = (function FontClosure() {
|
||||||
}
|
}
|
||||||
this.toFontChar[charCode] = fontChar;
|
this.toFontChar[charCode] = fontChar;
|
||||||
}
|
}
|
||||||
|
for (charCode in properties.differences) {
|
||||||
|
fontChar = GlyphsUnicode[properties.differences[charCode]];
|
||||||
|
if (!fontChar) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.toFontChar[charCode] = fontChar;
|
||||||
|
}
|
||||||
} else if (/Dingbats/i.test(fontName)) {
|
} else if (/Dingbats/i.test(fontName)) {
|
||||||
var dingbats = Encodings.ZapfDingbatsEncoding;
|
var dingbats = Encodings.ZapfDingbatsEncoding;
|
||||||
for (charCode in dingbats) {
|
for (charCode in dingbats) {
|
||||||
|
@ -15928,6 +16056,9 @@ var Font = (function FontClosure() {
|
||||||
|
|
||||||
var data;
|
var data;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case 'MMType1':
|
||||||
|
info('MMType1 font (' + name + '), falling back to Type1.');
|
||||||
|
/* falls through */
|
||||||
case 'Type1':
|
case 'Type1':
|
||||||
case 'CIDFontType0':
|
case 'CIDFontType0':
|
||||||
this.mimetype = 'font/opentype';
|
this.mimetype = 'font/opentype';
|
||||||
|
@ -31206,7 +31337,7 @@ var JpegStream = (function JpegStreamClosure() {
|
||||||
var jpegImage = new JpegImage();
|
var jpegImage = new JpegImage();
|
||||||
|
|
||||||
// checking if values needs to be transformed before conversion
|
// checking if values needs to be transformed before conversion
|
||||||
if (this.dict && isArray(this.dict.get('Decode'))) {
|
if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
|
||||||
var decodeArr = this.dict.get('Decode');
|
var decodeArr = this.dict.get('Decode');
|
||||||
var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
|
var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
|
||||||
var decodeArrLength = decodeArr.length;
|
var decodeArrLength = decodeArr.length;
|
||||||
|
@ -32840,6 +32971,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
httpHeaders: source.httpHeaders,
|
httpHeaders: source.httpHeaders,
|
||||||
withCredentials: source.withCredentials
|
withCredentials: source.withCredentials
|
||||||
});
|
});
|
||||||
|
var cachedChunks = [];
|
||||||
var fullRequestXhrId = networkManager.requestFull({
|
var fullRequestXhrId = networkManager.requestFull({
|
||||||
onHeadersReceived: function onHeadersReceived() {
|
onHeadersReceived: function onHeadersReceived() {
|
||||||
if (disableRange) {
|
if (disableRange) {
|
||||||
|
@ -32870,11 +33002,18 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: by cancelling the full request, and then issuing range
|
if (networkManager.isStreamingRequest(fullRequestXhrId)) {
|
||||||
// requests, there will be an issue for sites where you can only
|
// We can continue fetching when progressive loading is enabled,
|
||||||
// request the pdf once. However, if this is the case, then the
|
// and we don't need the autoFetch feature.
|
||||||
// server should not be returning that it can support range requests.
|
source.disableAutoFetch = true;
|
||||||
networkManager.abortRequest(fullRequestXhrId);
|
} else {
|
||||||
|
// NOTE: by cancelling the full request, and then issuing range
|
||||||
|
// requests, there will be an issue for sites where you can only
|
||||||
|
// request the pdf once. However, if this is the case, then the
|
||||||
|
// server should not be returning that it can support range
|
||||||
|
// requests.
|
||||||
|
networkManager.abortRequest(fullRequestXhrId);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pdfManager = new NetworkPdfManager(source, handler);
|
pdfManager = new NetworkPdfManager(source, handler);
|
||||||
|
@ -32884,10 +33023,44 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onProgressiveData: source.disableStream ? null :
|
||||||
|
function onProgressiveData(chunk) {
|
||||||
|
if (!pdfManager) {
|
||||||
|
cachedChunks.push(chunk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pdfManager.sendProgressiveData(chunk);
|
||||||
|
},
|
||||||
|
|
||||||
onDone: function onDone(args) {
|
onDone: function onDone(args) {
|
||||||
|
if (pdfManager) {
|
||||||
|
return; // already processed
|
||||||
|
}
|
||||||
|
|
||||||
|
var pdfFile;
|
||||||
|
if (args === null) {
|
||||||
|
// TODO add some streaming manager, e.g. for unknown length files.
|
||||||
|
// The data was returned in the onProgressiveData, combining...
|
||||||
|
var pdfFileLength = 0, pos = 0;
|
||||||
|
cachedChunks.forEach(function (chunk) {
|
||||||
|
pdfFileLength += chunk.byteLength;
|
||||||
|
});
|
||||||
|
if (source.length && pdfFileLength !== source.length) {
|
||||||
|
warn('reported HTTP length is different from actual');
|
||||||
|
}
|
||||||
|
var pdfFileArray = new Uint8Array(pdfFileLength);
|
||||||
|
cachedChunks.forEach(function (chunk) {
|
||||||
|
pdfFileArray.set(new Uint8Array(chunk), pos);
|
||||||
|
pos += chunk.byteLength;
|
||||||
|
});
|
||||||
|
pdfFile = pdfFileArray.buffer;
|
||||||
|
} else {
|
||||||
|
pdfFile = args.chunk;
|
||||||
|
}
|
||||||
|
|
||||||
// the data is array, instantiating directly from it
|
// the data is array, instantiating directly from it
|
||||||
try {
|
try {
|
||||||
pdfManager = new LocalPdfManager(args.chunk, source.password);
|
pdfManager = new LocalPdfManager(pdfFile, source.password);
|
||||||
pdfManagerCapability.resolve();
|
pdfManagerCapability.resolve();
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
pdfManagerCapability.reject(ex);
|
pdfManagerCapability.reject(ex);
|
||||||
|
@ -32982,6 +33155,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
PDFJS.cMapPacked = data.cMapPacked === true;
|
PDFJS.cMapPacked = data.cMapPacked === true;
|
||||||
|
|
||||||
getPdfManager(data).then(function () {
|
getPdfManager(data).then(function () {
|
||||||
|
handler.send('PDFManagerReady', null);
|
||||||
pdfManager.onLoadedStream().then(function(stream) {
|
pdfManager.onLoadedStream().then(function(stream) {
|
||||||
handler.send('DataLoaded', { length: stream.bytes.byteLength });
|
handler.send('DataLoaded', { length: stream.bytes.byteLength });
|
||||||
});
|
});
|
||||||
|
@ -33036,6 +33210,12 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
handler.on('GetDestination',
|
||||||
|
function wphSetupGetDestination(data) {
|
||||||
|
return pdfManager.ensureCatalog('getDestination', [ data.id ]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
handler.on('GetAttachments',
|
handler.on('GetAttachments',
|
||||||
function wphSetupGetAttachments(data) {
|
function wphSetupGetAttachments(data) {
|
||||||
return pdfManager.ensureCatalog('attachments');
|
return pdfManager.ensureCatalog('attachments');
|
||||||
|
|
|
@ -62,11 +62,11 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
var length = data.length;
|
var length = data.length;
|
||||||
var buffer = new Uint8Array(length);
|
var array = new Uint8Array(length);
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
buffer[i] = data.charCodeAt(i) & 0xFF;
|
array[i] = data.charCodeAt(i) & 0xFF;
|
||||||
}
|
}
|
||||||
return buffer;
|
return array.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManager.prototype = {
|
NetworkManager.prototype = {
|
||||||
|
@ -81,11 +81,11 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||||
return this.request(args);
|
return this.request(args);
|
||||||
},
|
},
|
||||||
|
|
||||||
requestFull: function NetworkManager_requestRange(listeners) {
|
requestFull: function NetworkManager_requestFull(listeners) {
|
||||||
return this.request(listeners);
|
return this.request(listeners);
|
||||||
},
|
},
|
||||||
|
|
||||||
request: function NetworkManager_requestRange(args) {
|
request: function NetworkManager_request(args) {
|
||||||
var xhr = this.getXhr();
|
var xhr = this.getXhr();
|
||||||
var xhrId = this.currXhrId++;
|
var xhrId = this.currXhrId++;
|
||||||
var pendingRequest = this.pendingRequests[xhrId] = {
|
var pendingRequest = this.pendingRequests[xhrId] = {
|
||||||
|
@ -109,27 +109,54 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||||
pendingRequest.expectedStatus = 200;
|
pendingRequest.expectedStatus = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.responseType = 'arraybuffer';
|
if (args.onProgressiveData) {
|
||||||
|
xhr.responseType = 'moz-chunked-arraybuffer';
|
||||||
if (args.onProgress) {
|
if (xhr.responseType === 'moz-chunked-arraybuffer') {
|
||||||
xhr.onprogress = args.onProgress;
|
pendingRequest.onProgressiveData = args.onProgressiveData;
|
||||||
|
pendingRequest.mozChunked = true;
|
||||||
|
} else {
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.onError) {
|
if (args.onError) {
|
||||||
xhr.onerror = function(evt) {
|
xhr.onerror = function(evt) {
|
||||||
args.onError(xhr.status);
|
args.onError(xhr.status);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
|
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
|
||||||
|
xhr.onprogress = this.onProgress.bind(this, xhrId);
|
||||||
|
|
||||||
pendingRequest.onHeadersReceived = args.onHeadersReceived;
|
pendingRequest.onHeadersReceived = args.onHeadersReceived;
|
||||||
pendingRequest.onDone = args.onDone;
|
pendingRequest.onDone = args.onDone;
|
||||||
pendingRequest.onError = args.onError;
|
pendingRequest.onError = args.onError;
|
||||||
|
pendingRequest.onProgress = args.onProgress;
|
||||||
|
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
|
|
||||||
return xhrId;
|
return xhrId;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onProgress: function NetworkManager_onProgress(xhrId, evt) {
|
||||||
|
var pendingRequest = this.pendingRequests[xhrId];
|
||||||
|
if (!pendingRequest) {
|
||||||
|
// Maybe abortRequest was called...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingRequest.mozChunked) {
|
||||||
|
var chunk = getArrayBuffer(pendingRequest.xhr);
|
||||||
|
pendingRequest.onProgressiveData(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
var onProgress = pendingRequest.onProgress;
|
||||||
|
if (onProgress) {
|
||||||
|
onProgress(evt);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
|
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
|
||||||
var pendingRequest = this.pendingRequests[xhrId];
|
var pendingRequest = this.pendingRequests[xhrId];
|
||||||
if (!pendingRequest) {
|
if (!pendingRequest) {
|
||||||
|
@ -190,6 +217,8 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||||
begin: begin,
|
begin: begin,
|
||||||
chunk: chunk
|
chunk: chunk
|
||||||
});
|
});
|
||||||
|
} else if (pendingRequest.onProgressiveData) {
|
||||||
|
pendingRequest.onDone(null);
|
||||||
} else {
|
} else {
|
||||||
pendingRequest.onDone({
|
pendingRequest.onDone({
|
||||||
begin: 0,
|
begin: 0,
|
||||||
|
@ -209,6 +238,10 @@ var NetworkManager = (function NetworkManagerClosure() {
|
||||||
return this.pendingRequests[xhrId].xhr;
|
return this.pendingRequests[xhrId].xhr;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
|
||||||
|
return !!(this.pendingRequests[xhrId].onProgressiveData);
|
||||||
|
},
|
||||||
|
|
||||||
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
|
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
|
||||||
return xhrId in this.pendingRequests;
|
return xhrId in this.pendingRequests;
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/* jshint esnext:true */
|
/* jshint esnext:true */
|
||||||
/* globals Components, PdfjsContentUtils, PdfJs */
|
/* globals Components, PdfjsContentUtils, PdfJs, Services */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
|
@ -112,13 +112,20 @@ var FontInspector = (function FontInspectorClosure() {
|
||||||
return moreInfo;
|
return moreInfo;
|
||||||
}
|
}
|
||||||
var moreInfo = properties(fontObj, ['name', 'type']);
|
var moreInfo = properties(fontObj, ['name', 'type']);
|
||||||
var m = /url\(['"]?([^\)"']+)/.exec(url);
|
|
||||||
var fontName = fontObj.loadedName;
|
var fontName = fontObj.loadedName;
|
||||||
var font = document.createElement('div');
|
var font = document.createElement('div');
|
||||||
var name = document.createElement('span');
|
var name = document.createElement('span');
|
||||||
name.textContent = fontName;
|
name.textContent = fontName;
|
||||||
var download = document.createElement('a');
|
var download = document.createElement('a');
|
||||||
download.href = m[1];
|
if (url) {
|
||||||
|
url = /url\(['"]?([^\)"']+)/.exec(url);
|
||||||
|
download.href = url[1];
|
||||||
|
} else if (fontObj.data) {
|
||||||
|
url = URL.createObjectURL(new Blob([fontObj.data], {
|
||||||
|
type: fontObj.mimeType
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
download.href = url;
|
||||||
download.textContent = 'Download';
|
download.textContent = 'Download';
|
||||||
var logIt = document.createElement('a');
|
var logIt = document.createElement('a');
|
||||||
logIt.href = '';
|
logIt.href = '';
|
||||||
|
@ -211,6 +218,7 @@ var StepperManager = (function StepperManagerClosure() {
|
||||||
},
|
},
|
||||||
selectStepper: function selectStepper(pageIndex, selectPanel) {
|
selectStepper: function selectStepper(pageIndex, selectPanel) {
|
||||||
var i;
|
var i;
|
||||||
|
pageIndex = pageIndex | 0;
|
||||||
if (selectPanel) {
|
if (selectPanel) {
|
||||||
this.manager.selectPanel(this);
|
this.manager.selectPanel(this);
|
||||||
}
|
}
|
||||||
|
@ -419,7 +427,7 @@ var Stepper = (function StepperClosure() {
|
||||||
var allRows = this.panel.getElementsByClassName('line');
|
var allRows = this.panel.getElementsByClassName('line');
|
||||||
for (var x = 0, xx = allRows.length; x < xx; ++x) {
|
for (var x = 0, xx = allRows.length; x < xx; ++x) {
|
||||||
var row = allRows[x];
|
var row = allRows[x];
|
||||||
if (parseInt(row.dataset.idx, 10) === idx) {
|
if ((row.dataset.idx | 0) === idx) {
|
||||||
row.style.backgroundColor = 'rgb(251,250,207)';
|
row.style.backgroundColor = 'rgb(251,250,207)';
|
||||||
row.scrollIntoView();
|
row.scrollIntoView();
|
||||||
} else {
|
} else {
|
||||||
|
|
Двоичные данные
browser/extensions/pdfjs/content/web/images/loading-small.png
Двоичные данные
browser/extensions/pdfjs/content/web/images/loading-small.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 3.5 KiB После Ширина: | Высота: | Размер: 7.2 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 16 KiB |
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2012 Mozilla Foundation
|
/* Copyright 2014 Mozilla Foundation
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -13,6 +13,141 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.textLayer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer > div {
|
||||||
|
color: transparent;
|
||||||
|
position: absolute;
|
||||||
|
white-space: pre;
|
||||||
|
cursor: text;
|
||||||
|
-moz-transform-origin: 0% 0%;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight {
|
||||||
|
margin: -1px;
|
||||||
|
padding: 1px;
|
||||||
|
|
||||||
|
background-color: rgb(180, 0, 170);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight.begin {
|
||||||
|
border-radius: 4px 0px 0px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight.end {
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight.middle {
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight.selected {
|
||||||
|
background-color: rgb(0, 100, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .canvasWrapper {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page {
|
||||||
|
direction: ltr;
|
||||||
|
width: 816px;
|
||||||
|
height: 1056px;
|
||||||
|
margin: 1px auto -8px auto;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
border: 9px solid transparent;
|
||||||
|
background-clip: content-box;
|
||||||
|
border-image: url(images/shadow.png) 9 9 repeat;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page canvas {
|
||||||
|
margin: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .loadingIcon {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: url('images/loading-icon.gif') center no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotLink > a:hover {
|
||||||
|
opacity: 0.2;
|
||||||
|
background: #ff0;
|
||||||
|
box-shadow: 0px 2px 10px #ff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-moz-full-screen .pdfViewer .page {
|
||||||
|
margin-bottom: 100%;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:fullscreen .pdfViewer .page {
|
||||||
|
margin-bottom: 100%;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotationHighlight {
|
||||||
|
position: absolute;
|
||||||
|
border: 2px #FFFF99 solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotText > img {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotTextContentWrapper {
|
||||||
|
position: absolute;
|
||||||
|
width: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotTextContent {
|
||||||
|
z-index: 200;
|
||||||
|
float: left;
|
||||||
|
max-width: 20em;
|
||||||
|
background-color: #FFFF99;
|
||||||
|
box-shadow: 0px 2px 5px #333;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0.6em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotTextContent > h1 {
|
||||||
|
font-size: 1em;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotTextContent > p {
|
||||||
|
padding-top: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdfViewer .page .annotLink > a {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 1em;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -65,16 +200,6 @@ select {
|
||||||
cursor: none;
|
cursor: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
:-moz-full-screen .page {
|
|
||||||
margin-bottom: 100%;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:fullscreen .page {
|
|
||||||
margin-bottom: 100%;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:-moz-full-screen a:not(.internalLink) {
|
:-moz-full-screen a:not(.internalLink) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -984,6 +1109,12 @@ html[dir='rtl'] .verticalToolbarSeparator {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbarField.pageNumber.visiblePageIsLoading {
|
||||||
|
background-image: url(images/loading-small.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.toolbarField:hover {
|
.toolbarField:hover {
|
||||||
background-color: hsla(0,0%,100%,.11);
|
background-color: hsla(0,0%,100%,.11);
|
||||||
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
|
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
|
||||||
|
@ -1167,135 +1298,17 @@ html[dir='rtl'] .attachmentsItem > button {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.canvasWrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
margin: 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
direction: ltr;
|
|
||||||
width: 816px;
|
|
||||||
height: 1056px;
|
|
||||||
margin: 1px auto -8px auto;
|
|
||||||
position: relative;
|
|
||||||
overflow: visible;
|
|
||||||
border: 9px solid transparent;
|
|
||||||
background-clip: content-box;
|
|
||||||
border-image: url(images/shadow.png) 9 9 repeat;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotLink > a:hover {
|
|
||||||
opacity: 0.2;
|
|
||||||
background: #ff0;
|
|
||||||
box-shadow: 0px 2px 10px #ff0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loadingIcon {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: url('images/loading-icon.gif') center no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer > div {
|
|
||||||
color: transparent;
|
|
||||||
position: absolute;
|
|
||||||
white-space: pre;
|
|
||||||
cursor: text;
|
|
||||||
-moz-transform-origin: 0% 0%;
|
|
||||||
transform-origin: 0% 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer .highlight {
|
|
||||||
margin: -1px;
|
|
||||||
padding: 1px;
|
|
||||||
|
|
||||||
background-color: rgba(180, 0, 170, 0.2);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer .highlight.begin {
|
|
||||||
border-radius: 4px 0px 0px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer .highlight.end {
|
|
||||||
border-radius: 0px 4px 4px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer .highlight.middle {
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textLayer .highlight.selected {
|
|
||||||
background-color: rgba(0, 100, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||||
so we can override the opaque grey background when the window is inactive;
|
so we can override the opaque grey background when the window is inactive;
|
||||||
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
||||||
::selection { background:rgba(0,0,255,0.3); }
|
::selection { background: rgba(0,0,255,0.3); }
|
||||||
::-moz-selection { background:rgba(0,0,255,0.3); }
|
::-moz-selection { background: rgba(0,0,255,0.3); }
|
||||||
|
|
||||||
.annotationHighlight {
|
.textLayer ::selection { background: rgb(0,0,255); }
|
||||||
position: absolute;
|
.textLayer ::-moz-selection { background: rgb(0,0,255); }
|
||||||
border: 2px #FFFF99 solid;
|
.textLayer {
|
||||||
}
|
opacity: 0.2;
|
||||||
|
|
||||||
.annotText > img {
|
|
||||||
position: absolute;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotTextContentWrapper {
|
|
||||||
position: absolute;
|
|
||||||
width: 20em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotTextContent {
|
|
||||||
z-index: 200;
|
|
||||||
float: left;
|
|
||||||
max-width: 20em;
|
|
||||||
background-color: #FFFF99;
|
|
||||||
box-shadow: 0px 2px 5px #333;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 0.6em;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotTextContent > h1 {
|
|
||||||
font-size: 1em;
|
|
||||||
border-bottom: 1px solid #000000;
|
|
||||||
padding-bottom: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotTextContent > p {
|
|
||||||
padding-top: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotLink > a {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 1em;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#errorWrapper {
|
#errorWrapper {
|
||||||
|
@ -1477,11 +1490,9 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
|
||||||
.debuggerShowText {
|
.debuggerShowText {
|
||||||
background: none repeat scroll 0 0 yellow;
|
background: none repeat scroll 0 0 yellow;
|
||||||
color: blue;
|
color: blue;
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
.debuggerHideText:hover {
|
.debuggerHideText:hover {
|
||||||
background: none repeat scroll 0 0 yellow;
|
background: none repeat scroll 0 0 yellow;
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
#PDFBug .stats {
|
#PDFBug .stats {
|
||||||
font-family: courier;
|
font-family: courier;
|
||||||
|
@ -1561,6 +1572,12 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
|
||||||
left: 186px;
|
left: 186px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbarField.pageNumber.visiblePageIsLoading,
|
||||||
|
#findInput[data-status="pending"] {
|
||||||
|
background-image: url(images/loading-small@2x.png);
|
||||||
|
background-size: 16px 17px;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdownToolbarButton {
|
.dropdownToolbarButton {
|
||||||
background: url(images/toolbarButton-menuArrows@2x.png) no-repeat;
|
background: url(images/toolbarButton-menuArrows@2x.png) no-repeat;
|
||||||
background-size: 7px 16px;
|
background-size: 7px 16px;
|
||||||
|
@ -1710,6 +1727,8 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
|
||||||
display: none;
|
display: none;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
background-clip: content-box;
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page[data-loaded] {
|
.page[data-loaded] {
|
||||||
|
@ -1731,6 +1750,7 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||||
</menu>
|
</menu>
|
||||||
|
|
||||||
<div id="viewerContainer" tabindex="0">
|
<div id="viewerContainer" tabindex="0">
|
||||||
<div id="viewer"></div>
|
<div id="viewer" class="pdfViewer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="errorWrapper" hidden='true'>
|
<div id="errorWrapper" hidden='true'>
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -97,7 +97,7 @@ quit-button.tooltiptext.linux2 = Quit %1$S (%2$S)
|
||||||
# %2$S is the keyboard shortcut
|
# %2$S is the keyboard shortcut
|
||||||
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
|
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
|
||||||
|
|
||||||
# LOCALIZATION NOTE(loop-call-button2.label2): This is a brand name, request
|
# LOCALIZATION NOTE(loop-call-button3.label): This is a brand name, request
|
||||||
# approval before you change it.
|
# approval before you change it.
|
||||||
loop-call-button3.label = Hello
|
loop-call-button3.label = Hello
|
||||||
loop-call-button2.tooltiptext = Start a conversation
|
loop-call-button2.tooltiptext = Start a conversation
|
||||||
|
|
|
@ -2068,15 +2068,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
|
||||||
|
|
||||||
/* Social toolbar item */
|
/* Social toolbar item */
|
||||||
|
|
||||||
#social-provider-button {
|
|
||||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
|
||||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-provider-button > .toolbarbutton-menu-dropmarker {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-notification-icon[popupid="servicesInstall"] {
|
.popup-notification-icon[popupid="servicesInstall"] {
|
||||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4366,64 +4366,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === social toolbar button === */
|
|
||||||
|
|
||||||
#social-toolbar-item > .toolbarbutton-1 {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(ltr) {
|
|
||||||
-moz-border-end-width: 0;
|
|
||||||
}
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:last-child:-moz-locale-dir(ltr) {
|
|
||||||
-moz-border-end-width: 1px;
|
|
||||||
}
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(rtl) {
|
|
||||||
-moz-border-start-width: 0;
|
|
||||||
}
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:first-child:-moz-locale-dir(rtl) {
|
|
||||||
-moz-border-start-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(ltr):first-child,
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(rtl):last-child {
|
|
||||||
margin-left: 4px;
|
|
||||||
border-top-left-radius: 3px;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
}
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(rtl):first-child,
|
|
||||||
#social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(ltr):last-child {
|
|
||||||
margin-right: 4px;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
border-bottom-right-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-toolbar-item > toolbaritem {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-provider-button {
|
|
||||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-resolution: 2dppx) {
|
|
||||||
#social-provider-button {
|
|
||||||
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
|
|
||||||
}
|
|
||||||
#social-provider-button > .toolbarbutton-icon {
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-provider-button > .toolbarbutton-menu-dropmarker {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-notification-icon[popupid="servicesInstall"] {
|
.popup-notification-icon[popupid="servicesInstall"] {
|
||||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||||
}
|
}
|
||||||
|
|
|
@ -623,7 +623,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||||
-moz-padding-end: 5px;
|
-moz-padding-end: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) {
|
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
@ -698,7 +698,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
|
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
|
||||||
#nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
|
#nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
|
||||||
-moz-padding-end: 17px;
|
-moz-padding-end: 17px;
|
||||||
}
|
}
|
||||||
|
@ -2677,15 +2677,6 @@ notification[value="translation"] {
|
||||||
|
|
||||||
/* Social toolbar item */
|
/* Social toolbar item */
|
||||||
|
|
||||||
#social-provider-button {
|
|
||||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
|
||||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
#social-provider-button > .toolbarbutton-menu-dropmarker {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#switch-to-metro-button[cui-areatype="toolbar"] {
|
#switch-to-metro-button[cui-areatype="toolbar"] {
|
||||||
list-style-image: url(chrome://browser/skin/Metro_Glyph.png);
|
list-style-image: url(chrome://browser/skin/Metro_Glyph.png);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1788,7 +1788,7 @@ public class BrowserApp extends GeckoApp
|
||||||
mTabsPanel.prepareTabsAnimation(mMainLayoutAnimator);
|
mTabsPanel.prepareTabsAnimation(mMainLayoutAnimator);
|
||||||
mBrowserToolbar.triggerTabsPanelTransition(mMainLayoutAnimator, areTabsShown());
|
mBrowserToolbar.triggerTabsPanelTransition(mMainLayoutAnimator, areTabsShown());
|
||||||
|
|
||||||
// If the tabs layout is animating onto the screen, pin the dynamic
|
// If the tabs panel is animating onto the screen, pin the dynamic
|
||||||
// toolbar.
|
// toolbar.
|
||||||
if (mDynamicToolbar.isEnabled()) {
|
if (mDynamicToolbar.isEnabled()) {
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
|
@ -2376,7 +2376,7 @@ public class BrowserApp extends GeckoApp
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides certain UI elements (e.g. button toast, tabs tray) when the
|
* Hides certain UI elements (e.g. button toast, tabs panel) when the
|
||||||
* user touches the main layout.
|
* user touches the main layout.
|
||||||
*/
|
*/
|
||||||
private class HideOnTouchListener implements TouchEventInterceptor {
|
private class HideOnTouchListener implements TouchEventInterceptor {
|
||||||
|
@ -2412,7 +2412,7 @@ public class BrowserApp extends GeckoApp
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the tab tray is showing, hide the tab tray and don't send the event to content.
|
// If the tabs panel is showing, hide the tab panel and don't send the event to content.
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) {
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) {
|
||||||
mIsHidingTabs = true;
|
mIsHidingTabs = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -128,7 +128,7 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
|
||||||
lastModifiedView.setText(TabsAccessor.getLastSyncedString(context, now, client.lastModified));
|
lastModifiedView.setText(TabsAccessor.getLastSyncedString(context, now, client.lastModified));
|
||||||
|
|
||||||
// These views exists only in some of our group views: they are present
|
// These views exists only in some of our group views: they are present
|
||||||
// for the home panel groups and not for the tabs tray groups.
|
// for the home panel groups and not for the tabs panel groups.
|
||||||
// Therefore, we must handle null.
|
// Therefore, we must handle null.
|
||||||
final ImageView deviceTypeView = (ImageView) view.findViewById(R.id.device_type);
|
final ImageView deviceTypeView = (ImageView) view.findViewById(R.id.device_type);
|
||||||
if (deviceTypeView != null) {
|
if (deviceTypeView != null) {
|
||||||
|
@ -174,7 +174,7 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
|
||||||
final RemoteTab tab = client.tabs.get(childPosition);
|
final RemoteTab tab = client.tabs.get(childPosition);
|
||||||
|
|
||||||
// The view is a TwoLinePageRow only for some of our child views: it's
|
// The view is a TwoLinePageRow only for some of our child views: it's
|
||||||
// present for the home panel children and not for the tabs tray
|
// present for the home panel children and not for the tabs panel
|
||||||
// children. Therefore, we must handle one case manually.
|
// children. Therefore, we must handle one case manually.
|
||||||
if (view instanceof TwoLinePageRow) {
|
if (view instanceof TwoLinePageRow) {
|
||||||
((TwoLinePageRow) view).update(tab.title, tab.url);
|
((TwoLinePageRow) view).update(tab.title, tab.url);
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<view class="org.mozilla.gecko.tabs.TabsPanel$PanelViewContainer"
|
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayoutContainer"
|
||||||
android:id="@+id/tabs_container"
|
android:id="@+id/tabs_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dip"
|
android:layout_height="0dip"
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
||||||
android:id="@+id/normal_tabs"
|
android:id="@+id/normal_tabs"
|
||||||
style="@style/TabsList"
|
style="@style/TabsLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:choiceMode="singleChoice"
|
android:choiceMode="singleChoice"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1.0"
|
android:layout_weight="1.0"
|
||||||
android:paddingTop="4dip"
|
android:paddingTop="4dip"
|
||||||
style="@style/TabRowTextAppearance"
|
style="@style/TabLayoutItemTextAppearance"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#FFFFFFFF"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
|
|
@ -45,11 +45,11 @@
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<!-- Note: for an unknown reason, scrolling in the TabsListLayout
|
<!-- Note: for an unknown reason, scrolling in the TabsLayout
|
||||||
does not work unless it is laid out after the empty view. -->
|
does not work unless it is laid out after the empty view. -->
|
||||||
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
||||||
android:id="@+id/private_tabs_tray"
|
android:id="@+id/private_tabs_layout"
|
||||||
style="@style/TabsList"
|
style="@style/TabsLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:choiceMode="singleChoice"
|
android:choiceMode="singleChoice"
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1.0"
|
android:layout_weight="1.0"
|
||||||
android:padding="4dip"
|
android:padding="4dip"
|
||||||
style="@style/TabRowTextAppearance"
|
style="@style/TabLayoutItemTextAppearance"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textColor="#FF222222"
|
android:textColor="#FF222222"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
android:paddingTop="4dip"
|
android:paddingTop="4dip"
|
||||||
android:paddingLeft="8dip"
|
android:paddingLeft="8dip"
|
||||||
android:paddingRight="4dip"
|
android:paddingRight="4dip"
|
||||||
style="@style/TabRowTextAppearance"
|
style="@style/TabLayoutItemTextAppearance"
|
||||||
android:textColor="#FFFFFFFF"
|
android:textColor="#FFFFFFFF"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:singleLine="false"
|
android:singleLine="false"
|
||||||
|
|
|
@ -50,14 +50,14 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<view class="org.mozilla.gecko.tabs.TabsPanel$PanelViewContainer"
|
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayoutContainer"
|
||||||
android:id="@+id/tabs_container"
|
android:id="@+id/tabs_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
<view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
|
||||||
android:id="@+id/normal_tabs"
|
android:id="@+id/normal_tabs"
|
||||||
style="@style/TabsList"
|
style="@style/TabsLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:choiceMode="singleChoice"
|
android:choiceMode="singleChoice"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="TabsList" parent="TabsListBase">
|
<style name="TabsLayout" parent="TabsLayoutBase">
|
||||||
<item name="android:orientation">horizontal</item>
|
<item name="android:orientation">horizontal</item>
|
||||||
<item name="android:scrollbars">horizontal</item>
|
<item name="android:scrollbars">horizontal</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="TabsList" parent="TabsListBase">
|
<style name="TabsLayout" parent="TabsLayoutBase">
|
||||||
<item name="android:orientation">vertical</item>
|
<item name="android:orientation">vertical</item>
|
||||||
<item name="android:scrollbars">vertical</item>
|
<item name="android:scrollbars">vertical</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<item name="android:orientation">horizontal</item>
|
<item name="android:orientation">horizontal</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TabsList" parent="TabsListBase">
|
<style name="TabsLayout" parent="TabsLayoutBase">
|
||||||
<item name="android:orientation">horizontal</item>
|
<item name="android:orientation">horizontal</item>
|
||||||
<item name="android:scrollbars">horizontal</item>
|
<item name="android:scrollbars">horizontal</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -51,8 +51,8 @@
|
||||||
<item name="android:displayOptions">showHome|homeAsUp|showTitle</item>
|
<item name="android:displayOptions">showHome|homeAsUp|showTitle</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- TabsTray ActionBar -->
|
<!-- TabsLayout ActionBar -->
|
||||||
<style name="ActionBar.TabsTray">
|
<style name="ActionBar.TabsLayout">
|
||||||
<item name="android:visibility">gone</item>
|
<item name="android:visibility">gone</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
<attr name="entryKeys" format="string"/>
|
<attr name="entryKeys" format="string"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="TabsTray">
|
<declare-styleable name="TabsLayout">
|
||||||
<attr name="tabs">
|
<attr name="tabs">
|
||||||
<flag name="tabs_normal" value="0x00" />
|
<flag name="tabs_normal" value="0x00" />
|
||||||
<flag name="tabs_private" value ="0x01" />
|
<flag name="tabs_private" value ="0x01" />
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
<dimen name="tabs_strip_button_width">100dp</dimen>
|
<dimen name="tabs_strip_button_width">100dp</dimen>
|
||||||
<dimen name="tabs_strip_button_padding">18dp</dimen>
|
<dimen name="tabs_strip_button_padding">18dp</dimen>
|
||||||
<dimen name="tabs_strip_shadow_size">1dp</dimen>
|
<dimen name="tabs_strip_shadow_size">1dp</dimen>
|
||||||
<dimen name="tabs_tray_horizontal_height">156dp</dimen>
|
<dimen name="tabs_layout_horizontal_height">156dp</dimen>
|
||||||
<dimen name="text_selection_handle_width">47dp</dimen>
|
<dimen name="text_selection_handle_width">47dp</dimen>
|
||||||
<dimen name="text_selection_handle_height">58dp</dimen>
|
<dimen name="text_selection_handle_height">58dp</dimen>
|
||||||
<dimen name="text_selection_handle_shadow">11dp</dimen>
|
<dimen name="text_selection_handle_shadow">11dp</dimen>
|
||||||
|
|
|
@ -480,13 +480,13 @@
|
||||||
<item name="android:layout_weight">0.0</item>
|
<item name="android:layout_weight">0.0</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- TabsTray List -->
|
<!-- TabsLayout -->
|
||||||
<style name="TabsListBase">
|
<style name="TabsLayoutBase">
|
||||||
<item name="android:background">@android:color/transparent</item>
|
<item name="android:background">@android:color/transparent</item>
|
||||||
<item name="android:listSelector">@android:color/transparent</item>
|
<item name="android:listSelector">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TabsList" parent="TabsListBase">
|
<style name="TabsLayout" parent="TabsLayoutBase">
|
||||||
<item name="android:orientation">vertical</item>
|
<item name="android:orientation">vertical</item>
|
||||||
<item name="android:scrollbars">vertical</item>
|
<item name="android:scrollbars">vertical</item>
|
||||||
</style>
|
</style>
|
||||||
|
@ -615,15 +615,15 @@
|
||||||
<item name="android:drawSelectorOnTop">true</item>
|
<item name="android:drawSelectorOnTop">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- TabsTray Row -->
|
<!-- TabsLayout Row -->
|
||||||
<style name="TabRowTextAppearance">
|
<style name="TabLayoutItemTextAppearance">
|
||||||
<item name="android:textColor">#FFFFFFFF</item>
|
<item name="android:textColor">#FFFFFFFF</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
<item name="android:ellipsize">middle</item>
|
<item name="android:ellipsize">middle</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- TabsTray RemoteTabs Row Url -->
|
<!-- TabsLayout RemoteTabs Row Url -->
|
||||||
<style name="TabRowTextAppearance.Url">
|
<style name="TabLayoutItemTextAppearance.Url">
|
||||||
<item name="android:textColor">#FFA4A7A9</item>
|
<item name="android:textColor">#FFA4A7A9</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ class PrivateTabsPanel extends FrameLayout implements CloseAllPanelView {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
LayoutInflater.from(context).inflate(R.layout.private_tabs_panel, this);
|
LayoutInflater.from(context).inflate(R.layout.private_tabs_panel, this);
|
||||||
tabsLayout = (TabsLayout) findViewById(R.id.private_tabs_tray);
|
tabsLayout = (TabsLayout) findViewById(R.id.private_tabs_layout);
|
||||||
|
|
||||||
final View emptyView = findViewById(R.id.private_tabs_empty);
|
final View emptyView = findViewById(R.id.private_tabs_empty);
|
||||||
tabsLayout.setEmptyView(emptyView);
|
tabsLayout.setEmptyView(emptyView);
|
||||||
|
|
|
@ -47,8 +47,8 @@ class TabsGridLayout extends GridView
|
||||||
super(context, attrs, R.attr.tabGridLayoutViewStyle);
|
super(context, attrs, R.attr.tabGridLayoutViewStyle);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsTray);
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsLayout);
|
||||||
mIsPrivate = (a.getInt(R.styleable.TabsTray_tabs, 0x0) == 1);
|
mIsPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
|
|
||||||
mTabsAdapter = new TabsGridLayoutAdapter(mContext);
|
mTabsAdapter = new TabsGridLayoutAdapter(mContext);
|
||||||
|
|
|
@ -65,8 +65,8 @@ class TabsListLayout extends TwoWayView
|
||||||
|
|
||||||
setItemsCanFocus(true);
|
setItemsCanFocus(true);
|
||||||
|
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsTray);
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsLayout);
|
||||||
mIsPrivate = (a.getInt(R.styleable.TabsTray_tabs, 0x0) == 1);
|
mIsPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
|
|
||||||
mTabsAdapter = new TabsListLayoutAdapter(mContext);
|
mTabsAdapter = new TabsListLayoutAdapter(mContext);
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class TabsPanel extends LinearLayout
|
||||||
private final GeckoApp mActivity;
|
private final GeckoApp mActivity;
|
||||||
private final LightweightTheme mTheme;
|
private final LightweightTheme mTheme;
|
||||||
private RelativeLayout mHeader;
|
private RelativeLayout mHeader;
|
||||||
private PanelViewContainer mPanelsContainer;
|
private TabsLayoutContainer mTabsContainer;
|
||||||
private PanelView mPanel;
|
private PanelView mPanel;
|
||||||
private PanelView mPanelNormal;
|
private PanelView mPanelNormal;
|
||||||
private PanelView mPanelPrivate;
|
private PanelView mPanelPrivate;
|
||||||
|
@ -152,7 +152,7 @@ public class TabsPanel extends LinearLayout
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
|
mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
|
||||||
mPanelsContainer = (PanelViewContainer) findViewById(R.id.tabs_container);
|
mTabsContainer = (TabsLayoutContainer) findViewById(R.id.tabs_container);
|
||||||
|
|
||||||
mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
|
mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
|
||||||
mPanelNormal.setTabsPanel(this);
|
mPanelNormal.setTabsPanel(this);
|
||||||
|
@ -279,19 +279,19 @@ public class TabsPanel extends LinearLayout
|
||||||
return mActivity.onOptionsItemSelected(item);
|
return mActivity.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getPanelsContainerHeight(PanelViewContainer panelsContainer) {
|
private static int getTabContainerHeight(TabsLayoutContainer tabsContainer) {
|
||||||
Resources resources = panelsContainer.getContext().getResources();
|
Resources resources = tabsContainer.getContext().getResources();
|
||||||
|
|
||||||
PanelView panelView = panelsContainer.getCurrentPanelView();
|
PanelView panelView = tabsContainer.getCurrentPanelView();
|
||||||
if (panelView != null && !panelView.shouldExpand()) {
|
if (panelView != null && !panelView.shouldExpand()) {
|
||||||
return resources.getDimensionPixelSize(R.dimen.tabs_tray_horizontal_height);
|
return resources.getDimensionPixelSize(R.dimen.tabs_layout_horizontal_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
|
int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
|
||||||
int screenHeight = resources.getDisplayMetrics().heightPixels;
|
int screenHeight = resources.getDisplayMetrics().heightPixels;
|
||||||
|
|
||||||
Rect windowRect = new Rect();
|
Rect windowRect = new Rect();
|
||||||
panelsContainer.getWindowVisibleDisplayFrame(windowRect);
|
tabsContainer.getWindowVisibleDisplayFrame(windowRect);
|
||||||
int windowHeight = windowRect.bottom - windowRect.top;
|
int windowHeight = windowRect.bottom - windowRect.top;
|
||||||
|
|
||||||
// The web content area should have at least 1.5x the height of the action bar.
|
// The web content area should have at least 1.5x the height of the action bar.
|
||||||
|
@ -338,9 +338,8 @@ public class TabsPanel extends LinearLayout
|
||||||
onLightweightThemeChanged();
|
onLightweightThemeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panel View Container holds the ListView
|
static class TabsLayoutContainer extends FrameLayout {
|
||||||
static class PanelViewContainer extends FrameLayout {
|
public TabsLayoutContainer(Context context, AttributeSet attrs) {
|
||||||
public PanelViewContainer(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +360,7 @@ public class TabsPanel extends LinearLayout
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
if (!GeckoAppShell.getGeckoInterface().hasTabsSideBar()) {
|
if (!GeckoAppShell.getGeckoInterface().hasTabsSideBar()) {
|
||||||
int heightSpec = MeasureSpec.makeMeasureSpec(getPanelsContainerHeight(PanelViewContainer.this), MeasureSpec.EXACTLY);
|
int heightSpec = MeasureSpec.makeMeasureSpec(getTabContainerHeight(TabsLayoutContainer.this), MeasureSpec.EXACTLY);
|
||||||
super.onMeasure(widthMeasureSpec, heightSpec);
|
super.onMeasure(widthMeasureSpec, heightSpec);
|
||||||
} else {
|
} else {
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
@ -483,7 +482,7 @@ public class TabsPanel extends LinearLayout
|
||||||
dispatchLayoutChange(getWidth(), getHeight());
|
dispatchLayoutChange(getWidth(), getHeight());
|
||||||
} else {
|
} else {
|
||||||
int actionBarHeight = mContext.getResources().getDimensionPixelSize(R.dimen.browser_toolbar_height);
|
int actionBarHeight = mContext.getResources().getDimensionPixelSize(R.dimen.browser_toolbar_height);
|
||||||
int height = actionBarHeight + getPanelsContainerHeight(mPanelsContainer);
|
int height = actionBarHeight + getTabContainerHeight(mTabsContainer);
|
||||||
dispatchLayoutChange(getWidth(), height);
|
dispatchLayoutChange(getWidth(), height);
|
||||||
}
|
}
|
||||||
mHeaderVisible = true;
|
mHeaderVisible = true;
|
||||||
|
@ -502,7 +501,7 @@ public class TabsPanel extends LinearLayout
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
removeAllViews();
|
removeAllViews();
|
||||||
|
|
||||||
LayoutInflater.from(mContext).inflate(R.layout.tabs_panel, this);
|
inflateLayout(mContext);
|
||||||
initialize();
|
initialize();
|
||||||
|
|
||||||
if (mVisible)
|
if (mVisible)
|
||||||
|
@ -541,13 +540,13 @@ public class TabsPanel extends LinearLayout
|
||||||
final int tabsPanelWidth = getWidth();
|
final int tabsPanelWidth = getWidth();
|
||||||
if (mVisible) {
|
if (mVisible) {
|
||||||
ViewHelper.setTranslationX(mHeader, -tabsPanelWidth);
|
ViewHelper.setTranslationX(mHeader, -tabsPanelWidth);
|
||||||
ViewHelper.setTranslationX(mPanelsContainer, -tabsPanelWidth);
|
ViewHelper.setTranslationX(mTabsContainer, -tabsPanelWidth);
|
||||||
|
|
||||||
// The footer view is only present on the sidebar, v11+.
|
// The footer view is only present on the sidebar, v11+.
|
||||||
ViewHelper.setTranslationX(mFooter, -tabsPanelWidth);
|
ViewHelper.setTranslationX(mFooter, -tabsPanelWidth);
|
||||||
}
|
}
|
||||||
final int translationX = (mVisible ? 0 : -tabsPanelWidth);
|
final int translationX = (mVisible ? 0 : -tabsPanelWidth);
|
||||||
animator.attach(mPanelsContainer, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
animator.attach(mTabsContainer, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
||||||
animator.attach(mHeader, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
animator.attach(mHeader, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
||||||
animator.attach(mFooter, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
animator.attach(mFooter, PropertyAnimator.Property.TRANSLATION_X, translationX);
|
||||||
|
|
||||||
|
@ -557,16 +556,16 @@ public class TabsPanel extends LinearLayout
|
||||||
final int translationY = (mVisible ? 0 : -toolbarHeight);
|
final int translationY = (mVisible ? 0 : -toolbarHeight);
|
||||||
if (mVisible) {
|
if (mVisible) {
|
||||||
ViewHelper.setTranslationY(mHeader, -toolbarHeight);
|
ViewHelper.setTranslationY(mHeader, -toolbarHeight);
|
||||||
ViewHelper.setTranslationY(mPanelsContainer, -toolbarHeight);
|
ViewHelper.setTranslationY(mTabsContainer, -toolbarHeight);
|
||||||
ViewHelper.setAlpha(mPanelsContainer, 0.0f);
|
ViewHelper.setAlpha(mTabsContainer, 0.0f);
|
||||||
}
|
}
|
||||||
animator.attach(mPanelsContainer, PropertyAnimator.Property.ALPHA, mVisible ? 1.0f : 0.0f);
|
animator.attach(mTabsContainer, PropertyAnimator.Property.ALPHA, mVisible ? 1.0f : 0.0f);
|
||||||
animator.attach(mPanelsContainer, PropertyAnimator.Property.TRANSLATION_Y, translationY);
|
animator.attach(mTabsContainer, PropertyAnimator.Property.TRANSLATION_Y, translationY);
|
||||||
animator.attach(mHeader, PropertyAnimator.Property.TRANSLATION_Y, translationY);
|
animator.attach(mHeader, PropertyAnimator.Property.TRANSLATION_Y, translationY);
|
||||||
}
|
}
|
||||||
|
|
||||||
mHeader.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
mHeader.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||||
mPanelsContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
mTabsContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishTabsAnimation() {
|
public void finishTabsAnimation() {
|
||||||
|
@ -575,10 +574,10 @@ public class TabsPanel extends LinearLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
mHeader.setLayerType(View.LAYER_TYPE_NONE, null);
|
mHeader.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
mPanelsContainer.setLayerType(View.LAYER_TYPE_NONE, null);
|
mTabsContainer.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
|
||||||
// If the tray is now hidden, call hide() on current panel and unset it as the current panel
|
// If the tabs panel is now hidden, call hide() on current panel and unset it as the current panel
|
||||||
// to avoid hide() being called again when the tray is opened next.
|
// to avoid hide() being called again when the layout is opened next.
|
||||||
if (!mVisible && mPanel != null) {
|
if (!mVisible && mPanel != null) {
|
||||||
mPanel.hide();
|
mPanel.hide();
|
||||||
mPanel = null;
|
mPanel = null;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.mozilla.gecko.GeckoEvent;
|
||||||
import org.mozilla.gecko.GeckoProfile;
|
import org.mozilla.gecko.GeckoProfile;
|
||||||
import org.mozilla.gecko.GeckoThread;
|
import org.mozilla.gecko.GeckoThread;
|
||||||
import org.mozilla.gecko.GeckoThread.LaunchState;
|
import org.mozilla.gecko.GeckoThread.LaunchState;
|
||||||
|
import org.mozilla.gecko.NewTabletUI;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
import org.mozilla.gecko.RobocopUtils;
|
import org.mozilla.gecko.RobocopUtils;
|
||||||
import org.mozilla.gecko.Tab;
|
import org.mozilla.gecko.Tab;
|
||||||
|
@ -69,6 +70,8 @@ abstract class BaseTest extends BaseRobocopTest {
|
||||||
private static final int GECKO_READY_WAIT_MS = 180000;
|
private static final int GECKO_READY_WAIT_MS = 180000;
|
||||||
public static final int MAX_WAIT_BLOCK_FOR_EVENT_DATA_MS = 90000;
|
public static final int MAX_WAIT_BLOCK_FOR_EVENT_DATA_MS = 90000;
|
||||||
|
|
||||||
|
private static final String URL_HTTP_PREFIX = "http://";
|
||||||
|
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
private int mPreferenceRequestID = 0;
|
private int mPreferenceRequestID = 0;
|
||||||
protected Solo mSolo;
|
protected Solo mSolo;
|
||||||
|
@ -527,7 +530,25 @@ abstract class BaseTest extends BaseRobocopTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void verifyPageTitle(String title) {
|
public final void verifyPageTitle(final String title, String url) {
|
||||||
|
// We are asserting visible state - we shouldn't know if the title is null.
|
||||||
|
mAsserter.isnot(title, null, "The title argument is not null");
|
||||||
|
mAsserter.isnot(url, null, "The url argument is not null");
|
||||||
|
|
||||||
|
// TODO: We should also check the title bar preference.
|
||||||
|
final String expected;
|
||||||
|
if (!NewTabletUI.isEnabled(mActivity)) {
|
||||||
|
expected = title;
|
||||||
|
} else {
|
||||||
|
if (StringHelper.ABOUT_HOME_URL.equals(url)) {
|
||||||
|
expected = StringHelper.ABOUT_HOME_TITLE;
|
||||||
|
} else if (url.startsWith(URL_HTTP_PREFIX)) {
|
||||||
|
expected = url.substring(URL_HTTP_PREFIX.length());
|
||||||
|
} else {
|
||||||
|
expected = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final TextView urlBarTitle = (TextView) mSolo.getView(R.id.url_bar_title);
|
final TextView urlBarTitle = (TextView) mSolo.getView(R.id.url_bar_title);
|
||||||
String pageTitle = null;
|
String pageTitle = null;
|
||||||
if (urlBarTitle != null) {
|
if (urlBarTitle != null) {
|
||||||
|
@ -536,7 +557,7 @@ abstract class BaseTest extends BaseRobocopTest {
|
||||||
waitForCondition(new VerifyTextViewText(urlBarTitle, title), MAX_WAIT_VERIFY_PAGE_TITLE_MS);
|
waitForCondition(new VerifyTextViewText(urlBarTitle, title), MAX_WAIT_VERIFY_PAGE_TITLE_MS);
|
||||||
pageTitle = urlBarTitle.getText().toString();
|
pageTitle = urlBarTitle.getText().toString();
|
||||||
}
|
}
|
||||||
mAsserter.is(pageTitle, title, "Page title is correct");
|
mAsserter.is(pageTitle, expected, "Page title is correct");
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void verifyTabCount(int expectedTabCount) {
|
public final void verifyTabCount(int expectedTabCount) {
|
||||||
|
@ -619,23 +640,23 @@ abstract class BaseTest extends BaseRobocopTest {
|
||||||
/**
|
/**
|
||||||
* Gets the AdapterView of the tabs list.
|
* Gets the AdapterView of the tabs list.
|
||||||
*
|
*
|
||||||
* @return List view in the tabs tray
|
* @return List view in the tabs panel
|
||||||
*/
|
*/
|
||||||
private final AdapterView<ListAdapter> getTabsList() {
|
private final AdapterView<ListAdapter> getTabsLayout() {
|
||||||
Element tabs = mDriver.findElement(getActivity(), R.id.tabs);
|
Element tabs = mDriver.findElement(getActivity(), R.id.tabs);
|
||||||
tabs.click();
|
tabs.click();
|
||||||
return (AdapterView<ListAdapter>) getActivity().findViewById(R.id.normal_tabs);
|
return (AdapterView<ListAdapter>) getActivity().findViewById(R.id.normal_tabs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the view in the tabs tray at the specified index.
|
* Gets the view in the tabs panel at the specified index.
|
||||||
*
|
*
|
||||||
* @return View at index
|
* @return View at index
|
||||||
*/
|
*/
|
||||||
private View getTabViewAt(final int index) {
|
private View getTabViewAt(final int index) {
|
||||||
final View[] childView = { null };
|
final View[] childView = { null };
|
||||||
|
|
||||||
final AdapterView<ListAdapter> view = getTabsList();
|
final AdapterView<ListAdapter> view = getTabsLayout();
|
||||||
|
|
||||||
runOnUiThreadSync(new Runnable() {
|
runOnUiThreadSync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -197,7 +197,7 @@ public abstract class SessionTest extends BaseTest {
|
||||||
verifyUrl(page.url);
|
verifyUrl(page.url);
|
||||||
} else {
|
} else {
|
||||||
waitForText(page.title);
|
waitForText(page.title);
|
||||||
verifyPageTitle(page.title);
|
verifyPageTitle(page.title, page.url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,12 @@ import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertFalse;
|
||||||
import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
|
import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
|
||||||
import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
|
import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.NewTabletUI;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.tests.StringHelper;
|
||||||
import org.mozilla.gecko.tests.UITestContext;
|
import org.mozilla.gecko.tests.UITestContext;
|
||||||
import org.mozilla.gecko.tests.helpers.DeviceHelper;
|
import org.mozilla.gecko.tests.helpers.DeviceHelper;
|
||||||
|
import org.mozilla.gecko.tests.helpers.NavigationHelper;
|
||||||
import org.mozilla.gecko.tests.helpers.WaitHelper;
|
import org.mozilla.gecko.tests.helpers.WaitHelper;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -26,6 +29,9 @@ import com.jayway.android.robotium.solo.Solo;
|
||||||
* A class representing any interactions that take place on the Toolbar.
|
* A class representing any interactions that take place on the Toolbar.
|
||||||
*/
|
*/
|
||||||
public class ToolbarComponent extends BaseComponent {
|
public class ToolbarComponent extends BaseComponent {
|
||||||
|
|
||||||
|
private static final String URL_HTTP_PREFIX = "http://";
|
||||||
|
|
||||||
public ToolbarComponent(final UITestContext testContext) {
|
public ToolbarComponent(final UITestContext testContext) {
|
||||||
super(testContext);
|
super(testContext);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +46,26 @@ public class ToolbarComponent extends BaseComponent {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ToolbarComponent assertTitle(final String expected) {
|
public ToolbarComponent assertTitle(final String title, final String url) {
|
||||||
|
// We are asserting visible state - we shouldn't know if the title is null.
|
||||||
|
fAssertNotNull("The title argument is not null", title);
|
||||||
|
fAssertNotNull("The url argument is not null", url);
|
||||||
|
|
||||||
|
// TODO: We should also check the title bar preference.
|
||||||
|
final String expected;
|
||||||
|
if (!NewTabletUI.isEnabled(mActivity)) {
|
||||||
|
expected = title;
|
||||||
|
} else {
|
||||||
|
final String absoluteURL = NavigationHelper.adjustUrl(url);
|
||||||
|
if (StringHelper.ABOUT_HOME_URL.equals(absoluteURL)) {
|
||||||
|
expected = StringHelper.ABOUT_HOME_TITLE;
|
||||||
|
} else if (absoluteURL.startsWith(URL_HTTP_PREFIX)) {
|
||||||
|
expected = absoluteURL.substring(URL_HTTP_PREFIX.length());
|
||||||
|
} else {
|
||||||
|
expected = absoluteURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fAssertEquals("The Toolbar title is " + expected, expected, getTitle());
|
fAssertEquals("The Toolbar title is " + expected, expected, getTitle());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +116,7 @@ public class ToolbarComponent extends BaseComponent {
|
||||||
return (ImageButton) getToolbarView().findViewById(R.id.edit_cancel);
|
return (ImageButton) getToolbarView().findViewById(R.id.edit_cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence getTitle() {
|
private String getTitle() {
|
||||||
return getTitleHelper(true);
|
return getTitleHelper(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,16 +125,16 @@ public class ToolbarComponent extends BaseComponent {
|
||||||
* may return a value that may never be visible to the user. Callers likely want to use
|
* may return a value that may never be visible to the user. Callers likely want to use
|
||||||
* {@link assertTitle} instead.
|
* {@link assertTitle} instead.
|
||||||
*/
|
*/
|
||||||
public CharSequence getPotentiallyInconsistentTitle() {
|
public String getPotentiallyInconsistentTitle() {
|
||||||
return getTitleHelper(false);
|
return getTitleHelper(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence getTitleHelper(final boolean shouldAssertNotEditing) {
|
private String getTitleHelper(final boolean shouldAssertNotEditing) {
|
||||||
if (shouldAssertNotEditing) {
|
if (shouldAssertNotEditing) {
|
||||||
assertIsNotEditing();
|
assertIsNotEditing();
|
||||||
}
|
}
|
||||||
|
|
||||||
return getUrlTitleText().getText();
|
return getUrlTitleText().getText().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEditing() {
|
private boolean isEditing() {
|
||||||
|
|
|
@ -44,7 +44,7 @@ final public class NavigationHelper {
|
||||||
/**
|
/**
|
||||||
* Returns a new URL with the docshell HTTP server host prefix.
|
* Returns a new URL with the docshell HTTP server host prefix.
|
||||||
*/
|
*/
|
||||||
private static String adjustUrl(final String url) {
|
public static String adjustUrl(final String url) {
|
||||||
fAssertNotNull("url is not null", url);
|
fAssertNotNull("url is not null", url);
|
||||||
|
|
||||||
if (url.startsWith("about:") || url.startsWith("chrome:")) {
|
if (url.startsWith("about:") || url.startsWith("chrome:")) {
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
#[testTabHistory]
|
#[testTabHistory]
|
||||||
# fails on gs2, nexus one, lg revolution, nexus s
|
# fails on gs2, nexus one, lg revolution, nexus s
|
||||||
|
|
||||||
#[testTabsTrayMenu]
|
#[testTabsLayoutMenu]
|
||||||
# fails on gs2, nexus one, lg revolution, nexus s
|
# fails on gs2, nexus one, lg revolution, nexus s
|
||||||
|
|
||||||
#[testThumbnails]
|
#[testThumbnails]
|
||||||
|
|
|
@ -13,18 +13,20 @@ public class testAboutHomeVisibility extends UITest {
|
||||||
GeckoHelper.blockForReady();
|
GeckoHelper.blockForReady();
|
||||||
|
|
||||||
// Check initial state on about:home.
|
// Check initial state on about:home.
|
||||||
mToolbar.assertTitle(StringHelper.ABOUT_HOME_TITLE);
|
mToolbar.assertTitle(StringHelper.ABOUT_HOME_TITLE, StringHelper.ABOUT_HOME_URL);
|
||||||
mAboutHome.assertVisible()
|
mAboutHome.assertVisible()
|
||||||
.assertCurrentPanel(PanelType.TOP_SITES);
|
.assertCurrentPanel(PanelType.TOP_SITES);
|
||||||
|
|
||||||
// Go to blank 01.
|
// Go to blank 01.
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
mAboutHome.assertNotVisible();
|
mAboutHome.assertNotVisible();
|
||||||
|
|
||||||
// Go to blank 02.
|
// Go to blank 02.
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
mAboutHome.assertNotVisible();
|
mAboutHome.assertNotVisible();
|
||||||
|
|
||||||
// Enter editing mode, where the about:home UI should be visible.
|
// Enter editing mode, where the about:home UI should be visible.
|
||||||
|
@ -38,7 +40,7 @@ public class testAboutHomeVisibility extends UITest {
|
||||||
|
|
||||||
// Loading about:home should show about:home again.
|
// Loading about:home should show about:home again.
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ABOUT_HOME_URL);
|
NavigationHelper.enterAndLoadUrl(StringHelper.ABOUT_HOME_URL);
|
||||||
mToolbar.assertTitle(StringHelper.ABOUT_HOME_TITLE);
|
mToolbar.assertTitle(StringHelper.ABOUT_HOME_TITLE, StringHelper.ABOUT_HOME_URL);
|
||||||
mAboutHome.assertVisible()
|
mAboutHome.assertVisible()
|
||||||
.assertCurrentPanel(PanelType.TOP_SITES);
|
.assertCurrentPanel(PanelType.TOP_SITES);
|
||||||
|
|
||||||
|
@ -49,7 +51,5 @@ public class testAboutHomeVisibility extends UITest {
|
||||||
mAboutHome.navigateToBuiltinPanelType(PanelType.HISTORY)
|
mAboutHome.navigateToBuiltinPanelType(PanelType.HISTORY)
|
||||||
.assertVisible()
|
.assertVisible()
|
||||||
.assertCurrentPanel(PanelType.HISTORY);
|
.assertCurrentPanel(PanelType.HISTORY);
|
||||||
|
|
||||||
// TODO: Type in a url and assert the go button is visible.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,44 @@ package org.mozilla.gecko.tests;
|
||||||
|
|
||||||
import org.mozilla.gecko.Actions;
|
import org.mozilla.gecko.Actions;
|
||||||
import org.mozilla.gecko.Element;
|
import org.mozilla.gecko.Element;
|
||||||
|
import org.mozilla.gecko.NewTabletUI;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
/* Tests related to the about: page:
|
/* Tests related to the about: page:
|
||||||
* - check that about: loads from the URL bar
|
* - check that about: loads from the URL bar
|
||||||
* - check that about: loads from Settings/About...
|
* - check that about: loads from Settings/About...
|
||||||
*/
|
*/
|
||||||
public class testAboutPage extends PixelTest {
|
public class testAboutPage extends PixelTest {
|
||||||
private void ensureTitleMatches(final String regex) {
|
/**
|
||||||
Element urlBarTitle = mDriver.findElement(getActivity(), R.id.url_bar_title);
|
* Ensures the page title matches the given regex (as opposed to String equality).
|
||||||
|
*/
|
||||||
|
private void ensureTitleMatches(final String titleRegex, final String urlRegex) {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
final Element urlBarTitle = mDriver.findElement(activity, R.id.url_bar_title);
|
||||||
|
|
||||||
|
// TODO: We should also be testing what the page title preference value is.
|
||||||
|
final String expectedTitle = NewTabletUI.isEnabled(activity) ? urlRegex : titleRegex;
|
||||||
mAsserter.isnot(urlBarTitle, null, "Got the URL bar title");
|
mAsserter.isnot(urlBarTitle, null, "Got the URL bar title");
|
||||||
assertMatches(urlBarTitle.getText(), regex, "page title match");
|
assertMatches(urlBarTitle.getText(), expectedTitle, "page title match");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAboutPage() {
|
public void testAboutPage() {
|
||||||
blockForGeckoReady();
|
blockForGeckoReady();
|
||||||
|
|
||||||
// Load the about: page and verify its title.
|
// Load the about: page and verify its title.
|
||||||
String url = "about:";
|
String url = StringHelper.ABOUT_SCHEME;
|
||||||
loadAndPaint(url);
|
loadAndPaint(url);
|
||||||
|
|
||||||
ensureTitleMatches(StringHelper.ABOUT_LABEL);
|
ensureTitleMatches(StringHelper.ABOUT_LABEL, url);
|
||||||
|
|
||||||
// Open a new page to remove the about: page from the current tab.
|
// Open a new page to remove the about: page from the current tab.
|
||||||
url = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
url = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
|
|
||||||
// At this point the page title should have been set.
|
// At this point the page title should have been set.
|
||||||
ensureTitleMatches(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
|
||||||
|
|
||||||
// Set up listeners to catch the page load we're about to do.
|
// Set up listeners to catch the page load we're about to do.
|
||||||
Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
||||||
|
@ -45,6 +55,6 @@ public class testAboutPage extends PixelTest {
|
||||||
contentEventExpecter.unregisterListener();
|
contentEventExpecter.unregisterListener();
|
||||||
|
|
||||||
// Grab the title to make sure the about: page was loaded.
|
// Grab the title to make sure the about: page was loaded.
|
||||||
ensureTitleMatches(StringHelper.ABOUT_LABEL);
|
ensureTitleMatches(StringHelper.ABOUT_LABEL, StringHelper.ABOUT_SCHEME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class testAddSearchEngine extends AboutHomeTest {
|
||||||
// Load the page for the search engine to add.
|
// Load the page for the search engine to add.
|
||||||
inputAndLoadUrl(searchEngineURL);
|
inputAndLoadUrl(searchEngineURL);
|
||||||
waitForText(StringHelper.ROBOCOP_SEARCH_TITLE);
|
waitForText(StringHelper.ROBOCOP_SEARCH_TITLE);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_SEARCH_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_SEARCH_TITLE, searchEngineURL);
|
||||||
|
|
||||||
// Used to long-tap on the search input box for the search engine to add.
|
// Used to long-tap on the search input box for the search engine to add.
|
||||||
getInstrumentation().waitForIdleSync();
|
getInstrumentation().waitForIdleSync();
|
||||||
|
@ -99,7 +99,7 @@ public class testAddSearchEngine extends AboutHomeTest {
|
||||||
|
|
||||||
mAsserter.dumpLog("Search Engines list = " + searchEngines.toString());
|
mAsserter.dumpLog("Search Engines list = " + searchEngines.toString());
|
||||||
mAsserter.is(searchEngines.size(), initialNumSearchEngines + 1, "Checking the number of Search Engines has increased");
|
mAsserter.is(searchEngines.size(), initialNumSearchEngines + 1, "Checking the number of Search Engines has increased");
|
||||||
|
|
||||||
// Verify that the number of displayed searchengines is the same as the one received through the SearchEngines:Data event.
|
// Verify that the number of displayed searchengines is the same as the one received through the SearchEngines:Data event.
|
||||||
verifyDisplayedSearchEnginesCount(initialNumSearchEngines + 1);
|
verifyDisplayedSearchEnginesCount(initialNumSearchEngines + 1);
|
||||||
searchEngineDataEventExpector.unregisterListener();
|
searchEngineDataEventExpector.unregisterListener();
|
||||||
|
@ -151,7 +151,7 @@ public class testAddSearchEngine extends AboutHomeTest {
|
||||||
return (adapter.getCount() == expectedCount);
|
return (adapter.getCount() == expectedCount);
|
||||||
}
|
}
|
||||||
}, MAX_WAIT_TEST_MS);
|
}, MAX_WAIT_TEST_MS);
|
||||||
|
|
||||||
// Exit about:home
|
// Exit about:home
|
||||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class testAddonManager extends PixelTest {
|
||||||
public void testAddonManager() {
|
public void testAddonManager() {
|
||||||
Actions.EventExpecter tabEventExpecter;
|
Actions.EventExpecter tabEventExpecter;
|
||||||
Actions.EventExpecter contentEventExpecter;
|
Actions.EventExpecter contentEventExpecter;
|
||||||
String url = StringHelper.ABOUT_ADDONS_URL;
|
final String aboutAddonsURL = StringHelper.ABOUT_ADDONS_URL;
|
||||||
|
|
||||||
blockForGeckoReady();
|
blockForGeckoReady();
|
||||||
|
|
||||||
|
@ -36,21 +36,22 @@ public class testAddonManager extends PixelTest {
|
||||||
contentEventExpecter.unregisterListener();
|
contentEventExpecter.unregisterListener();
|
||||||
|
|
||||||
// Verify the url
|
// Verify the url
|
||||||
verifyPageTitle(StringHelper.ADDONS_LABEL);
|
verifyPageTitle(StringHelper.ADDONS_LABEL, aboutAddonsURL);
|
||||||
|
|
||||||
// Close the Add-on Manager
|
// Close the Add-on Manager
|
||||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||||
|
|
||||||
// Load the about:addons page and verify it was loaded
|
// Load the about:addons page and verify it was loaded
|
||||||
loadAndPaint(url);
|
loadAndPaint(aboutAddonsURL);
|
||||||
verifyPageTitle(StringHelper.ADDONS_LABEL);
|
verifyPageTitle(StringHelper.ADDONS_LABEL, aboutAddonsURL);
|
||||||
|
|
||||||
// Setup wait for tab to spawn and load
|
// Setup wait for tab to spawn and load
|
||||||
tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
||||||
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||||
|
|
||||||
// Open a new tab
|
// Open a new tab
|
||||||
addTab(getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL));
|
final String blankURL = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
addTab(blankURL);
|
||||||
|
|
||||||
// Wait for the new tab and page to load
|
// Wait for the new tab and page to load
|
||||||
tabEventExpecter.blockForEvent();
|
tabEventExpecter.blockForEvent();
|
||||||
|
@ -63,7 +64,7 @@ public class testAddonManager extends PixelTest {
|
||||||
verifyTabCount(2);
|
verifyTabCount(2);
|
||||||
|
|
||||||
// Verify the page was opened
|
// Verify the page was opened
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, blankURL);
|
||||||
|
|
||||||
// Addons Manager is not opened 2 separate times when opened from the menu
|
// Addons Manager is not opened 2 separate times when opened from the menu
|
||||||
selectMenuItem(StringHelper.ADDONS_LABEL);
|
selectMenuItem(StringHelper.ADDONS_LABEL);
|
||||||
|
|
|
@ -48,7 +48,8 @@ public class testAppMenuPathways extends UITest {
|
||||||
// The above mock video playback test changes Java state, but not the associated JS state.
|
// The above mock video playback test changes Java state, but not the associated JS state.
|
||||||
// Navigate to a new page so that the Java state is cleared.
|
// Navigate to a new page so that the Java state is cleared.
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
|
||||||
// Test save as pdf functionality.
|
// Test save as pdf functionality.
|
||||||
// The following call doesn't wait for the resulting pdf but checks that no exception are thrown.
|
// The following call doesn't wait for the resulting pdf but checks that no exception are thrown.
|
||||||
|
|
|
@ -32,7 +32,8 @@ public class testBookmark extends AboutHomeTest {
|
||||||
isBookmarkDisplayed(BOOKMARK_URL);
|
isBookmarkDisplayed(BOOKMARK_URL);
|
||||||
loadBookmark(BOOKMARK_URL);
|
loadBookmark(BOOKMARK_URL);
|
||||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
|
||||||
mDatabaseHelper.deleteBookmark(BOOKMARK_URL);
|
mDatabaseHelper.deleteBookmark(BOOKMARK_URL);
|
||||||
waitForBookmarked(false);
|
waitForBookmarked(false);
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class testBookmarkFolders extends AboutHomeTest {
|
||||||
// Open the bookmark from a bookmark folder hierarchy
|
// Open the bookmark from a bookmark folder hierarchy
|
||||||
loadBookmark(DESKTOP_BOOKMARK_URL);
|
loadBookmark(DESKTOP_BOOKMARK_URL);
|
||||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, DESKTOP_BOOKMARK_URL);
|
||||||
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||||
|
|
||||||
// Check that folders don't have a context menu
|
// Check that folders don't have a context menu
|
||||||
|
|
|
@ -19,7 +19,8 @@ public class testBookmarkKeyword extends AboutHomeTest {
|
||||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||||
|
|
||||||
// Make sure the title of the page appeared.
|
// Make sure the title of the page appeared.
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
|
||||||
// Delete the bookmark to clean up.
|
// Delete the bookmark to clean up.
|
||||||
mDatabaseHelper.deleteBookmark(url);
|
mDatabaseHelper.deleteBookmark(url);
|
||||||
|
|
|
@ -18,7 +18,9 @@ public class testBookmarklets extends AboutHomeTest {
|
||||||
|
|
||||||
// load a standard page so bookmarklets work
|
// load a standard page so bookmarklets work
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE); // Waiting for page title to ensure the page is loaded
|
// Waiting for page title to ensure the page is loaded
|
||||||
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
|
||||||
// verify that user-entered bookmarklets do *not* work
|
// verify that user-entered bookmarklets do *not* work
|
||||||
enterUrl(js);
|
enterUrl(js);
|
||||||
|
|
|
@ -30,14 +30,14 @@ public class testClearPrivateData extends PixelTest {
|
||||||
String blank2 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
String blank2 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE;
|
String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE;
|
||||||
inputAndLoadUrl(blank1);
|
inputAndLoadUrl(blank1);
|
||||||
verifyPageTitle(title);
|
verifyPageTitle(title, blank1);
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
|
mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
|
||||||
|
|
||||||
// Checking that the history list is not empty
|
// Checking that the history list is not empty
|
||||||
verifyHistoryCount(1);
|
verifyHistoryCount(1);
|
||||||
|
|
||||||
//clear and check for device
|
//clear and check for device
|
||||||
checkDevice(title);
|
checkDevice(title, blank1);
|
||||||
|
|
||||||
// Checking that history list is empty
|
// Checking that history list is empty
|
||||||
verifyHistoryCount(0);
|
verifyHistoryCount(0);
|
||||||
|
@ -65,7 +65,7 @@ public class testClearPrivateData extends PixelTest {
|
||||||
checkOption(shareStrings[3], "Cancel");
|
checkOption(shareStrings[3], "Cancel");
|
||||||
loadCheckDismiss(shareStrings[2], url, shareStrings[0]);
|
loadCheckDismiss(shareStrings[2], url, shareStrings[0]);
|
||||||
checkOption(shareStrings[2], "Cancel");
|
checkOption(shareStrings[2], "Cancel");
|
||||||
checkDevice(titleGeolocation);
|
checkDevice(titleGeolocation, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPassword(){
|
public void clearPassword(){
|
||||||
|
@ -75,24 +75,20 @@ public class testClearPrivateData extends PixelTest {
|
||||||
loadCheckDismiss(passwordStrings[1], loginUrl, passwordStrings[0]);
|
loadCheckDismiss(passwordStrings[1], loginUrl, passwordStrings[0]);
|
||||||
checkOption(passwordStrings[1], "Clear");
|
checkOption(passwordStrings[1], "Clear");
|
||||||
loadCheckDismiss(passwordStrings[2], loginUrl, passwordStrings[0]);
|
loadCheckDismiss(passwordStrings[2], loginUrl, passwordStrings[0]);
|
||||||
checkDevice(title);
|
checkDevice(title, getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear private data and verify the device type because for phone there is an extra back action to exit the settings menu
|
// clear private data and verify the device type because for phone there is an extra back action to exit the settings menu
|
||||||
public void checkDevice(String title) {
|
public void checkDevice(final String title, final String url) {
|
||||||
clearPrivateData();
|
clearPrivateData();
|
||||||
if (mDevice.type.equals("phone")) {
|
if (mDevice.type.equals("phone")) {
|
||||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||||
mAsserter.ok(waitForText(StringHelper.PRIVACY_SECTION_LABEL), "waiting to perform one back", "one back");
|
mAsserter.ok(waitForText(StringHelper.PRIVACY_SECTION_LABEL), "waiting to perform one back", "one back");
|
||||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
|
||||||
verifyPageTitle(title);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
|
||||||
verifyPageTitle(title);
|
|
||||||
}
|
}
|
||||||
|
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||||
|
verifyPageTitle(title, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load a URL, verify that the doorhanger appears and dismiss it
|
// Load a URL, verify that the doorhanger appears and dismiss it
|
||||||
public void loadCheckDismiss(String option, String url, String message) {
|
public void loadCheckDismiss(String option, String url, String message) {
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
|
|
|
@ -17,11 +17,11 @@ public class testHistory extends AboutHomeTest {
|
||||||
String url3 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
String url3 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
||||||
|
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_URL, url);
|
||||||
inputAndLoadUrl(url2);
|
inputAndLoadUrl(url2);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_URL, url2);
|
||||||
inputAndLoadUrl(url3);
|
inputAndLoadUrl(url3);
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_URL, url3);
|
||||||
|
|
||||||
openAboutHomeTab(AboutHomeTabs.HISTORY);
|
openAboutHomeTab(AboutHomeTabs.HISTORY);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public class testHistory extends AboutHomeTest {
|
||||||
|
|
||||||
// The first item here (since it was just visited) should be a "Switch to tab" item
|
// The first item here (since it was just visited) should be a "Switch to tab" item
|
||||||
// i.e. don't expect a DOMContentLoaded event
|
// i.e. don't expect a DOMContentLoaded event
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_URL, StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
||||||
verifyUrl(url3);
|
verifyUrl(url3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,9 @@ public class testInputConnection extends UITest {
|
||||||
public void testInputConnection() throws InterruptedException {
|
public void testInputConnection() throws InterruptedException {
|
||||||
GeckoHelper.blockForReady();
|
GeckoHelper.blockForReady();
|
||||||
|
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_INPUT_URL + "#" + INITIAL_TEXT);
|
final String url = StringHelper.ROBOCOP_INPUT_URL + "#" + INITIAL_TEXT;
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_INPUT_TITLE);
|
NavigationHelper.enterAndLoadUrl(url);
|
||||||
|
mToolbar.assertTitle(StringHelper.ROBOCOP_INPUT_TITLE, url);
|
||||||
|
|
||||||
mGeckoView.mTextInput
|
mGeckoView.mTextInput
|
||||||
.waitForInputConnection()
|
.waitForInputConnection()
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class testPictureLinkContextMenu extends ContentContextMenuTest {
|
||||||
PICTURE_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_PICTURE_LINK_URL);
|
PICTURE_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_PICTURE_LINK_URL);
|
||||||
BLANK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
BLANK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
loadAndPaint(PICTURE_PAGE_URL);
|
loadAndPaint(PICTURE_PAGE_URL);
|
||||||
verifyPageTitle(PICTURE_PAGE_TITLE);
|
verifyPageTitle(PICTURE_PAGE_TITLE, PICTURE_PAGE_URL);
|
||||||
|
|
||||||
switchTabs(imageTitle);
|
switchTabs(imageTitle);
|
||||||
verifyContextMenuItems(photoMenuItems);
|
verifyContextMenuItems(photoMenuItems);
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class testReaderMode extends AboutHomeTest {
|
||||||
contentPageShowExpecter.unregisterListener();
|
contentPageShowExpecter.unregisterListener();
|
||||||
paintExpecter.blockUntilClear(EVENT_CLEAR_DELAY_MS);
|
paintExpecter.blockUntilClear(EVENT_CLEAR_DELAY_MS);
|
||||||
paintExpecter.unregisterListener();
|
paintExpecter.unregisterListener();
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE, StringHelper.ROBOCOP_TEXT_PAGE_URL);
|
||||||
|
|
||||||
// Open the share menu for the reader toolbar
|
// Open the share menu for the reader toolbar
|
||||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||||
|
@ -134,7 +134,7 @@ public class testReaderMode extends AboutHomeTest {
|
||||||
mSolo.clickOnView(child);
|
mSolo.clickOnView(child);
|
||||||
contentEventExpecter.blockForEvent();
|
contentEventExpecter.blockForEvent();
|
||||||
contentEventExpecter.unregisterListener();
|
contentEventExpecter.unregisterListener();
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE, StringHelper.ROBOCOP_TEXT_PAGE_URL);
|
||||||
|
|
||||||
// Verify that we are in reader mode and remove the page from Reading List
|
// Verify that we are in reader mode and remove the page from Reading List
|
||||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||||
|
@ -142,7 +142,7 @@ public class testReaderMode extends AboutHomeTest {
|
||||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||||
mSolo.clickOnScreen(width,height);
|
mSolo.clickOnScreen(width,height);
|
||||||
mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List");
|
mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List");
|
||||||
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE);
|
verifyPageTitle(StringHelper.ROBOCOP_TEXT_PAGE_TITLE, StringHelper.ROBOCOP_TEXT_PAGE_URL);
|
||||||
|
|
||||||
//Check if the Reading List is empty
|
//Check if the Reading List is empty
|
||||||
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
||||||
|
|
|
@ -16,8 +16,9 @@ public class testSelectionHandler extends UITest {
|
||||||
GeckoHelper.blockForReady();
|
GeckoHelper.blockForReady();
|
||||||
|
|
||||||
Actions.EventExpecter robocopTestExpecter = getActions().expectGeckoEvent("Robocop:testSelectionHandler");
|
Actions.EventExpecter robocopTestExpecter = getActions().expectGeckoEvent("Robocop:testSelectionHandler");
|
||||||
NavigationHelper.enterAndLoadUrl("chrome://roboextender/content/testSelectionHandler.html");
|
final String url = "chrome://roboextender/content/testSelectionHandler.html";
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_SELECTION_HANDLER_TITLE);
|
NavigationHelper.enterAndLoadUrl(url);
|
||||||
|
mToolbar.assertTitle(StringHelper.ROBOCOP_SELECTION_HANDLER_TITLE, url);
|
||||||
|
|
||||||
while (!test(robocopTestExpecter)) {
|
while (!test(robocopTestExpecter)) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
|
@ -10,25 +10,32 @@ public class testSessionHistory extends UITest {
|
||||||
public void testSessionHistory() {
|
public void testSessionHistory() {
|
||||||
GeckoHelper.blockForReady();
|
GeckoHelper.blockForReady();
|
||||||
|
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
String url = StringHelper.ROBOCOP_BLANK_PAGE_01_URL;
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
NavigationHelper.enterAndLoadUrl(url);
|
||||||
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
|
||||||
|
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
url = StringHelper.ROBOCOP_BLANK_PAGE_02_URL;
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
NavigationHelper.enterAndLoadUrl(url);
|
||||||
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, url);
|
||||||
|
|
||||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_BLANK_PAGE_03_URL);
|
url = StringHelper.ROBOCOP_BLANK_PAGE_03_URL;
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_TITLE);
|
NavigationHelper.enterAndLoadUrl(url);
|
||||||
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_03_TITLE, url);
|
||||||
|
|
||||||
NavigationHelper.goBack();
|
NavigationHelper.goBack();
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
|
|
||||||
NavigationHelper.goBack();
|
NavigationHelper.goBack();
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||||
|
|
||||||
NavigationHelper.goForward();
|
NavigationHelper.goForward();
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
|
|
||||||
NavigationHelper.reload();
|
NavigationHelper.reload();
|
||||||
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
mToolbar.assertTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE,
|
||||||
|
StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class testShareLink extends AboutHomeTest {
|
||||||
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
||||||
|
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
verifyPageTitle(urlTitle); // Waiting for page title to ensure the page is loaded
|
verifyPageTitle(urlTitle, url); // Waiting for page title to ensure the page is loaded
|
||||||
|
|
||||||
selectMenuItem(StringHelper.SHARE_LABEL);
|
selectMenuItem(StringHelper.SHARE_LABEL);
|
||||||
if (Build.VERSION.SDK_INT >= 14) {
|
if (Build.VERSION.SDK_INT >= 14) {
|
||||||
|
@ -248,7 +248,7 @@ public class testShareLink extends AboutHomeTest {
|
||||||
public boolean test() {
|
public boolean test() {
|
||||||
ArrayList<View> views = mSolo.getCurrentViews();
|
ArrayList<View> views = mSolo.getCurrentViews();
|
||||||
for (View view : views) {
|
for (View view : views) {
|
||||||
// List may be displayed in different view formats.
|
// List may be displayed in different view formats.
|
||||||
// On JB, GridView is common; on ICS-, ListView is common.
|
// On JB, GridView is common; on ICS-, ListView is common.
|
||||||
if (view instanceof ListView ||
|
if (view instanceof ListView ||
|
||||||
view instanceof GridView) {
|
view instanceof GridView) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.mozilla.gecko.tests;
|
package org.mozilla.gecko.tests;
|
||||||
|
|
||||||
import org.mozilla.gecko.Actions;
|
import org.mozilla.gecko.Actions;
|
||||||
|
import org.mozilla.gecko.NewTabletUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This patch tests the option that shows the full URL and title in the URL Bar
|
* This patch tests the option that shows the full URL and title in the URL Bar
|
||||||
|
@ -7,6 +9,11 @@ import org.mozilla.gecko.Actions;
|
||||||
|
|
||||||
public class testTitleBar extends PixelTest {
|
public class testTitleBar extends PixelTest {
|
||||||
public void testTitleBar() {
|
public void testTitleBar() {
|
||||||
|
// Because there is no title bar option on new tablet, we don't need to run this test.
|
||||||
|
if (NewTabletUI.isEnabled(getActivity())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
blockForGeckoReady();
|
blockForGeckoReady();
|
||||||
checkOption();
|
checkOption();
|
||||||
}
|
}
|
||||||
|
@ -18,7 +25,7 @@ public class testTitleBar extends PixelTest {
|
||||||
|
|
||||||
// Loading a page
|
// Loading a page
|
||||||
inputAndLoadUrl(blank1);
|
inputAndLoadUrl(blank1);
|
||||||
verifyPageTitle(title);
|
verifyPageTitle(title, blank1);
|
||||||
|
|
||||||
// Ensure the full URL is displayed in the URL Bar
|
// Ensure the full URL is displayed in the URL Bar
|
||||||
selectOption(StringHelper.SHOW_PAGE_ADDRESS_LABEL);
|
selectOption(StringHelper.SHOW_PAGE_ADDRESS_LABEL);
|
||||||
|
@ -28,7 +35,7 @@ public class testTitleBar extends PixelTest {
|
||||||
// Ensure the title is displayed in the URL Bar
|
// Ensure the title is displayed in the URL Bar
|
||||||
selectOption(StringHelper.SHOW_PAGE_TITLE_LABEL);
|
selectOption(StringHelper.SHOW_PAGE_TITLE_LABEL);
|
||||||
inputAndLoadUrl(blank1);
|
inputAndLoadUrl(blank1);
|
||||||
verifyPageTitle(title);
|
verifyPageTitle(title, blank1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entering settings, changing the options: show title/page address option and verifing the device type because for phone there is an extra back action to exit the settings menu
|
// Entering settings, changing the options: show title/page address option and verifing the device type because for phone there is an extra back action to exit the settings menu
|
||||||
|
|
|
@ -36,6 +36,8 @@ public class TabCounter extends ThemedTextSwitcher
|
||||||
private final int mLayoutId;
|
private final int mLayoutId;
|
||||||
|
|
||||||
private int mCount;
|
private int mCount;
|
||||||
|
public static final int MAX_VISIBLE_TABS = 99;
|
||||||
|
public static final String SO_MANY_TABS_OPEN = "∞";
|
||||||
|
|
||||||
private enum FadeMode {
|
private enum FadeMode {
|
||||||
FADE_IN,
|
FADE_IN,
|
||||||
|
@ -84,6 +86,12 @@ public class TabCounter extends ThemedTextSwitcher
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't animate if there are still over MAX_VISIBLE_TABS tabs open
|
||||||
|
if (mCount > MAX_VISIBLE_TABS && count > MAX_VISIBLE_TABS) {
|
||||||
|
mCount = count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (count < mCount) {
|
if (count < mCount) {
|
||||||
setInAnimation(mFlipInBackward);
|
setInAnimation(mFlipInBackward);
|
||||||
setOutAnimation(mFlipOutForward);
|
setOutAnimation(mFlipOutForward);
|
||||||
|
@ -97,14 +105,21 @@ public class TabCounter extends ThemedTextSwitcher
|
||||||
setDisplayedChild(0);
|
setDisplayedChild(0);
|
||||||
|
|
||||||
// Set In value, trigger animation to Out value
|
// Set In value, trigger animation to Out value
|
||||||
setCurrentText(String.valueOf(mCount));
|
setCurrentText(formatForDisplay(mCount));
|
||||||
setText(String.valueOf(count));
|
setText(formatForDisplay(count));
|
||||||
|
|
||||||
mCount = count;
|
mCount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String formatForDisplay(int count) {
|
||||||
|
if (count > MAX_VISIBLE_TABS) {
|
||||||
|
return SO_MANY_TABS_OPEN;
|
||||||
|
}
|
||||||
|
return String.valueOf(count);
|
||||||
|
}
|
||||||
|
|
||||||
void setCount(int count) {
|
void setCount(int count) {
|
||||||
setCurrentText(String.valueOf(count));
|
setCurrentText(formatForDisplay(count));
|
||||||
mCount = count;
|
mCount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class IconTabWidget extends TabWidget {
|
||||||
if (!mIsIcon) {
|
if (!mIsIcon) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// We can have multiple views in the tray for each child. This finds the
|
// We can have multiple views in the tabs panel for each child. This finds the
|
||||||
// first view corresponding to the given tab. This varies by Android
|
// first view corresponding to the given tab. This varies by Android
|
||||||
// version. The first view should always be our ImageButton, but let's
|
// version. The first view should always be our ImageButton, but let's
|
||||||
// be safe.
|
// be safe.
|
||||||
|
@ -98,7 +98,7 @@ public class IconTabWidget extends TabWidget {
|
||||||
if (!mIsIcon) {
|
if (!mIsIcon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We can have multiple views in the tray for each child. This finds the
|
// We can have multiple views in the tabs panel for each child. This finds the
|
||||||
// first view corresponding to the given tab. This varies by Android
|
// first view corresponding to the given tab. This varies by Android
|
||||||
// version. The first view should always be our ImageButton, but let's
|
// version. The first view should always be our ImageButton, but let's
|
||||||
// be safe.
|
// be safe.
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
var WebcompatReporter = {
|
||||||
|
menuItem: null,
|
||||||
|
menuItemEnabled: null,
|
||||||
|
init: function() {
|
||||||
|
Services.obs.addObserver(this, "DesktopMode:Change", false);
|
||||||
|
Services.obs.addObserver(this, "content-page-shown", false);
|
||||||
|
this.addMenuItem();
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit: function() {
|
||||||
|
Services.obs.removeObserver(this, "DesktopMode:Change");
|
||||||
|
|
||||||
|
if (this.menuItem) {
|
||||||
|
NativeWindow.menu.remove(this.menuItem);
|
||||||
|
this.menuItem = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
observe: function(subject, topic, data) {
|
||||||
|
if (topic === "content-page-shown") {
|
||||||
|
let currentURI = subject.documentURI;
|
||||||
|
if (!this.menuItemEnabled && this.isReportableUrl(currentURI)) {
|
||||||
|
NativeWindow.menu.update(this.menuItem, {enabled: true});
|
||||||
|
this.menuItemEnabled = true;
|
||||||
|
} else if (this.menuItemEnabled && !this.isReportableUrl(currentURI)) {
|
||||||
|
NativeWindow.menu.update(this.menuItem, {enabled: false});
|
||||||
|
this.menuItemEnabled = false;
|
||||||
|
}
|
||||||
|
} else if (topic === "DesktopMode:Change") {
|
||||||
|
let args = JSON.parse(data);
|
||||||
|
let tab = BrowserApp.getTabForId(args.tabId);
|
||||||
|
if (args.desktopMode && tab !== null) {
|
||||||
|
this.reportDesktopModePrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addMenuItem: function() {
|
||||||
|
this.menuItem = NativeWindow.menu.add({
|
||||||
|
name: this.strings.GetStringFromName("webcompat.menu.name"),
|
||||||
|
callback: () => {
|
||||||
|
let currentURI = BrowserApp.selectedTab.browser.currentURI.spec;
|
||||||
|
this.reportIssue(currentURI);
|
||||||
|
},
|
||||||
|
enabled: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
isReportableUrl: function(url) {
|
||||||
|
return url !== null && !(url.startsWith("about") ||
|
||||||
|
url.startsWith("chrome") ||
|
||||||
|
url.startsWith("file") ||
|
||||||
|
url.startsWith("resource"));
|
||||||
|
},
|
||||||
|
|
||||||
|
reportDesktopModePrompt: function() {
|
||||||
|
let currentURI = BrowserApp.selectedTab.browser.currentURI.spec;
|
||||||
|
let message = this.strings.GetStringFromName("webcompat.reportDesktopMode.message");
|
||||||
|
let options = {
|
||||||
|
button: {
|
||||||
|
label: this.strings.GetStringFromName("webcompat.reportDesktopModeYes.label"),
|
||||||
|
callback: () => this.reportIssue(currentURI)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NativeWindow.toast.show(message, "long", options);
|
||||||
|
},
|
||||||
|
|
||||||
|
reportIssue: function(url) {
|
||||||
|
let webcompatURL = new URL("http://webcompat.com/");
|
||||||
|
webcompatURL.searchParams.append("open", "1");
|
||||||
|
webcompatURL.searchParams.append("url", url);
|
||||||
|
BrowserApp.addTab(webcompatURL.href);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(WebcompatReporter, "strings", function() {
|
||||||
|
return Services.strings.createBundle("chrome://browser/locale/webcompatReporter.properties");
|
||||||
|
});
|
|
@ -112,6 +112,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences",
|
||||||
["Linkifier", "chrome://browser/content/Linkify.js"],
|
["Linkifier", "chrome://browser/content/Linkify.js"],
|
||||||
["ZoomHelper", "chrome://browser/content/ZoomHelper.js"],
|
["ZoomHelper", "chrome://browser/content/ZoomHelper.js"],
|
||||||
["CastingApps", "chrome://browser/content/CastingApps.js"],
|
["CastingApps", "chrome://browser/content/CastingApps.js"],
|
||||||
|
#ifdef NIGHTLY_BUILD
|
||||||
|
["WebcompatReporter", "chrome://browser/content/WebcompatReporter.js"],
|
||||||
|
#endif
|
||||||
].forEach(function (aScript) {
|
].forEach(function (aScript) {
|
||||||
let [name, script] = aScript;
|
let [name, script] = aScript;
|
||||||
XPCOMUtils.defineLazyGetter(window, name, function() {
|
XPCOMUtils.defineLazyGetter(window, name, function() {
|
||||||
|
@ -334,6 +337,9 @@ var BrowserApp = {
|
||||||
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
|
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
|
||||||
SafeBrowsing.init();
|
SafeBrowsing.init();
|
||||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||||
|
#endif
|
||||||
|
#ifdef NIGHTLY_BUILD
|
||||||
|
WebcompatReporter.init();
|
||||||
#endif
|
#endif
|
||||||
} catch(ex) { console.log(ex); }
|
} catch(ex) { console.log(ex); }
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -858,6 +864,9 @@ var BrowserApp = {
|
||||||
CastingApps.uninit();
|
CastingApps.uninit();
|
||||||
Distribution.uninit();
|
Distribution.uninit();
|
||||||
Tabs.uninit();
|
Tabs.uninit();
|
||||||
|
#ifdef NIGHTLY_BUILD
|
||||||
|
WebcompatReporter.uninit();
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
|
|
||||||
// This function returns false during periods where the browser displayed document is
|
// This function returns false during periods where the browser displayed document is
|
||||||
|
|
|
@ -62,6 +62,9 @@ chrome.jar:
|
||||||
content/aboutDevices.xhtml (content/aboutDevices.xhtml)
|
content/aboutDevices.xhtml (content/aboutDevices.xhtml)
|
||||||
content/aboutDevices.js (content/aboutDevices.js)
|
content/aboutDevices.js (content/aboutDevices.js)
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NIGHTLY_BUILD
|
||||||
|
content/WebcompatReporter.js (content/WebcompatReporter.js)
|
||||||
|
#endif
|
||||||
|
|
||||||
% content branding %content/branding/
|
% content branding %content/branding/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (webcompat.menu.name): A "site issue" is a bug, display,
|
||||||
|
# or functionality problem with a webpage in the browser.
|
||||||
|
webcompat.menu.name=Report Site Issue
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (webcompat.reportDesktopMode.message): A " site issue" is a
|
||||||
|
# bug, display, or functionality problem with a webpage in the browser.
|
||||||
|
webcompat.reportDesktopMode.message=Report site issue?
|
||||||
|
webcompat.reportDesktopModeYes.label=Report
|
|
@ -39,6 +39,9 @@
|
||||||
locale/@AB_CD@/browser/payments.properties (%chrome/payments.properties)
|
locale/@AB_CD@/browser/payments.properties (%chrome/payments.properties)
|
||||||
locale/@AB_CD@/browser/handling.properties (%chrome/handling.properties)
|
locale/@AB_CD@/browser/handling.properties (%chrome/handling.properties)
|
||||||
locale/@AB_CD@/browser/webapp.properties (%chrome/webapp.properties)
|
locale/@AB_CD@/browser/webapp.properties (%chrome/webapp.properties)
|
||||||
|
#ifdef NIGHTLY_BUILD
|
||||||
|
locale/@AB_CD@/browser/webcompatReporter.properties (%chrome/webcompatReporter.properties)
|
||||||
|
#endif
|
||||||
|
|
||||||
# overrides for toolkit l10n, also for en-US
|
# overrides for toolkit l10n, also for en-US
|
||||||
relativesrcdir toolkit/locales:
|
relativesrcdir toolkit/locales:
|
||||||
|
|
|
@ -5,171 +5,33 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||||
|
|
||||||
|
const CONFIG = { iceServers: [{ "url": "stun:stun.services.mozilla.com" }] };
|
||||||
|
|
||||||
|
let log = Cu.import("resource://gre/modules/AndroidLog.jsm",
|
||||||
|
{}).AndroidLog.d.bind(null, "TabMirror");
|
||||||
|
|
||||||
|
let failure = function(x) {
|
||||||
|
log("ERROR: " + JSON.stringify(x));
|
||||||
|
};
|
||||||
|
|
||||||
let TabMirror = function(deviceId, window) {
|
let TabMirror = function(deviceId, window) {
|
||||||
let out_queue = [];
|
|
||||||
let in_queue = [];
|
|
||||||
let DEBUG = false;
|
|
||||||
|
|
||||||
let log = Cu.import("resource://gre/modules/AndroidLog.jsm",
|
this.deviceId = deviceId;
|
||||||
{}).AndroidLog.d.bind(null, "TabMirror");
|
// Save mozRTCSessionDescription and mozRTCIceCandidate for later when the window object is not available.
|
||||||
|
this.RTCSessionDescription = window.mozRTCSessionDescription;
|
||||||
|
this.RTCIceCandidate = window.mozRTCIceCandidate;
|
||||||
|
|
||||||
let RTCPeerConnection = window.mozRTCPeerConnection;
|
Services.obs.addObserver((aSubject, aTopic, aData) => this._processMessage(aData), "MediaPlayer:Response", false);
|
||||||
let RTCSessionDescription = window.mozRTCSessionDescription;
|
|
||||||
let RTCIceCandidate = window.mozRTCIceCandidate;
|
|
||||||
let getUserMedia = window.navigator.mozGetUserMedia.bind(window.navigator);
|
|
||||||
|
|
||||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
this._pc = new window.mozRTCPeerConnection(CONFIG, {});
|
||||||
in_queue.push(aData);
|
|
||||||
}, "MediaPlayer:Response", false);
|
|
||||||
|
|
||||||
let poll_timeout = 1000; // ms
|
if (!this._pc) {
|
||||||
|
throw "Failure creating Webrtc object";
|
||||||
let audio_stream = undefined;
|
|
||||||
let video_stream = undefined;
|
|
||||||
let pc = undefined;
|
|
||||||
|
|
||||||
let poll_success = function(msg) {
|
|
||||||
if (!msg) {
|
|
||||||
poll_error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let js;
|
|
||||||
try {
|
|
||||||
js = JSON.parse(msg);
|
|
||||||
} catch(ex) {
|
|
||||||
log("ex: " + ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
let sdp = js.body;
|
|
||||||
|
|
||||||
if (sdp) {
|
|
||||||
if (sdp.sdp) {
|
|
||||||
if (sdp.type === "offer") {
|
|
||||||
process_offer(sdp);
|
|
||||||
} else if (sdp.type === "answer") {
|
|
||||||
process_answer(sdp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
process_ice_candidate(sdp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.setTimeout(poll, poll_timeout);
|
|
||||||
};
|
|
||||||
|
|
||||||
let poll_error = function (msg) {
|
|
||||||
window.setTimeout(poll, poll_timeout);
|
|
||||||
};
|
|
||||||
|
|
||||||
let poll = function () {
|
|
||||||
if (in_queue) {
|
|
||||||
poll_success(in_queue.pop());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let failure = function(x) {
|
|
||||||
log("ERROR: " + JSON.stringify(x));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Signaling methods
|
|
||||||
let send_sdpdescription= function(sdp) {
|
|
||||||
let msg = {
|
|
||||||
body: sdp
|
|
||||||
};
|
|
||||||
|
|
||||||
sendMessage(JSON.stringify(msg));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let deobjify = function(x) {
|
|
||||||
return JSON.parse(JSON.stringify(x));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let process_offer = function(sdp) {
|
|
||||||
pc.setRemoteDescription(new RTCSessionDescription(sdp),
|
|
||||||
set_remote_offer_success, failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
let process_answer = function(sdp) {
|
|
||||||
pc.setRemoteDescription(new RTCSessionDescription(sdp),
|
|
||||||
set_remote_answer_success, failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
let process_ice_candidate = function(msg) {
|
|
||||||
pc.addIceCandidate(new RTCIceCandidate(msg));
|
|
||||||
};
|
|
||||||
|
|
||||||
let set_remote_offer_success = function() {
|
|
||||||
pc.createAnswer(create_answer_success, failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
let set_remote_answer_success= function() {
|
|
||||||
};
|
|
||||||
|
|
||||||
let set_local_success_offer = function(sdp) {
|
|
||||||
send_sdpdescription(sdp);
|
|
||||||
};
|
|
||||||
|
|
||||||
let set_local_success_answer = function(sdp) {
|
|
||||||
send_sdpdescription(sdp);
|
|
||||||
};
|
|
||||||
|
|
||||||
let filter_nonrelay_candidates = function(sdp) {
|
|
||||||
let lines = sdp.sdp.split("\r\n");
|
|
||||||
let lines2 = lines.filter(function(x) {
|
|
||||||
if (!/candidate/.exec(x))
|
|
||||||
return true;
|
|
||||||
if (/relay/.exec(x))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
sdp.sdp = lines2.join("\r\n");
|
|
||||||
};
|
|
||||||
|
|
||||||
let create_offer_success = function(sdp) {
|
|
||||||
pc.setLocalDescription(sdp,
|
|
||||||
function() {
|
|
||||||
set_local_success_offer(sdp);
|
|
||||||
},
|
|
||||||
failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
let create_answer_success = function(sdp) {
|
|
||||||
pc.setLocalDescription(sdp,
|
|
||||||
function() {
|
|
||||||
set_local_success_answer(sdp);
|
|
||||||
},
|
|
||||||
failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
let on_ice_candidate = function (candidate) {
|
|
||||||
send_sdpdescription(candidate.candidate);
|
|
||||||
};
|
|
||||||
|
|
||||||
let ready = function() {
|
|
||||||
pc.createOffer(create_offer_success, failure);
|
|
||||||
poll();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let config = {
|
|
||||||
iceServers: [{ "url": "stun:stun.services.mozilla.com" }]
|
|
||||||
};
|
|
||||||
|
|
||||||
pc = new RTCPeerConnection(config, {});
|
|
||||||
|
|
||||||
if (!pc) {
|
|
||||||
log("Failure creating Webrtc object");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.onicecandidate = on_ice_candidate;
|
this._pc.onicecandidate = this._onIceCandidate.bind(this);
|
||||||
|
|
||||||
let windowId = window.BrowserApp.selectedBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
let windowId = window.BrowserApp.selectedBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||||
let viewport = window.BrowserApp.selectedTab.getViewport();
|
let viewport = window.BrowserApp.selectedTab.getViewport();
|
||||||
|
@ -203,41 +65,95 @@ let TabMirror = function(deviceId, window) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let gUM_success = function(stream){
|
window.navigator.mozGetUserMedia(constraints, this._onGumSuccess.bind(this), this._onGumFailure.bind(this));
|
||||||
pc.addStream(stream);
|
};
|
||||||
ready();
|
|
||||||
};
|
|
||||||
|
|
||||||
let gUM_failure = function() {
|
TabMirror.prototype = {
|
||||||
log("Could not get video stream");
|
|
||||||
};
|
|
||||||
|
|
||||||
getUserMedia( constraints, gUM_success, gUM_failure);
|
_processMessage: function(data) {
|
||||||
|
|
||||||
function sendMessage(msg) {
|
if (!data) {
|
||||||
let obj = {
|
return;
|
||||||
type: "MediaPlayer:Message",
|
|
||||||
id: deviceId,
|
|
||||||
data: msg
|
|
||||||
};
|
|
||||||
|
|
||||||
if (deviceId) {
|
|
||||||
Services.androidBridge.handleGeckoMessage(obj);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
let msg = JSON.parse(data);
|
||||||
stop: function() {
|
|
||||||
|
if (!msg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.sdp) {
|
||||||
|
if (msg.type === "answer") {
|
||||||
|
this._processAnswer(msg);
|
||||||
|
} else {
|
||||||
|
log("Unandled sdp message type: " + msg.type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._processIceCandidate(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Signaling methods
|
||||||
|
_processAnswer: function(msg) {
|
||||||
|
this._pc.setRemoteDescription(new this.RTCSessionDescription(msg),
|
||||||
|
this._setRemoteAnswerSuccess.bind(this), failure);
|
||||||
|
},
|
||||||
|
|
||||||
|
_processIceCandidate: function(msg) {
|
||||||
|
// WebRTC generates a warning if the success and fail callbacks are not passed in.
|
||||||
|
this._pc.addIceCandidate(new this.RTCIceCandidate(msg), () => log("Ice Candiated added successfuly"), () => log("Failed to add Ice Candidate"));
|
||||||
|
},
|
||||||
|
|
||||||
|
_setRemoteAnswerSuccess: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
_setLocalSuccessOffer: function(sdp) {
|
||||||
|
this._sendMessage(sdp);
|
||||||
|
},
|
||||||
|
|
||||||
|
_createOfferSuccess: function(sdp) {
|
||||||
|
this._pc.setLocalDescription(sdp, () => this._setLocalSuccessOffer(sdp), failure);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onIceCandidate: function (msg) {
|
||||||
|
log("NEW Ice Candidate: " + JSON.stringify(msg.candidate));
|
||||||
|
this._sendMessage(msg.candidate);
|
||||||
|
},
|
||||||
|
|
||||||
|
_ready: function() {
|
||||||
|
this._pc.createOffer(this._createOfferSuccess.bind(this), failure);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onGumSuccess: function(stream){
|
||||||
|
this._pc.addStream(stream);
|
||||||
|
this._ready();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onGumFailure: function() {
|
||||||
|
log("Could not get video stream");
|
||||||
|
this._pc.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
_sendMessage: function(msg) {
|
||||||
|
if (this.deviceId) {
|
||||||
|
let obj = {
|
||||||
|
type: "MediaPlayer:Message",
|
||||||
|
id: this.deviceId,
|
||||||
|
data: JSON.stringify(msg)
|
||||||
|
};
|
||||||
|
Messaging.sendRequest(obj);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function() {
|
||||||
|
if (this.deviceId) {
|
||||||
let obj = {
|
let obj = {
|
||||||
type: "MediaPlayer:End",
|
type: "MediaPlayer:End",
|
||||||
id: deviceId
|
id: this.deviceId
|
||||||
};
|
};
|
||||||
|
Services.androidBridge.handleGeckoMessage(obj);
|
||||||
if (deviceId) {
|
|
||||||
Services.androidBridge.handleGeckoMessage(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче