Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-08-19 07:47:16 -04:00
commit 2ff752b147
61 changed files with 1223 additions and 731 deletions

View File

@ -89,6 +89,6 @@ tabbrowser[pendingpaint] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
background-repeat: no-repeat;
background-position: center center;
background-color: #fff;
opacity: 0.3;
background-color: #f9f9f9 !important;
background-size: 30px;
}

View File

@ -3086,6 +3086,9 @@
STATE_LOADED: 2,
STATE_UNLOADING: 3,
// re-entrancy guard:
_processing: false,
getTabState: function(tab) {
let state = this.tabState.get(tab);
if (state === undefined) {
@ -3228,7 +3231,6 @@
}
this.lastVisibleTab = this.visibleTab;
},
assert: function(cond) {
@ -3441,7 +3443,17 @@
this.postActions();
},
handleEvent: function(event) {
handleEvent: function(event, delayed = false) {
if (this._processing) {
setTimeout(() => this.handleEvent(event, true), 0);
return;
}
if (delayed && this.tabbrowser._switcher != this) {
// if we delayed processing this event, we might be out of date, in which
// case we drop the delayed events
return;
}
this._processing = true;
this.preActions();
if (event.type == "MozLayerTreeReady") {
@ -3455,6 +3467,7 @@
}
this.postActions();
this._processing = false;
},
/*

View File

@ -17,9 +17,51 @@ html {
-moz-margin-start: 10px;
}
.content-area input.contact-filter {
margin-top: 14px;
border-radius: 10000px;
.contact-filter-container {
display: flex;
height: 2em;
}
.contact-filter {
margin: 0;
-moz-padding-start: 34px;
width: 100%;
height: 28px;
border: 0;
border-bottom: 1px solid #ddd;
background-image: url("../shared/img/icons-14x14.svg#magnifier");
background-position: 10px center;
background-size: 14px;
background-repeat: no-repeat;
color: #999;
font-size: 1.2rem;
flex: 2 1 auto;
align-self: stretch;
}
html[dir="rtl"] .contact-filter {
background-position: right 10px center;
}
.contact-filter:focus + .clear-search,
.contact-filter:focus {
border-bottom: 1px solid #5cccee;
color: #4a4a4a;
}
.clear-search {
width: 34px;
height: 28px;
border: none;
border-bottom: 1px solid #ddd;
background-color: #fff;
background-image: url("../shared/img/icons-14x14.svg#clear");
background-position: center;
background-size: 14px;
background-repeat: no-repeat;
cursor: pointer;
flex: 0 1 auto;
align-self: stretch;
}
.contact-list {
@ -28,6 +70,8 @@ html {
/* Space for six contacts, not affected by filtering. This is enough space
to show the dropdown menu when there is only one contact. */
height: 306px;
/* Contact list title goes away when searching, needed for spacing. */
margin-top: 4px;
}
.contact-list-title {
@ -165,6 +209,36 @@ html {
width: 100%;
}
.contact-list-empty,
.contact-search-list-empty {
background-image: url("../shared/img/empty_contacts.svg");
background-repeat: no-repeat;
background-position: top center;
margin-top: 4rem;
padding-top: 10rem;
padding-bottom: 5rem;
text-align: center;
color: #4a4a4a;
}
.contact-search-list-empty {
background-image: url("../shared/img/empty_search.svg");
}
.panel-text-medium,
.panel-text-large {
margin: 3px;
color: #4a4a4a;
}
.panel-text-medium {
font-size: 1.2rem;
}
.panel-text-large {
font-size: 2.2rem;
}
.contact > .details > .username {
font-size: 1.3rem;
line-height: 20px;
@ -221,7 +295,7 @@ html {
border-radius: 50%;
background-color: #5bc0a4;
background-image: url("../shared/img/icons-14x14.svg#video-white");
background-size: 16px 16px;
background-size: 14px 14px;
}
.icon-contact-video-call:hover {
@ -250,6 +324,7 @@ html {
right: 22px;
bottom: auto;
left: auto;
z-index: 2;
}
html[dir="rtl"] .contact > .dropdown-menu {
@ -340,8 +415,19 @@ html[dir="rtl"] .contacts-gravatar-promo > .button-close {
color: #fff;
}
.button.primary:active,
.button.primary:hover {
background: #5cccee;
}
.button.secondary {
background: #EBEBEB;
background: #ebebeb;
color: #4D4D4D;
}
.button.secondary:hover,
.button.secondary:active {
background: #dad6d6;
color: #4D4D4D;
}

View File

@ -413,6 +413,63 @@ loop.contacts = (function(_, mozL10n) {
window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
},
/*
* Filter a user by name, email or phone number.
* Takes in an input to filter by and returns a filter function which
* expects a contact.
*
* @returns {Function}
*/
filterContact: function(filter) {
return function(contact) {
return getPreferred(contact, "name").toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "email").value.toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "tel").value.toLocaleLowerCase().includes(filter);
};
},
/*
* Takes all contacts, it groups and filters them before rendering.
*/
_filterContactsList: function() {
let shownContacts = _.groupBy(this.contacts, function(contact) {
return contact.blocked ? "blocked" : "available";
});
if (this._shouldShowFilter()) {
let filter = this.state.filter.trim().toLocaleLowerCase();
let filterFn = this.filterContact(filter);
if (filter) {
if (shownContacts.available) {
shownContacts.available = shownContacts.available.filter(filterFn);
// Filter can return an empty array.
if (!shownContacts.available.length) {
shownContacts.available = null;
}
}
if (shownContacts.blocked) {
shownContacts.blocked = shownContacts.blocked.filter(filterFn);
// Filter can return an empty array.
if (!shownContacts.blocked.length) {
shownContacts.blocked = null;
}
}
}
}
return shownContacts;
},
/*
* Decide to render contacts filter based on the number of contacts.
*
* @returns {bool}
*/
_shouldShowFilter: function() {
return Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
},
_onStatusChanged: function() {
let profile = this.props.mozLoop.userProfile;
let currUid = this._userProfile ? this._userProfile.uid : null;
@ -531,6 +588,16 @@ loop.contacts = (function(_, mozL10n) {
this.refresh();
},
/*
* Callback triggered when clicking the `X` from the contacts filter.
* Clears the search query.
*/
_handleFilterClear: function() {
this.setState({
filter: ""
});
},
sortContacts: function(contact1, contact2) {
let comp = contact1.name[0].localeCompare(contact2.name[0]);
if (comp !== 0) {
@ -541,9 +608,35 @@ loop.contacts = (function(_, mozL10n) {
return contact1._guid - contact2._guid;
},
_renderFilterClearButton: function() {
if (this.state.filter) {
return (
React.createElement("button", {className: "clear-search",
onClick: this._handleFilterClear})
);
}
return null;
},
_renderContactsFilter: function() {
if (this._shouldShowFilter()) {
return (
React.createElement("div", {className: "contact-filter-container"},
React.createElement("input", {className: "contact-filter",
placeholder: mozL10n.get("contacts_search_placesholder"),
valueLink: this.linkState("filter")}),
this._renderFilterClearButton()
)
);
}
return null;
},
_renderContactsList: function() {
let cx = React.addons.classSet;
let shownContacts = this._filterContactsList();
let viewForItem = item => {
return (
React.createElement(ContactDetail, {contact: item,
@ -552,92 +645,100 @@ loop.contacts = (function(_, mozL10n) {
);
};
let shownContacts = _.groupBy(this.contacts, function(contact) {
return contact.blocked ? "blocked" : "available";
});
let showFilter = Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
if (showFilter) {
let filter = this.state.filter.trim().toLocaleLowerCase();
if (filter) {
let filterFn = contact => {
return contact.name[0].toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "email").value.toLocaleLowerCase().includes(filter);
};
if (shownContacts.available) {
shownContacts.available = shownContacts.available.filter(filterFn);
}
if (shownContacts.blocked) {
shownContacts.blocked = shownContacts.blocked.filter(filterFn);
}
}
// If no contacts to show and filter is set, then none match the search.
if (!shownContacts.available && !shownContacts.blocked &&
this.state.filter) {
return (
React.createElement("div", {className: "contact-search-list-empty"},
React.createElement("p", {className: "panel-text-large"},
mozL10n.get("no_search_results_message_heading")
),
React.createElement("p", {className: "panel-text-medium"},
mozL10n.get("no_search_results_message_subheading")
)
)
);
}
if (shownContacts.available || shownContacts.blocked) {
// If no contacts to show and filter is not set, we don't have contacts.
if (!shownContacts.available && !shownContacts.blocked &&
!this.state.filter) {
return (
React.createElement("div", null,
React.createElement("div", {className: "contact-list-title"},
mozL10n.get("contact_list_title")
React.createElement("div", {className: "contact-list-empty"},
React.createElement("p", {className: "panel-text-large"},
mozL10n.get("no_contacts_message_heading")
),
React.createElement("ul", {className: "contact-list"},
shownContacts.available ?
shownContacts.available.sort(this.sortContacts).map(viewForItem) :
null,
shownContacts.blocked && shownContacts.blocked.length > 0 ?
React.createElement("div", {className: "contact-separator"}, mozL10n.get("contacts_blocked_contacts")) :
null,
shownContacts.blocked ?
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
null
React.createElement("p", {className: "panel-text-medium"},
mozL10n.get("no_contacts_import_or_add")
)
)
);
}
return (
React.createElement("div", {className: "contact-list-empty"},
React.createElement("p", {className: "panel-text-large"},
mozL10n.get("no_contacts_message_heading")
),
React.createElement("p", {className: "panel-text-medium"},
mozL10n.get("no_contacts_import_or_add")
React.createElement("div", null,
!this.state.filter ? React.createElement("div", {className: "contact-list-title"},
mozL10n.get("contact_list_title")
) : null,
React.createElement("ul", {className: "contact-list"},
shownContacts.available ?
shownContacts.available.sort(this.sortContacts).map(viewForItem) :
null,
shownContacts.blocked && shownContacts.blocked.length > 0 ?
React.createElement("div", {className: "contact-separator"}, mozL10n.get("contacts_blocked_contacts")) :
null,
shownContacts.blocked ?
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
null
)
)
);
},
render: function() {
_renderAddContactButtons: function() {
let cx = React.addons.classSet;
let showFilter = Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
if (this.state.filter) {
return null;
}
return (
React.createElement("div", null,
React.createElement("div", {className: "content-area"},
showFilter ?
React.createElement("input", {className: "contact-filter",
placeholder: mozL10n.get("contacts_search_placesholder"),
valueLink: this.linkState("filter")})
: null,
React.createElement(GravatarPromo, {handleUse: this.handleUseGravatar})
React.createElement(ButtonGroup, {additionalClass: "contact-controls"},
React.createElement(Button, {additionalClass: "secondary",
caption: this.state.importBusy ? mozL10n.get("importing_contacts_progress_button") :
mozL10n.get("import_contacts_button3"),
disabled: this.state.importBusy,
onClick: this.handleImportButtonClick},
React.createElement("div", {className: cx({"contact-import-spinner": true,
spinner: true,
busy: this.state.importBusy})})
),
React.createElement(Button, {additionalClass: "primary",
caption: mozL10n.get("new_contact_button"),
onClick: this.handleAddContactButtonClick})
)
);
},
_renderGravatarPromoMessage: function() {
if (this.state.filter) {
return null;
}
return (
React.createElement("div", {className: "content-area"},
React.createElement(GravatarPromo, {handleUse: this.handleUseGravatar})
)
);
},
render: function() {
return (
React.createElement("div", null,
this._renderContactsFilter(),
this._renderGravatarPromoMessage(),
this._renderContactsList(),
React.createElement(ButtonGroup, {additionalClass: "contact-controls"},
React.createElement(Button, {additionalClass: "secondary",
caption: this.state.importBusy
? mozL10n.get("importing_contacts_progress_button")
: mozL10n.get("import_contacts_button3"),
disabled: this.state.importBusy,
onClick: this.handleImportButtonClick},
React.createElement("div", {className: cx({"contact-import-spinner": true,
spinner: true,
busy: this.state.importBusy})})
),
React.createElement(Button, {additionalClass: "primary",
caption: mozL10n.get("new_contact_button"),
onClick: this.handleAddContactButtonClick})
)
this._renderAddContactButtons()
)
);
}

View File

@ -413,6 +413,63 @@ loop.contacts = (function(_, mozL10n) {
window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
},
/*
* Filter a user by name, email or phone number.
* Takes in an input to filter by and returns a filter function which
* expects a contact.
*
* @returns {Function}
*/
filterContact: function(filter) {
return function(contact) {
return getPreferred(contact, "name").toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "email").value.toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "tel").value.toLocaleLowerCase().includes(filter);
};
},
/*
* Takes all contacts, it groups and filters them before rendering.
*/
_filterContactsList: function() {
let shownContacts = _.groupBy(this.contacts, function(contact) {
return contact.blocked ? "blocked" : "available";
});
if (this._shouldShowFilter()) {
let filter = this.state.filter.trim().toLocaleLowerCase();
let filterFn = this.filterContact(filter);
if (filter) {
if (shownContacts.available) {
shownContacts.available = shownContacts.available.filter(filterFn);
// Filter can return an empty array.
if (!shownContacts.available.length) {
shownContacts.available = null;
}
}
if (shownContacts.blocked) {
shownContacts.blocked = shownContacts.blocked.filter(filterFn);
// Filter can return an empty array.
if (!shownContacts.blocked.length) {
shownContacts.blocked = null;
}
}
}
}
return shownContacts;
},
/*
* Decide to render contacts filter based on the number of contacts.
*
* @returns {bool}
*/
_shouldShowFilter: function() {
return Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
},
_onStatusChanged: function() {
let profile = this.props.mozLoop.userProfile;
let currUid = this._userProfile ? this._userProfile.uid : null;
@ -531,6 +588,16 @@ loop.contacts = (function(_, mozL10n) {
this.refresh();
},
/*
* Callback triggered when clicking the `X` from the contacts filter.
* Clears the search query.
*/
_handleFilterClear: function() {
this.setState({
filter: ""
});
},
sortContacts: function(contact1, contact2) {
let comp = contact1.name[0].localeCompare(contact2.name[0]);
if (comp !== 0) {
@ -541,9 +608,35 @@ loop.contacts = (function(_, mozL10n) {
return contact1._guid - contact2._guid;
},
_renderFilterClearButton: function() {
if (this.state.filter) {
return (
<button className="clear-search"
onClick={this._handleFilterClear} />
);
}
return null;
},
_renderContactsFilter: function() {
if (this._shouldShowFilter()) {
return (
<div className="contact-filter-container">
<input className="contact-filter"
placeholder={mozL10n.get("contacts_search_placesholder")}
valueLink={this.linkState("filter")} />
{this._renderFilterClearButton()}
</div>
);
}
return null;
},
_renderContactsList: function() {
let cx = React.addons.classSet;
let shownContacts = this._filterContactsList();
let viewForItem = item => {
return (
<ContactDetail contact={item}
@ -552,92 +645,100 @@ loop.contacts = (function(_, mozL10n) {
);
};
let shownContacts = _.groupBy(this.contacts, function(contact) {
return contact.blocked ? "blocked" : "available";
});
let showFilter = Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
if (showFilter) {
let filter = this.state.filter.trim().toLocaleLowerCase();
if (filter) {
let filterFn = contact => {
return contact.name[0].toLocaleLowerCase().includes(filter) ||
getPreferred(contact, "email").value.toLocaleLowerCase().includes(filter);
};
if (shownContacts.available) {
shownContacts.available = shownContacts.available.filter(filterFn);
}
if (shownContacts.blocked) {
shownContacts.blocked = shownContacts.blocked.filter(filterFn);
}
}
// If no contacts to show and filter is set, then none match the search.
if (!shownContacts.available && !shownContacts.blocked &&
this.state.filter) {
return (
<div className="contact-search-list-empty">
<p className="panel-text-large">
{mozL10n.get("no_search_results_message_heading")}
</p>
<p className="panel-text-medium">
{mozL10n.get("no_search_results_message_subheading")}
</p>
</div>
);
}
if (shownContacts.available || shownContacts.blocked) {
// If no contacts to show and filter is not set, we don't have contacts.
if (!shownContacts.available && !shownContacts.blocked &&
!this.state.filter) {
return (
<div>
<div className="contact-list-title">
{mozL10n.get("contact_list_title")}
</div>
<ul className="contact-list">
{shownContacts.available ?
shownContacts.available.sort(this.sortContacts).map(viewForItem) :
null}
{shownContacts.blocked && shownContacts.blocked.length > 0 ?
<div className="contact-separator">{mozL10n.get("contacts_blocked_contacts")}</div> :
null}
{shownContacts.blocked ?
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
null}
</ul>
<div className="contact-list-empty">
<p className="panel-text-large">
{mozL10n.get("no_contacts_message_heading")}
</p>
<p className="panel-text-medium">
{mozL10n.get("no_contacts_import_or_add")}
</p>
</div>
);
}
return (
<div className="contact-list-empty">
<p className="panel-text-large">
{mozL10n.get("no_contacts_message_heading")}
</p>
<p className="panel-text-medium">
{mozL10n.get("no_contacts_import_or_add")}
</p>
<div>
{!this.state.filter ? <div className="contact-list-title">
{mozL10n.get("contact_list_title")}
</div> : null}
<ul className="contact-list">
{shownContacts.available ?
shownContacts.available.sort(this.sortContacts).map(viewForItem) :
null}
{shownContacts.blocked && shownContacts.blocked.length > 0 ?
<div className="contact-separator">{mozL10n.get("contacts_blocked_contacts")}</div> :
null}
{shownContacts.blocked ?
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
null}
</ul>
</div>
);
},
_renderAddContactButtons: function() {
let cx = React.addons.classSet;
if (this.state.filter) {
return null;
}
return (
<ButtonGroup additionalClass="contact-controls">
<Button additionalClass="secondary"
caption={this.state.importBusy ? mozL10n.get("importing_contacts_progress_button") :
mozL10n.get("import_contacts_button3")}
disabled={this.state.importBusy}
onClick={this.handleImportButtonClick} >
<div className={cx({"contact-import-spinner": true,
spinner: true,
busy: this.state.importBusy})} />
</Button>
<Button additionalClass="primary"
caption={mozL10n.get("new_contact_button")}
onClick={this.handleAddContactButtonClick} />
</ButtonGroup>
);
},
_renderGravatarPromoMessage: function() {
if (this.state.filter) {
return null;
}
return (
<div className="content-area">
<GravatarPromo handleUse={this.handleUseGravatar}/>
</div>
);
},
render: function() {
let cx = React.addons.classSet;
let showFilter = Object.getOwnPropertyNames(this.contacts).length >=
MIN_CONTACTS_FOR_FILTERING;
return (
<div>
<div className="content-area">
{showFilter ?
<input className="contact-filter"
placeholder={mozL10n.get("contacts_search_placesholder")}
valueLink={this.linkState("filter")} />
: null }
<GravatarPromo handleUse={this.handleUseGravatar}/>
</div>
{this._renderContactsFilter()}
{this._renderGravatarPromoMessage()}
{this._renderContactsList()}
<ButtonGroup additionalClass="contact-controls">
<Button additionalClass="secondary"
caption={this.state.importBusy
? mozL10n.get("importing_contacts_progress_button")
: mozL10n.get("import_contacts_button3")}
disabled={this.state.importBusy}
onClick={this.handleImportButtonClick} >
<div className={cx({"contact-import-spinner": true,
spinner: true,
busy: this.state.importBusy})} />
</Button>
<Button additionalClass="primary"
caption={mozL10n.get("new_contact_button")}
onClick={this.handleAddContactButtonClick} />
</ButtonGroup>
{this._renderAddContactButtons()}
</div>
);
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="92px" height="99px" viewBox="0 0 92 99" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M16,25.4921875 C16,21.7812314 17.1913943,18.0215034 19.5742188,14.2128906 C21.9570432,10.4042778 25.4335709,7.2500125 30.0039062,4.75 C34.5742416,2.2499875 39.9062195,1 46,1 C51.6640908,1 56.6640408,2.04491143 61,4.13476562 C65.3359592,6.22461982 68.6855351,9.06638828 71.0488281,12.6601562 C73.4121212,16.2539242 74.59375,20.1601352 74.59375,24.3789062 C74.59375,27.6992354 73.9199286,30.6093625 72.5722656,33.109375 C71.2246026,35.6093875 69.6230562,37.767569 67.7675781,39.5839844 C65.9121001,41.4003997 62.5820553,44.4570098 57.7773438,48.7539062 C56.4492121,49.9648498 55.3847696,51.0292923 54.5839844,51.9472656 C53.7831991,52.865239 53.187502,53.7050743 52.796875,54.4667969 C52.406248,55.2285194 52.1035167,55.9902306 51.8886719,56.7519531 C51.6738271,57.5136757 51.3515646,58.8515529 50.921875,60.765625 C50.1796838,64.8281453 47.8554883,66.859375 43.9492188,66.859375 C41.9179586,66.859375 40.2089913,66.1953191 38.8222656,64.8671875 C37.4355399,63.5390559 36.7421875,61.5664193 36.7421875,58.9492188 C36.7421875,55.6679523 37.2499949,52.8261839 38.265625,50.4238281 C39.2812551,48.0214724 40.6288979,45.9121185 42.3085938,44.0957031 C43.9882896,42.2792878 46.253892,40.1211062 49.1054688,37.6210938 C51.6054813,35.4335828 53.4121038,33.7832087 54.5253906,32.6699219 C55.6386774,31.5566351 56.5761681,30.3164131 57.3378906,28.9492188 C58.0996132,27.5820244 58.4804688,26.0976643 58.4804688,24.4960938 C58.4804688,21.3710781 57.318371,18.7343857 54.9941406,16.5859375 C52.6699103,14.4374893 49.6718934,13.3632812 46,13.3632812 C41.7031035,13.3632812 38.5390727,14.4472548 36.5078125,16.6152344 C34.4765523,18.783214 32.7578195,21.9765414 31.3515625,26.1953125 C30.0234309,30.6093971 27.5039248,32.8164062 23.7929688,32.8164062 C21.6054578,32.8164062 19.7597731,32.0449296 18.2558594,30.5019531 C16.7519456,28.9589767 16,27.2890715 16,25.4921875 L16,25.4921875 Z M44.59375,89.7109375 C42.2109256,89.7109375 40.1308683,88.9394608 38.3535156,87.3964844 C36.576163,85.8535079 35.6875,83.6953264 35.6875,80.921875 C35.6875,78.4609252 36.5468664,76.3906334 38.265625,74.7109375 C39.9843836,73.0312416 42.0937375,72.1914062 44.59375,72.1914062 C47.0546998,72.1914062 49.1249916,73.0312416 50.8046875,74.7109375 C52.4843834,76.3906334 53.3242188,78.4609252 53.3242188,80.921875 C53.3242188,83.6562637 52.4453213,85.8046797 50.6875,87.3671875 C48.9296787,88.9296953 46.898449,89.7109375 44.59375,89.7109375 L44.59375,89.7109375 Z" id="?-copy" fill="#D8D8D8"></path>
<path d="M30.0307824,90.7518487 C26.2851884,95.2457309 20.7911271,98.0823793 14.6681559,98.0823793 C9.0246635,98.0823793 3.91544008,95.6726018 0.217089748,91.7765187 C0.144175866,91.6997064 0.0718103773,91.6223165 -1.41595069e-13,91.5443559 C3.2164267,86.2421507 8.85313514,82.7267408 15.269241,82.7267408 C21.3600311,82.7267408 26.7484556,85.8947045 30.0307824,90.7518487 L30.0307824,90.7518487 Z M15.269241,80.2680577 C20.5820599,80.2680577 24.8889507,75.7308984 24.8889507,70.1340288 C24.8889507,64.5371593 20.5820599,60 15.269241,60 C9.95642199,60 5.64953124,64.5371593 5.64953124,70.1340288 C5.64953124,75.7308984 9.95642199,80.2680577 15.269241,80.2680577 Z" id="Mask-Copy-7" fill-opacity="0.8" fill="#D8D8D8"></path>
<path d="M91.0307824,90.7518487 C87.2851884,95.2457309 81.7911271,98.0823793 75.6681559,98.0823793 C70.0246635,98.0823793 64.9154401,95.6726018 61.2170897,91.7765187 C61.1441759,91.6997064 61.0718104,91.6223165 61,91.5443559 C64.2164267,86.2421507 69.8531351,82.7267408 76.269241,82.7267408 C82.3600311,82.7267408 87.7484556,85.8947045 91.0307824,90.7518487 L91.0307824,90.7518487 Z M76.269241,80.2680577 C81.5820599,80.2680577 85.8889507,75.7308984 85.8889507,70.1340288 C85.8889507,64.5371593 81.5820599,60 76.269241,60 C70.956422,60 66.6495312,64.5371593 66.6495312,70.1340288 C66.6495312,75.7308984 70.956422,80.2680577 76.269241,80.2680577 Z" id="Mask-Copy-8" fill-opacity="0.8" fill="#D8D8D8"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -42,6 +42,8 @@
</g>
<path id="contacts-shape" fill-rule="evenodd" transform="translate(-79.000000, -59.000000)" d="M91.5000066,69.9765672 C91.5000066,68.2109401 91.0859436,65.4999994 88.7968783,65.4999994 C88.5546906,65.4999994 87.5312518,66.5859382 86,66.5859382 C84.4687482,66.5859382 83.4453095,65.4999994 83.2031217,65.4999994 C80.9140564,65.4999994 80.4999935,68.2109401 80.4999935,69.9765672 C80.4999935,71.2421938 81.3437445,72.0000072 82.5859334,72.0000072 L89.4140666,72.0000072 C90.6562555,72.0000072 91.5000066,71.2421938 91.5000066,69.9765672 L91.5000066,69.9765672 L91.5000066,69.9765672 Z M89.0000036,62.9999964 C89.0000036,61.3437444 87.656252,59.9999928 86,59.9999928 C84.343748,59.9999928 82.9999964,61.3437444 82.9999964,62.9999964 C82.9999964,64.6562484 84.343748,66 86,66 C87.656252,66 89.0000036,64.6562484 89.0000036,62.9999964 L89.0000036,62.9999964 L89.0000036,62.9999964 Z" />
<path id="hello-shape" fill-rule="evenodd" transform="translate(-261.000000, -59.000000)" d="M268.273778,60 C264.809073,60 262,62.4730749 262,65.523237 C262,67.0417726 262.697086,68.4174001 263.822897,69.4155754 C263.627626,70.1061164 263.240356,71.0442922 262.474542,71.959559 C262.605451,72.1919211 264.761073,71.3737446 266.2807,70.7617485 C266.907968,70.946111 267.577782,71.046474 268.274868,71.046474 C271.740664,71.046474 274.549737,68.5733991 274.549737,65.523237 C274.549737,62.4730749 271.739573,60 268.274868,60 L268.273778,60 Z M270.15122,63.3119786 C270.609399,63.3119786 270.980306,63.6850671 270.980306,64.1432459 C270.980306,64.6036066 270.609399,64.9756042 270.15122,64.9756042 C269.693041,64.9756042 269.321044,64.6036066 269.321044,64.1432459 C269.321044,63.6850671 269.693041,63.3119786 270.15122,63.3119786 L270.15122,63.3119786 Z M266.36579,63.3119786 C266.823969,63.3119786 267.195966,63.6850671 267.195966,64.1432459 C267.195966,64.6036066 266.823969,64.9756042 266.36579,64.9756042 C265.907611,64.9756042 265.535613,64.6036066 265.535613,64.1432459 C265.535613,63.6850671 265.907611,63.3119786 266.36579,63.3119786 L266.36579,63.3119786 Z M268.283596,69.3675757 L268.258505,69.3664848 L268.233414,69.3675757 C266.557789,69.3675757 264.685801,68.2777646 264.254894,66.4428674 C265.38616,66.9675913 266.967968,67.1966807 268.258505,67.1966807 C269.549042,67.1966807 271.13085,66.9675913 272.262115,66.4428674 C271.8323,68.2777646 269.959221,69.3675757 268.283596,69.3675757 L268.283596,69.3675757 Z" />
<path id="clear-shape" d="M215.55504,63.8820643 C215.688665,63.7472288 215.688665,63.6111212 215.55504,63.4686535 L214.529316,62.463747 C214.382965,62.3174632 214.245523,62.3174632 214.116989,62.463747 L211.98791,64.6007632 L210.042087,62.6621843 C209.983547,62.6049428 209.917371,62.574414 209.841014,62.574414 C209.76593,62.574414 209.694664,62.6049428 209.631034,62.6621843 L208.666394,63.6518263 C208.520044,63.7866618 208.520044,63.9227694 208.666394,64.0639651 L210.586765,65.9821915 L208.466594,68.1192077 C208.408054,68.1789933 208.377511,68.245139 208.377511,68.3227331 C208.377511,68.3990551 208.408054,68.4690169 208.466594,68.5313465 L209.47323,69.5489733 C209.53177,69.6074868 209.599218,69.6380156 209.67812,69.6405597 C209.758295,69.6418317 209.827016,69.612575 209.885556,69.5489733 L212.023543,67.4208613 L213.942642,69.3568962 C214.001182,69.4141377 214.06863,69.4433945 214.150077,69.4433945 C214.228979,69.4433945 214.298973,69.4141377 214.357513,69.3568962 L215.347605,68.3672542 C215.481229,68.2324187 215.481229,68.0963111 215.347605,67.9551154 L213.399236,66.036889 L215.556313,63.8807923 L215.55504,63.8820643 Z M216.958731,61.0505179 C217.642123,61.7335999 218.152441,62.5057242 218.490955,63.3630747 C218.82947,64.2229693 219,65.0994003 219,66 C219,66.8980556 218.82947,67.7783027 218.490955,68.6394694 C218.152441,69.4955479 217.640851,70.2664001 216.958731,70.9507541 C216.274066,71.6338361 215.501591,72.1477376 214.63876,72.4873705 C213.775929,72.8295475 212.897827,73 212.001909,73 C211.103445,73 210.224071,72.8295475 209.36124,72.4873705 C208.498409,72.1464656 207.728479,71.6325641 207.043814,70.9507541 C206.360422,70.2664001 205.848832,69.4955479 205.509045,68.6394694 C205.17053,67.7795748 205,66.8993276 205,66 C205,65.0994003 205.171803,64.2216973 205.514135,63.3592586 C205.855195,62.4968199 206.36424,61.7285117 207.042542,61.0492459 C207.727207,60.3661639 208.498409,59.8548065 209.359967,59.5126295 C210.222798,59.1704525 211.1009,59 212.000636,59 C212.896555,59 213.774657,59.1704525 214.637488,59.5126295 C215.500318,59.8548065 216.272793,60.3674359 216.957458,61.0492459 L216.958731,61.0505179 Z" transform="translate(-205 -59)" fill="#9B9B9B" fill-rule="evenodd"/>
<path id="magnifier-shape" d="M191.499904,64.0475302 C191.499904,66.8377127 193.779753,69.0950604 196.596937,69.0950604 C199.414121,69.0950604 201.693971,66.8377127 201.693971,64.0475302 C201.693971,61.2573477 199.414121,59 196.596937,59 C193.779753,59 191.499904,61.2573477 191.499904,64.0475302 L191.499904,64.0475302 Z M193.353125,64.0475302 C193.353125,62.2762143 194.80852,60.8352201 196.596937,60.8352201 C198.385354,60.8352201 199.840749,62.2762143 199.840749,64.0475302 C199.840749,65.8188461 198.385354,67.2598403 196.596937,67.2598403 C194.80852,67.2598403 193.353125,65.8188461 193.353125,64.0475302 L193.353125,64.0475302 Z M200.600399,69.8475096 L203.046759,72.2704681 C203.324877,72.5458861 203.927017,72.5827885 204.418449,72.3343723 C204.946783,72.0679548 205.150197,70.9941846 204.881979,70.6548624 L202.472522,68.2229033 C202.055794,67.7089697 201.23044,67.7179703 200.693105,68.2508051 C200.211574,68.7278363 200.192672,69.4442832 200.600399,69.8475096 L200.600399,69.8475096 Z" transform="translate(-191 -59)" fill="#9B9B9B" fill-rule="evenodd"/>
</defs>
<use id="audio" xlink:href="#audio-shape"/>
<use id="audio-active" xlink:href="#audio-shape"/>
@ -77,4 +79,6 @@
<use id="volume" xlink:href="#volume-shape"/>
<use id="volume-active" xlink:href="#volume-shape"/>
<use id="volume-disabled" xlink:href="#volume-shape"/>
<use id="clear" xlink:href="#clear-shape"/>
<use id="magnifier" xlink:href="#magnifier-shape"/>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -75,6 +75,7 @@ browser.jar:
content/browser/loop/shared/img/ellipsis-v.svg (content/shared/img/ellipsis-v.svg)
content/browser/loop/shared/img/empty_contacts.svg (content/shared/img/empty_contacts.svg)
content/browser/loop/shared/img/empty_conversations.svg (content/shared/img/empty_conversations.svg)
content/browser/loop/shared/img/empty_search.svg (content/shared/img/empty_search.svg)
content/browser/loop/shared/img/avatars.svg (content/shared/img/avatars.svg)
# Shared scripts

View File

@ -13,7 +13,7 @@ describe("loop.contacts", function() {
var fakeEditContactButtonText = "Fake Edit Contact";
var fakeDoneButtonText = "Fake Done";
// The fake contacts array is copied each time mozLoop.contacts.getAll() is called.
var fakeContacts = [{
var fakeManyContacts = [{
id: 1,
_guid: 1,
name: ["Ally Avocado"],
@ -71,7 +71,45 @@ describe("loop.contacts", function() {
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 5,
_guid: 5,
name: ["Erin J. Bazile"],
email: [{
"pref": true,
"type": ["work"],
"value": "erinjbazile@armyspy.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 6,
_guid: 6,
name: ["Kelly F. Maldanado"],
email: [{
"pref": true,
"type": ["work"],
"value": "kellyfmaldonado@jourrapide.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 7,
_guid: 7,
name: ["John J. Brown"],
email: [{
"pref": true,
"type": ["work"],
"value": "johnjbrow@johndoe.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748,
blocked: true
}];
var fakeFewerContacts = fakeManyContacts.slice(0, 4);
var sandbox;
var fakeWindow;
var notifications;
@ -115,7 +153,7 @@ describe("loop.contacts", function() {
},
contacts: {
getAll: function(callback) {
callback(null, [].concat(fakeContacts));
callback(null, [].concat(fakeFewerContacts));
},
on: sandbox.stub()
},
@ -148,10 +186,10 @@ describe("loop.contacts", function() {
// When gravatars are enabled, contacts should be rendered with gravatars.
var gravatars = node.querySelectorAll(".contact img[src=gravatarsEnabled]");
expect(gravatars.length).to.equal(enabled ? fakeContacts.length : 0);
expect(gravatars.length).to.equal(enabled ? fakeFewerContacts.length : 0);
// Sanity check the reverse:
gravatars = node.querySelectorAll(".contact img[src=gravatarsDisabled]");
expect(gravatars.length).to.equal(enabled ? 0 : fakeContacts.length);
expect(gravatars.length).to.equal(enabled ? 0 : fakeFewerContacts.length);
}
it("should show the gravatars promo box", function() {
@ -297,7 +335,7 @@ describe("loop.contacts", function() {
describe("#RenderWithContacts", function() {
beforeEach(function() {
sandbox.stub(navigator.mozLoop.contacts, "getAll", function(cb) {
cb(null, [].concat(fakeContacts));
cb(null, [].concat(fakeFewerContacts));
});
listView = TestUtils.renderIntoDocument(
React.createElement(loop.contacts.ContactsList, {
@ -312,6 +350,120 @@ describe("loop.contacts", function() {
expect(node.querySelector(".contact-list-title")).not.to.eql(null);
sinon.assert.calledWithExactly(mozL10nGetSpy, "contact_list_title");
});
it("should not render the filter view unless MIN_CONTACTS_FOR_FILTERING",
function() {
var filterView = listView.getDOMNode()
.querySelector(".contact-filter-container");
expect(filterView).to.eql(null);
});
});
describe("ContactsFiltering", function() {
beforeEach(function() {
navigator.mozLoop.contacts = {
getAll: function(callback) {
callback(null, [].concat(fakeManyContacts));
},
on: sandbox.stub()
};
listView = TestUtils.renderIntoDocument(
React.createElement(loop.contacts.ContactsList, {
mozLoop: navigator.mozLoop,
notifications: notifications,
startForm: function() {}
}));
node = listView.getDOMNode();
});
it("should filter a non-existent user name", function() {
expect(listView.filterContact("foo")(fakeFewerContacts[0]))
.to.eql(false);
});
it("should display search returned no contacts view", function() {
listView.setState({
filter: "foo"
});
var view = node.querySelector(".contact-search-list-empty");
expect(view).to.not.eql(null);
});
it("should display the no search results strings", function() {
listView.setState({
filter: "foo"
});
sinon.assert.calledWithExactly(mozL10nGetSpy,
"no_search_results_message_heading");
sinon.assert.calledWithExactly(mozL10nGetSpy,
"no_search_results_message_subheading");
});
it("should filter the user name correctly", function() {
expect(listView.filterContact("ally")(fakeFewerContacts[0]))
.to.eql(true);
});
it("should filter and render a contact", function() {
listView.setState({
filter: "Ally"
});
var contacts = node.querySelectorAll(".contact");
expect(contacts.length).to.eql(1);
});
it("should render a list of contacts", function() {
var contactList = listView.getDOMNode().querySelectorAll(".contact");
expect(contactList.length).to.eql(fakeManyContacts.length);
});
it("should render the filter view for >= MIN_CONTACTS_FOR_FILTERING",
function() {
var filterView = listView.getDOMNode()
.querySelector(".contact-filter-container");
expect(filterView).to.not.eql(null);
});
it("should filter by name", function() {
var input = listView.getDOMNode()
.querySelector(".contact-filter-container input");
React.addons.TestUtils.Simulate.change(input,
{ target: { value: "Ally" } });
var contactList = listView.getDOMNode().querySelectorAll(".contact");
expect(contactList.length).to.eql(1);
});
it("should filter by email", function() {
var input = listView.getDOMNode()
.querySelector(".contact-filter-container input");
React.addons.TestUtils.Simulate.change(input,
{ target: { value: "@hotmail" } });
var contactList = listView.getDOMNode().querySelectorAll(".contact");
expect(contactList.length).to.eql(1);
});
it("should filter by phone number", function() {
var input = listView.getDOMNode()
.querySelector(".contact-filter-container input");
React.addons.TestUtils.Simulate.change(input,
{ target: { value: "12345678" } });
var contactList = listView.getDOMNode().querySelectorAll(".contact");
expect(contactList.length).to.eql(1);
});
});
describe("#handleContactAction", function() {

View File

@ -54,7 +54,7 @@ var fakeRooms = [
}
];
var fakeContacts = [{
var fakeManyContacts = [{
id: 1,
_guid: 1,
name: ["Ally Avocado"],
@ -112,7 +112,44 @@ var fakeContacts = [{
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 5,
_guid: 5,
name: ["Erin J. Bazile"],
email: [{
"pref": true,
"type": ["work"],
"value": "erinjbazile@armyspy.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 6,
_guid: 6,
name: ["Kelly F. Maldanado"],
email: [{
"pref": true,
"type": ["work"],
"value": "kellyfmaldonado@jourrapide.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}, {
id: 7,
_guid: 7,
name: ["John J. Brown"],
email: [{
"pref": true,
"type": ["work"],
"value": "johnjbrow@johndoe.com"
}],
category: ["google"],
published: 1406798311748,
updated: 1406798311748
}];
var fakeFewerContacts = fakeManyContacts.slice(0, 4);
(function() {
"use strict";
@ -152,7 +189,7 @@ var fakeContacts = [{
},
contacts: {
getAll: function(callback) {
callback(null, [].concat(fakeContacts));
callback(null, [].concat(fakeManyContacts));
},
on: function() {}
},

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global Frame:false uncaughtError:true fakeContacts:true */
/* global Frame:false uncaughtError:true fakeManyContacts:true fakeFewerContacts:true */
(function() {
"use strict";
@ -469,6 +469,9 @@
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
var mozLoopNoContacts = _.cloneDeep(navigator.mozLoop);
mozLoopNoContacts.contacts.getAll = function(callback) {
callback(null, []);
};
mozLoopNoContacts.userProfile = {
email: "reallyreallylongtext@example.com",
uid: "0354b278a381d3cb408bb46ffc01266"
@ -477,6 +480,15 @@
callback(null, []);
};
var mozLoopNoContactsFilter = _.cloneDeep(navigator.mozLoop);
mozLoopNoContactsFilter.userProfile = {
email: "reallyreallylongtext@example.com",
uid: "0354b278a381d3cb408bb46ffc01266"
};
mozLoopNoContactsFilter.contacts.getAll = function(callback) {
callback(null, fakeFewerContacts); // Defined in fake-mozLoop.js.
};
var mockContact = {
name: ["Mr Smith"],
email: [{
@ -539,7 +551,7 @@
"link", "link-active", "link-disabled", "mute", "mute-active",
"mute-disabled", "pause", "pause-active", "pause-disabled", "video",
"video-white", "video-active", "video-disabled", "volume", "volume-active",
"volume-disabled"
"volume-disabled", "clear", "magnifier"
],
"16x16": ["add", "add-hover", "add-active", "audio", "audio-hover", "audio-active",
"block", "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
@ -753,6 +765,20 @@
selectedTab: "contacts"})
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
summary: "Contact list tab (no search filter)",
width: 332},
React.createElement("div", {className: "panel"},
React.createElement(PanelView, {client: mockClient,
dispatcher: dispatcher,
mozLoop: mozLoopNoContactsFilter,
notifications: notifications,
roomStore: roomStore,
selectedTab: "contacts"})
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
@ -882,7 +908,7 @@
summary: "ContactDetail",
width: 300},
React.createElement("div", {className: "panel force-menu-show"},
React.createElement(ContactDetail, {contact: fakeContacts[0],
React.createElement(ContactDetail, {contact: fakeManyContacts[0],
handleContactAction: function() {}})
)
)

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global Frame:false uncaughtError:true fakeContacts:true */
/* global Frame:false uncaughtError:true fakeManyContacts:true fakeFewerContacts:true */
(function() {
"use strict";
@ -469,6 +469,9 @@
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
var mozLoopNoContacts = _.cloneDeep(navigator.mozLoop);
mozLoopNoContacts.contacts.getAll = function(callback) {
callback(null, []);
};
mozLoopNoContacts.userProfile = {
email: "reallyreallylongtext@example.com",
uid: "0354b278a381d3cb408bb46ffc01266"
@ -477,6 +480,15 @@
callback(null, []);
};
var mozLoopNoContactsFilter = _.cloneDeep(navigator.mozLoop);
mozLoopNoContactsFilter.userProfile = {
email: "reallyreallylongtext@example.com",
uid: "0354b278a381d3cb408bb46ffc01266"
};
mozLoopNoContactsFilter.contacts.getAll = function(callback) {
callback(null, fakeFewerContacts); // Defined in fake-mozLoop.js.
};
var mockContact = {
name: ["Mr Smith"],
email: [{
@ -539,7 +551,7 @@
"link", "link-active", "link-disabled", "mute", "mute-active",
"mute-disabled", "pause", "pause-active", "pause-disabled", "video",
"video-white", "video-active", "video-disabled", "volume", "volume-active",
"volume-disabled"
"volume-disabled", "clear", "magnifier"
],
"16x16": ["add", "add-hover", "add-active", "audio", "audio-hover", "audio-active",
"block", "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
@ -753,6 +765,20 @@
selectedTab="contacts" />
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
summary="Contact list tab (no search filter)"
width={332}>
<div className="panel">
<PanelView client={mockClient}
dispatcher={dispatcher}
mozLoop={mozLoopNoContactsFilter}
notifications={notifications}
roomStore={roomStore}
selectedTab="contacts" />
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
@ -882,7 +908,7 @@
summary="ContactDetail"
width={300}>
<div className="panel force-menu-show">
<ContactDetail contact={fakeContacts[0]}
<ContactDetail contact={fakeManyContacts[0]}
handleContactAction={function() {}} />
</div>
</FramedExample>

View File

@ -172,6 +172,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
"resource://gre/modules/ExtensionManagement.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
@ -821,7 +824,8 @@ BrowserGlue.prototype = {
_checkForOldBuildUpdates: function () {
// check for update if our build is old
if (Services.prefs.getBoolPref("app.update.enabled") &&
if (AppConstants.MOZ_UPDATER &&
Services.prefs.getBoolPref("app.update.enabled") &&
Services.prefs.getBoolPref("app.update.checkInstallTime")) {
let buildID = Services.appinfo.appBuildID;
@ -1793,23 +1797,6 @@ BrowserGlue.prototype = {
}
}
if (currentUIVersion < 3) {
// This code merges the reload/stop/go button into the url bar.
let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset");
// Need to migrate only if toolbar is customized and all 3 elements are found.
if (currentset &&
currentset.indexOf("reload-button") != -1 &&
currentset.indexOf("stop-button") != -1 &&
currentset.indexOf("urlbar-container") != -1 &&
currentset.indexOf("urlbar-container,reload-button,stop-button") == -1) {
currentset = currentset.replace(/(^|,)reload-button($|,)/, "$1$2")
.replace(/(^|,)stop-button($|,)/, "$1$2")
.replace(/(^|,)urlbar-container($|,)/,
"$1urlbar-container,reload-button,stop-button$2");
xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset);
}
}
if (currentUIVersion < 4) {
// This code moves the home button to the immediate left of the bookmarks menu button.
let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset");
@ -1921,10 +1908,7 @@ BrowserGlue.prototype = {
}
if (currentUIVersion < 16) {
let isCollapsed = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "collapsed");
if (isCollapsed == "true") {
xulStore.setValue(BROWSER_DOCURL, "nav-bar", "collapsed", "false");
}
xulStore.removeValue(BROWSER_DOCURL, "nav-bar", "collapsed");
}
// Insert the bookmarks-menu-button into the nav-bar if it isn't already
@ -1984,12 +1968,6 @@ BrowserGlue.prototype = {
xulStore.removeValue(BROWSER_DOCURL, "TabsToolbar", "collapsed");
}
if (currentUIVersion < 21) {
// Make sure the 'toolbarbutton-1' class will always be present from here
// on out.
xulStore.removeValue(BROWSER_DOCURL, "bookmarks-menu-button", "class");
}
if (currentUIVersion < 22) {
// Reset the Sync promobox count to promote the new FxAccount-based Sync.
Services.prefs.clearUserPref("browser.syncPromoViewsLeft");

View File

@ -116,9 +116,6 @@ var gPrivacyPane = {
gPrivacyPane.showCookies);
setEventListener("clearDataSettings", "command",
gPrivacyPane.showClearPrivateDataSettings);
document.getElementById("searchesSuggestion").hidden =
!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
},
// HISTORY MODE

View File

@ -41,9 +41,6 @@
<preference id="browser.urlbar.suggest.openpage"
name="browser.urlbar.suggest.openpage"
type="bool"/>
<preference id="browser.urlbar.suggest.searches"
name="browser.urlbar.suggest.searches"
type="bool"/>
<!-- History -->
<preference id="places.history.enabled"
@ -261,8 +258,7 @@
<checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
accesskey="&locbar.openpage.accesskey;"
preference="browser.urlbar.suggest.openpage"/>
<checkbox id="searchesSuggestion" label="&locbar.searches.label;"
hidden="true"
accesskey="&locbar.searches.accesskey;"
preference="browser.urlbar.suggest.searches"/>
<label class="text-link" onclick="if (event.button == 0) gotoPref('search')">
&suggestionSettings.label;
</label>
</groupbox>

View File

@ -29,6 +29,25 @@ var gEngineView = null;
var gSearchPane = {
/**
* Initialize autocomplete to ensure prefs are in sync.
*/
_initAutocomplete: function () {
let unifiedCompletePref = false;
try {
unifiedCompletePref =
Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
} catch (ex) {}
if (unifiedCompletePref) {
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
.getService(Components.interfaces.mozIPlacesAutoComplete);
} else {
Components.classes["@mozilla.org/autocomplete/search;1?name=history"]
.getService(Components.interfaces.mozIPlacesAutoComplete);
}
},
init: function ()
{
gEngineView = new EngineView(new EngineStore());
@ -46,6 +65,18 @@ var gSearchPane = {
window.addEventListener("unload", () => {
Services.obs.removeObserver(this, "browser-search-engine-modified", false);
});
this._initAutocomplete();
let urlbarSuggests = document.getElementById("urlBarSuggestion");
urlbarSuggests.hidden = !Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
let suggestsPref = document.getElementById("browser.search.suggest.enabled")
let updateSuggestsCheckbox = () => {
urlbarSuggests.disabled = !suggestsPref.value;
}
suggestsPref.addEventListener("change", updateSuggestsCheckbox);
updateSuggestsCheckbox();
},
buildDefaultEngineDropDown: function() {

View File

@ -4,6 +4,10 @@
name="browser.search.suggest.enabled"
type="bool"/>
<preference id="browser.urlbar.suggest.searches"
name="browser.urlbar.suggest.searches"
type="bool"/>
<preference id="browser.search.hiddenOneOffs"
name="browser.search.hiddenOneOffs"
type="unichar"/>
@ -37,6 +41,12 @@
label="&provideSearchSuggestions.label;"
accesskey="&provideSearchSuggestions.accesskey;"
preference="browser.search.suggest.enabled"/>
<hbox class="indent">
<checkbox id="urlBarSuggestion" label="&showURLBarSuggestions.label;"
hidden="true"
accesskey="&showURLBarSuggestions.accesskey;"
preference="browser.urlbar.suggest.searches"/>
</hbox>
<checkbox id="redirectSearchCheckbox"
label="&redirectWindowsSearch.label;"
accesskey="&redirectWindowsSearch.accesskey;"

View File

@ -25,6 +25,7 @@ skip-if = !healthreport || (os == 'linux' && debug)
[browser_privacypane_8.js]
skip-if = e10s # Bug ?????? - "leaked until shutdown [nsGlobalWindow #99 about:preferences]"
[browser_sanitizeOnShutdown_prefLocked.js]
[browser_searchsuggestions.js]
[browser_subdialogs.js]
skip-if = e10s # Bug 1087114
support-files = subdialog.xul

View File

@ -20,8 +20,5 @@ function test() {
test_locbar_suggestion_retention("history", false),
];
if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
tests.push(test_locbar_suggestion_retention("searches", true));
run_test_subset(tests);
}

View File

@ -0,0 +1,43 @@
let original = Services.prefs.getBoolPref("browser.search.suggest.enabled");
registerCleanupFunction(() => {
Services.prefs.setBoolPref("browser.search.suggest.enabled", original);
});
// Open with suggestions enabled
add_task(function*() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
yield openPreferencesViaOpenPreferencesAPI("search", undefined, { leaveOpen: true });
let doc = gBrowser.selectedBrowser.contentDocument;
let urlbarBox = doc.getElementById("urlBarSuggestion");
ok(!urlbarBox.disabled, "Checkbox should be enabled");
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
ok(urlbarBox.disabled, "Checkbox should be disabled");
gBrowser.removeCurrentTab();
});
// Open with suggestions disabled
add_task(function*() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
yield openPreferencesViaOpenPreferencesAPI("search", undefined, { leaveOpen: true });
let doc = gBrowser.selectedBrowser.contentDocument;
let urlbarBox = doc.getElementById("urlBarSuggestion");
ok(urlbarBox.disabled, "Checkbox should be disabled");
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
ok(!urlbarBox.disabled, "Checkbox should be enabled");
gBrowser.removeCurrentTab();
});
add_task(function*() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", original);
});

View File

@ -151,9 +151,9 @@ Telemetry.prototype = {
timerHistogram: "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS"
},
storage: {
histogram: "DEVTOOLS_STORAGE_OPENED_BOOLEAN",
userHistogram: "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
histogram: "DEVTOOLS_STORAGE_OPENED_BOOLEAN",
userHistogram: "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
},
tilt: {
histogram: "DEVTOOLS_TILT_OPENED_BOOLEAN",
@ -197,6 +197,23 @@ Telemetry.prototype = {
userHistogram: "DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS"
},
webideProjectEditor: {
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN",
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS"
},
webideProjectEditorSave: {
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_BOOLEAN",
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG",
},
webideNewProject: {
histogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_BOOLEAN",
userHistogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG",
},
webideImportProject: {
histogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN",
userHistogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG",
},
custom: {
histogram: "DEVTOOLS_CUSTOM_OPENED_BOOLEAN",
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
@ -225,6 +242,15 @@ Telemetry.prototype = {
}
},
/**
* Record that an action occurred. Aliases to `toolOpened`, so it's just for
* readability at the call site for cases where we aren't actually opening
* tools.
*/
actionOccurred(id) {
this.toolOpened(id);
},
toolClosed: function(id) {
let charts = this._histograms[id];

View File

@ -147,6 +147,8 @@ let UI = {
window.removeEventListener("message", this.onMessage);
this.updateConnectionTelemetry();
this._telemetry.toolClosed("webide");
this._telemetry.toolClosed("webideProjectEditor");
this._telemetry.destroy();
},
canCloseProject: function() {
@ -670,13 +672,18 @@ let UI = {
}
},
updateProjectEditorMenusVisibility: function() {
/**
* Called when selecting or deselecting the project editor panel.
*/
onChangeProjectEditorSelected: function() {
if (this.projecteditor) {
let panel = document.querySelector("#deck").selectedPanel;
if (panel && panel.id == "deck-panel-projecteditor") {
this.projecteditor.menuEnabled = true;
this._telemetry.toolOpened("webideProjectEditor");
} else {
this.projecteditor.menuEnabled = false;
this._telemetry.toolClosed("webideProjectEditor");
}
}
},
@ -691,8 +698,9 @@ let UI = {
menubar: document.querySelector("#main-menubar"),
menuindex: 1
});
this.projecteditor.on("onEditorSave", (editor, resource) => {
this.projecteditor.on("onEditorSave", () => {
AppManager.validateAndUpdateProject(AppManager.selectedProject);
this._telemetry.actionOccurred("webideProjectEditorSave");
});
return this.projecteditor.loaded;
},
@ -748,11 +756,11 @@ let UI = {
// Show ProjectEditor
this.selectDeckPanel("projecteditor");
this.getProjectEditor().then(() => {
this.updateProjectEditorHeader();
}, console.error);
this.selectDeckPanel("projecteditor");
},
autoStartProject: Task.async(function*() {
@ -806,6 +814,8 @@ let UI = {
// Select project
AppManager.selectedProject = project;
this._telemetry.actionOccurred("webideImportProject");
}),
// Remember the last selected project on the runtime
@ -919,7 +929,7 @@ let UI = {
panel.setAttribute("src", lazysrc);
}
deck.selectedPanel = panel;
this.updateProjectEditorMenusVisibility();
this.onChangeProjectEditorSelected();
this.updateToolboxFullscreenState();
},
@ -927,7 +937,7 @@ let UI = {
this.resetFocus();
let deck = document.querySelector("#deck");
deck.selectedPanel = null;
this.updateProjectEditorMenusVisibility();
this.onChangeProjectEditorSelected();
},
buildIDToDate(buildID) {

View File

@ -11,6 +11,7 @@ const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const EventEmitter = require("devtools/toolkit/event-emitter");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const utils = require("devtools/webide/utils");
const Telemetry = require("devtools/shared/telemetry");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
@ -23,6 +24,7 @@ module.exports = ProjectList = function(win, parentWindow) {
this._parentWindow = parentWindow;
this._panelNodeEl = "toolbarbutton";
this._sidebarsEnabled = Services.prefs.getBoolPref("devtools.webide.sidebars");
this._telemetry = new Telemetry();
if (this._sidebarsEnabled) {
this._panelNodeEl = "div";
@ -77,6 +79,7 @@ ProjectList.prototype = {
*/
newApp: function(testOptions) {
let parentWindow = this._parentWindow;
let self = this;
return this._UI.busyUntil(Task.spawn(function*() {
// Open newapp.xul, which will feed ret.location
let ret = {location: null, testOptions: testOptions};
@ -89,6 +92,8 @@ ProjectList.prototype = {
// Select project
AppManager.selectedProject = project;
self._telemetry.actionOccurred("webideNewProject");
}), "creating new app");
},

View File

@ -164,10 +164,17 @@
function checkResults() {
let result = Telemetry.prototype.telemetryInfo;
for (let [histId, value] of Iterator(result)) {
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
if (histId.endsWith("_PER_USER_FLAG")) {
ok(value.length === 1 && !!value[0],
"Per user value " + histId + " has a single value of true");
} else if (histId.endsWith("OPENED_BOOLEAN")) {
} else if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") {
ok(value.length === 1 && !!value[0],
histId + " has 1 successful entry");
} else if (histId ===
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN") {
ok(value.length === 1 && !!value[0],
histId + " has 1 successful entry");
} else if (histId === "DEVTOOLS_WEBIDE_OPENED_BOOLEAN") {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
@ -175,7 +182,7 @@
});
ok(okay, "All " + histId + " entries are true");
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
} else if (histId.endsWith("WEBIDE_TIME_ACTIVE_SECONDS")) {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
@ -183,6 +190,9 @@
});
ok(okay, "All " + histId + " entries have time > 0");
} else if (histId.endsWith("EDITOR_TIME_ACTIVE_SECONDS")) {
ok(value.length === 1 && value[0] > 0,
histId + " has 1 entry with time > 0");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
ok(value.length === 6, histId + " has 6 connection results");

View File

@ -164,10 +164,17 @@
function checkResults() {
let result = Telemetry.prototype.telemetryInfo;
for (let [histId, value] of Iterator(result)) {
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
if (histId.endsWith("_PER_USER_FLAG")) {
ok(value.length === 1 && !!value[0],
"Per user value " + histId + " has a single value of true");
} else if (histId.endsWith("OPENED_BOOLEAN")) {
} else if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") {
ok(value.length === 1 && !!value[0],
histId + " has 1 successful entry");
} else if (histId ===
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN") {
ok(value.length === 1 && !!value[0],
histId + " has 1 successful entry");
} else if (histId === "DEVTOOLS_WEBIDE_OPENED_BOOLEAN") {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
@ -175,7 +182,7 @@
});
ok(okay, "All " + histId + " entries are true");
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
} else if (histId.endsWith("WEBIDE_TIME_ACTIVE_SECONDS")) {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
@ -183,6 +190,9 @@
});
ok(okay, "All " + histId + " entries have time > 0");
} else if (histId.endsWith("EDITOR_TIME_ACTIVE_SECONDS")) {
ok(value.length === 1 && value[0] > 0,
histId + " has 1 entry with time > 0");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
ok(value.length === 6, histId + " has 6 connection results");

View File

@ -86,7 +86,7 @@ settings_menu_button_tooltip=Settings
## LOCALIZATION NOTE(contacts_search_placeholder): This is the placeholder text for
## the search field.
contacts_search_placesholder=Search…
contacts_search_placesholder=Type in contact name, email, phone number
## LOCALIZATION NOTE (new_contact_button): This is the button to open the
## new contact sub-panel.
@ -131,7 +131,7 @@ import_contacts_success_message={{total}} contact was successfully imported.;{{t
## LOCALIZATION NOTE(sync_contacts_button): This button is displayed in place of
## importing_contacts_button once contacts have been imported once.
sync_contacts_button=Sync Contacts
## LOCALIZATION NOTE(no_contacts_message_heading): Title shown when user has no
# LOCALIZATION NOTE(no_contacts_message_heading): Title shown when user has no
## contacts in his address book
no_contacts_message_heading=No contacts yet
## LOCALIZATION NOTE(no_contacts_import_or_add): Subheading inviting the user
@ -143,6 +143,10 @@ no_conversations_message_heading=There are no conversations yet
## LOCALIZATION NOTE(no_converastions_start_message): Subheading inviting the
## user to start a new conversation.
no_conversations_start_message=start a new conversation!
## LOCALIZATION NOTE(no_search_results_message_heading): Title to show when
## search returned no matching results.
no_search_results_message_heading=No matching results
no_search_results_message_subheading=with your search, try again!
## LOCALIZATION NOTE(import_failed_description simple): Displayed when an import of
## contacts fails. This is displayed in the error field.

View File

@ -1,32 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/netmonitor.inc.css
#headers-summary-resend {
padding: 4px;
}
#toggle-raw-headers {
padding: 4px;
}
.requests-menu-status-and-method {
width: 9em;
}
.requests-menu-security-and-domain {
width: 16vw;
}
.requests-menu-size {
width: 6em;
}
/* Responsive sidebar */
@media (max-width: 700px) {
.requests-menu-header-button {
font-size: 85%;
}
}

View File

@ -1,9 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/webconsole.inc.css
.jsterm-input-node {
width: 98%;
}

View File

@ -1,99 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
body {
font-family: sans-serif;
font-size: 11px;
background: #EEE;
color: #000;
}
#header {
padding: 5px;
overflow-x:auto;
display: block;
}
h1 {
font-size: 13px;
line-height: 15px;
padding: 3px 10px;
vertical-align: bottom;
margin: 0px;
background: linear-gradient(#BBB, #999);
border-radius: 2px;
text-shadow: #FFF 0px 1px 0px;
}
h1 .info {
font-size: 11px;
line-height: 15px;
vertical-align: bottom;
float: right;
color: #333;
padding-right: 3px;
}
.property-table {
padding: 2px 5px;
background: linear-gradient(#FFF, #F8F8F8);
color: #333;
width: 100%;
max-height: 330px;
overflow: auto;
display: block;
}
.property-name {
font-size: 11px;
font-weight: bold;
color: #000;
white-space: nowrap;
text-align: end;
vertical-align: top;
width: 10%;
}
.property-value {
padding-right: 5px;
font-size: 11px;
word-wrap: break-word;
width: 90%;
}
div.group {
margin-top: 10px;
}
div.group,
#header {
background: #FFF;
border-color: #E1E1E1;
border-style: solid;
border-width: 1px;
box-shadow: 0 1px 1.5px rgba(0, 0, 0, 0.2);
border-radius: 4px 4px 4px 4px;
}
img#responseImageNode {
box-shadow: rgba(0,0,0,0.2) 0px 3px 3.5px;
max-width: 100%;
}
#responseImageNodeDiv {
padding: 5px;
}
#responseBodyFetchLink, #requestBodyFetchLink {
padding: 5px;
margin: 0;
cursor: pointer;
font-weight: bold;
font-size: 1.1em;
text-decoration: underline;
}
.longStringEllipsis {
margin-left: 0.6em;
}

View File

@ -1,11 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/widgets.inc.css
.side-menu-widget-group-checkbox .checkbox-spacer-box,
.side-menu-widget-item-checkbox .checkbox-spacer-box {
margin: 0;
border: none;
}

View File

@ -301,7 +301,7 @@ browser.jar:
skin/classic/browser/devtools/newtab@2x.png (../shared/devtools/images/newtab@2x.png)
skin/classic/browser/devtools/newtab-inverted.png (../shared/devtools/images/newtab-inverted.png)
skin/classic/browser/devtools/newtab-inverted@2x.png (../shared/devtools/images/newtab-inverted@2x.png)
* skin/classic/browser/devtools/widgets.css (devtools/widgets.css)
* skin/classic/browser/devtools/widgets.css (../shared/devtools/widgets.css)
skin/classic/browser/devtools/power.svg (../shared/devtools/images/power.svg)
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
@ -332,8 +332,8 @@ browser.jar:
skin/classic/browser/devtools/alerticon-warning.png (../shared/devtools/images/alerticon-warning.png)
skin/classic/browser/devtools/alerticon-warning@2x.png (../shared/devtools/images/alerticon-warning@2x.png)
* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
* skin/classic/browser/devtools/webconsole.css (../shared/devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (../shared/devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.svg (../shared/devtools/images/webconsole.svg)
skin/classic/browser/devtools/commandline.css (../shared/devtools/commandline.css)
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
@ -348,7 +348,7 @@ browser.jar:
* skin/classic/browser/devtools/canvasdebugger.css (../shared/devtools/canvasdebugger.css)
skin/classic/browser/devtools/debugger.css (../shared/devtools/debugger.css)
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/netmonitor.css (../shared/devtools/netmonitor.css)
skin/classic/browser/devtools/performance.css (../shared/devtools/performance.css)
skin/classic/browser/devtools/promisedebugger.css (../shared/devtools/promisedebugger.css)
skin/classic/browser/devtools/timeline-filter.svg (../shared/devtools/images/timeline-filter.svg)
@ -415,8 +415,8 @@ browser.jar:
skin/classic/browser/devtools/dock-bottom-minimize@2x.png (../shared/devtools/images/dock-bottom-minimize@2x.png)
skin/classic/browser/devtools/dock-bottom-maximize@2x.png (../shared/devtools/images/dock-bottom-maximize@2x.png)
skin/classic/browser/devtools/dock-side@2x.png (../shared/devtools/images/dock-side@2x.png)
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
* skin/classic/browser/devtools/floating-scrollbars.css (../shared/devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (../shared/devtools/floating-scrollbars-light.css)
* skin/classic/browser/devtools/inspector.css (../shared/devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)

View File

@ -1,10 +0,0 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
@import url("floating-scrollbars.css");
scrollbar thumb {
background-color: rgba(170,170,170,0.2) !important;
}

View File

@ -1,35 +0,0 @@
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
scrollbar {
-moz-appearance: none;
position: relative;
background-color: transparent;
background-image: none;
border: 0px solid transparent;
z-index: 2147483647;
padding: 2px;
}
/* Scrollbar code will reset the margin to the correct side depending on
where layout actually puts the scrollbar */
scrollbar[orient="vertical"] {
margin-left: -8px;
min-width: 8px;
max-width: 8px;
}
scrollbar[orient="horizontal"] {
margin-top: -8px;
min-height: 8px;
max-height: 8px;
}
slider {
-moz-appearance: none !important;
}
thumb {
-moz-appearance: none !important;
background-color: rgba(0,0,0,0.2);
border-radius: 3px;
}

View File

@ -1,6 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../shared.inc
%include ../../shared/devtools/netmonitor.inc.css

View File

@ -1,6 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../shared.inc
%include ../../shared/devtools/webconsole.inc.css

View File

@ -1,6 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../shared.inc
%include ../../shared/devtools/widgets.inc.css

View File

@ -401,7 +401,7 @@ browser.jar:
skin/classic/browser/devtools/newtab@2x.png (../shared/devtools/images/newtab@2x.png)
skin/classic/browser/devtools/newtab-inverted.png (../shared/devtools/images/newtab-inverted.png)
skin/classic/browser/devtools/newtab-inverted@2x.png (../shared/devtools/images/newtab-inverted@2x.png)
* skin/classic/browser/devtools/widgets.css (devtools/widgets.css)
* skin/classic/browser/devtools/widgets.css (../shared/devtools/widgets.css)
skin/classic/browser/devtools/power.svg (../shared/devtools/images/power.svg)
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
@ -439,8 +439,8 @@ browser.jar:
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
* skin/classic/browser/devtools/webconsole.css (../shared/devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (../shared/devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.svg (../shared/devtools/images/webconsole.svg)
skin/classic/browser/devtools/breadcrumbs-divider@2x.png (../shared/devtools/images/breadcrumbs-divider@2x.png)
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (../shared/devtools/images/breadcrumbs-scrollbutton.png)
@ -449,7 +449,7 @@ browser.jar:
* skin/classic/browser/devtools/canvasdebugger.css (../shared/devtools/canvasdebugger.css)
skin/classic/browser/devtools/debugger.css (../shared/devtools/debugger.css)
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/netmonitor.css (../shared/devtools/netmonitor.css)
skin/classic/browser/devtools/performance.css (../shared/devtools/performance.css)
skin/classic/browser/devtools/promisedebugger.css (../shared/devtools/promisedebugger.css)
skin/classic/browser/devtools/timeline-filter.svg (../shared/devtools/images/timeline-filter.svg)
@ -498,8 +498,8 @@ browser.jar:
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
* skin/classic/browser/devtools/floating-scrollbars.css (../shared/devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (../shared/devtools/floating-scrollbars-light.css)
skin/classic/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsivemode/responsive-se-resizer.png)
skin/classic/browser/devtools/responsive-se-resizer@2x.png (../shared/devtools/images/responsivemode/responsive-se-resizer@2x.png)
skin/classic/browser/devtools/responsive-vertical-resizer.png (../shared/devtools/images/responsivemode/responsive-vertical-resizer.png)

View File

@ -7,6 +7,9 @@ scrollbar {
background-image: none;
z-index: 2147483647;
padding: 2px;
%ifdef XP_MACOSX
border: 0px solid transparent;
%endif
}
/* Scrollbar code will reset the margin to the correct side depending on
@ -23,13 +26,24 @@ scrollbar[orient="horizontal"] {
max-height: 10px;
}
%ifdef XP_MACOSX
slider {
-moz-appearance: none !important;
}
thumb {
-moz-appearance: none !important;
background-color: rgba(0,0,0,0.2);
border-radius: 3px;
}
%else
scrollbar thumb {
-moz-appearance: none !important;
border-width: 0px !important;
background-color: rgba(170,170,170,0.2) !important;
border-radius: 3px !important;
}
scrollbar scrollbarbutton, scrollbar gripper {
display: none;
}
%endif

View File

@ -827,3 +827,57 @@ box.requests-menu-status[code^="5"] {
right border and box-shadow of "Size" column should be hidden. */
}
}
/* Platform overrides (copied in from the old platform specific files) */
%ifdef XP_WIN
.requests-menu-header-button > .button-box {
padding: 0;
}
.requests-menu-timings-division {
padding-top: 1px;
font-size: 90%;
}
.requests-menu-footer-button,
.requests-menu-footer-label {
padding-top: 0px;
padding-bottom: 0px;
}
/* Responsive sidebar */
@media (max-width: 700px) {
.requests-menu-footer-button,
.requests-menu-footer-label {
padding-top: 0px;
padding-bottom: 0px;
}
}
%elifdef XP_LINUX
#headers-summary-resend {
padding: 4px;
}
#toggle-raw-headers {
padding: 4px;
}
.requests-menu-status-and-method {
width: 9em;
}
.requests-menu-security-and-domain {
width: 16vw;
}
.requests-menu-size {
width: 6em;
}
/* Responsive sidebar */
@media (max-width: 700px) {
.requests-menu-header-button {
font-size: 85%;
}
}
%endif

View File

@ -595,3 +595,14 @@ a {
margin-top: 5px;
}
}
%ifdef XP_WIN
/*
* This hardcoded width likely due to a toolkit Windows specific bug.
* See http://hg.mozilla.org/mozilla-central/annotate/f38d6df93cad/toolkit/themes/winstripe/global/textbox-aero.css#l7
*/
.hud-filter-box {
width: 200px;
}
%endif

View File

@ -220,6 +220,12 @@
padding-bottom: 0;
}
%ifdef XP_WIN
.breadcrumbs-widget-item:-moz-focusring > .button-box {
border-width: 0;
}
%endif
.breadcrumbs-widget-item:not([checked]) {
background: -moz-element(#breadcrumb-separator-normal) no-repeat center left;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -1235,15 +1235,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
margin-top: -1px;
}
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
#urlbar,
.searchbar-textbox {
border-radius: 2px;
}
}
@media (-moz-windows-default-theme) {
#urlbar,
.searchbar-textbox {

View File

@ -1,10 +0,0 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
@import url("floating-scrollbars.css");
scrollbar thumb {
background-color: rgba(170,170,170,0.2) !important;
}

View File

@ -1,35 +0,0 @@
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
scrollbar {
-moz-appearance: none !important;
position: relative;
background-color: transparent;
background-image: none;
z-index: 2147483647;
padding: 2px;
}
/* Scrollbar code will reset the margin to the correct side depending on
where layout actually puts the scrollbar */
scrollbar[orient="vertical"] {
margin-left: -10px;
min-width: 10px;
max-width: 10px;
}
scrollbar[orient="horizontal"] {
margin-top: -10px;
min-height: 10px;
max-height: 10px;
}
scrollbar thumb {
-moz-appearance: none !important;
border-width: 0px !important;
background-color: rgba(170,170,170,0.2) !important;
border-radius: 3px !important;
}
scrollbar scrollbarbutton, scrollbar gripper {
display: none;
}

View File

@ -1,29 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/netmonitor.inc.css
.requests-menu-header-button > .button-box {
padding: 0;
}
.requests-menu-timings-division {
padding-top: 1px;
font-size: 90%;
}
.requests-menu-footer-button,
.requests-menu-footer-label {
padding-top: 0px;
padding-bottom: 0px;
}
/* Responsive sidebar */
@media (max-width: 700px) {
.requests-menu-footer-button,
.requests-menu-footer-label {
padding-top: 0px;
padding-bottom: 0px;
}
}

View File

@ -1,14 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/webconsole.inc.css
/*
* This hardcoded width likely due to a toolkit Windows specific bug.
* See http://hg.mozilla.org/mozilla-central/annotate/f38d6df93cad/toolkit/themes/winstripe/global/textbox-aero.css#l7
*/
.hud-filter-box {
width: 200px;
}

View File

@ -1,100 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
body {
font-family: sans-serif;
font-size: 11px;
background: #EEE;
color: #000;
}
#header {
padding: 5px;
overflow-x: auto;
display: block;
}
h1 {
font-size: 13px;
line-height: 15px;
padding: 3px 10px;
vertical-align: bottom;
margin: 0px;
background: linear-gradient(#BBB, #999);
border-radius: 2px;
text-shadow: #FFF 0px 1px 0px;
}
h1 .info {
font-size: 11px;
line-height: 15px;
vertical-align: bottom;
float: right;
color: #333;
padding-right: 3px;
}
.property-table {
padding: 2px 5px;
background: linear-gradient(#FFF, #F8F8F8);
color: #333;
width: 100%;
max-height: 330px;
overflow: auto;
display: block;
}
.property-table-header {
font-size: 11px;
font-weight: bold;
padding-right: 4px;
color: #000;
white-space: nowrap;
text-align: end;
vertical-align: top;
width: 10%;
}
.property-table-value {
padding-right: 5px;
font-size: 11px;
word-wrap: break-word;
width: 90%;
}
div.group {
margin-top: 10px;
}
div.group,
#header {
background: #FFF;
border-color: #E1E1E1;
border-style: solid;
border-width: 1px;
box-shadow: 0 1px 1.5px rgba(0, 0, 0, 0.2);
border-radius: 4px 4px 4px 4px;
}
img#responseImageNode {
box-shadow: rgba(0,0,0,0.2) 0px 3px 3.5px;
max-width: 100%;
}
#responseImageNodeDiv {
padding: 5px;
}
#responseBodyFetchLink, #requestBodyFetchLink {
padding: 5px;
margin: 0;
cursor: pointer;
font-weight: bold;
font-size: 1.1em;
text-decoration: underline;
}
.longStringEllipsis {
margin-left: 0.6em;
}

View File

@ -1,9 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/widgets.inc.css
.breadcrumbs-widget-item:-moz-focusring > .button-box {
border-width: 0;
}

View File

@ -425,7 +425,7 @@ browser.jar:
skin/classic/browser/devtools/newtab@2x.png (../shared/devtools/images/newtab@2x.png)
skin/classic/browser/devtools/newtab-inverted.png (../shared/devtools/images/newtab-inverted.png)
skin/classic/browser/devtools/newtab-inverted@2x.png (../shared/devtools/images/newtab-inverted@2x.png)
* skin/classic/browser/devtools/widgets.css (devtools/widgets.css)
* skin/classic/browser/devtools/widgets.css (../shared/devtools/widgets.css)
skin/classic/browser/devtools/power.svg (../shared/devtools/images/power.svg)
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
@ -463,8 +463,8 @@ browser.jar:
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
* skin/classic/browser/devtools/webconsole.css (../shared/devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (../shared/devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.svg (../shared/devtools/images/webconsole.svg)
skin/classic/browser/devtools/breadcrumbs-divider@2x.png (../shared/devtools/images/breadcrumbs-divider@2x.png)
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (../shared/devtools/images/breadcrumbs-scrollbutton.png)
@ -473,7 +473,7 @@ browser.jar:
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
* skin/classic/browser/devtools/canvasdebugger.css (../shared/devtools/canvasdebugger.css)
skin/classic/browser/devtools/debugger.css (../shared/devtools/debugger.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/netmonitor.css (../shared/devtools/netmonitor.css)
skin/classic/browser/devtools/performance.css (../shared/devtools/performance.css)
skin/classic/browser/devtools/promisedebugger.css (../shared/devtools/promisedebugger.css)
skin/classic/browser/devtools/timeline-filter.svg (../shared/devtools/images/timeline-filter.svg)
@ -540,8 +540,8 @@ browser.jar:
skin/classic/browser/devtools/dock-bottom-minimize@2x.png (../shared/devtools/images/dock-bottom-minimize@2x.png)
skin/classic/browser/devtools/dock-bottom-maximize@2x.png (../shared/devtools/images/dock-bottom-maximize@2x.png)
skin/classic/browser/devtools/dock-side@2x.png (../shared/devtools/images/dock-side@2x.png)
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
* skin/classic/browser/devtools/floating-scrollbars.css (../shared/devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (../shared/devtools/floating-scrollbars-light.css)
* skin/classic/browser/devtools/inspector.css (../shared/devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)

View File

@ -8,12 +8,8 @@ package org.mozilla.gecko.widget;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@ -22,10 +18,10 @@ import android.widget.LinearLayout;
public class RoundedCornerLayout extends LinearLayout {
private static final String LOGTAG = "Gecko" + RoundedCornerLayout.class.getSimpleName();
private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;
private Path path;
public RoundedCornerLayout(Context context) {
super(context);
init(context);
@ -42,52 +38,28 @@ public class RoundedCornerLayout extends LinearLayout {
}
private void init(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.doorhanger_rounded_corner_radius), metrics);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setWillNotDraw(false);
}
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
maskBitmap = createMask(r, b);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
final RectF r = new RectF(0, 0, w, h);
path = new Path();
path.addRoundRect(r, cornerRadius, cornerRadius, Path.Direction.CW);
path.close();
}
@Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);
super.draw(offscreenCanvas);
offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
canvas.save();
canvas.clipPath(path);
super.draw(canvas);
canvas.restore();
}
private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, width, height, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
return mask;
}
}
}

View File

@ -6695,6 +6695,26 @@
"kind": "boolean",
"description": "How many times has the DevTools WebIDE been opened?"
},
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN": {
"expires_in_version": "never",
"kind": "boolean",
"description": "How many times has the DevTools WebIDE project editor been opened?"
},
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_BOOLEAN": {
"expires_in_version": "never",
"kind": "boolean",
"description": "How many times has a file been saved in the DevTools WebIDE project editor?"
},
"DEVTOOLS_WEBIDE_NEW_PROJECT_BOOLEAN": {
"expires_in_version": "never",
"kind": "boolean",
"description": "How many times has a new project been created in the DevTools WebIDE?"
},
"DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN": {
"expires_in_version": "never",
"kind": "boolean",
"description": "How many times has a project been imported into the DevTools WebIDE?"
},
"DEVTOOLS_CUSTOM_OPENED_BOOLEAN": {
"expires_in_version": "never",
"kind": "boolean",
@ -6840,6 +6860,26 @@
"kind": "flag",
"description": "How many users have opened the DevTools WebIDE?"
},
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG": {
"expires_in_version": "never",
"kind": "flag",
"description": "How many users have opened the DevTools WebIDE project editor?"
},
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG": {
"expires_in_version": "never",
"kind": "flag",
"description": "How many users have saved a file in the DevTools WebIDE project editor?"
},
"DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG": {
"expires_in_version": "never",
"kind": "flag",
"description": "How many users have created a new project in the DevTools WebIDE?"
},
"DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG": {
"expires_in_version": "never",
"kind": "flag",
"description": "How many users have imported a project into the DevTools WebIDE?"
},
"DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG": {
"expires_in_version": "never",
"kind": "flag",
@ -7020,6 +7060,13 @@
"n_buckets": 100,
"description": "How long has WebIDE been active (seconds)"
},
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000000",
"n_buckets": 100,
"description": "How long has WebIDE's project editor been active (seconds)"
},
"DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS": {
"expires_in_version": "never",
"kind": "exponential",

View File

@ -184,6 +184,11 @@ let TelemetryReportingPolicyImpl = {
* @return {Object} A date object or null on errors.
*/
get dataSubmissionPolicyNotifiedDate() {
if (!Preferences.has(PREF_ACCEPTED_POLICY_DATE)) {
this._log.info("get dataSubmissionPolicyNotifiedDate - No date stored yet.");
return null;
}
let prefString = Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0);
let valueInteger = parseInt(prefString, 10);

View File

@ -1257,12 +1257,14 @@ let TelemetryStorageImpl = {
ping = yield this.loadPingFile(info.path, false);
} catch(e) {
// If we failed to load the ping, check what happened and update the histogram.
// Then propagate the rejection.
if (e instanceof PingReadError) {
Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_READ").add();
} else if (e instanceof PingParseError) {
Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").add();
}
// Remove the ping from the cache, so we don't try to load it again.
this._pendingPings.delete(id);
// Then propagate the rejection.
throw e;
};
@ -1442,8 +1444,9 @@ let TelemetryStorageImpl = {
try {
array = yield OS.File.read(aFilePath, options);
} catch(e) {
this._log.trace("loadPingfile - unreadable ping " + aFilePath, e);
throw new PingReadError(e.message);
};
}
let decoder = new TextDecoder();
let string = decoder.decode(array);
@ -1455,6 +1458,10 @@ let TelemetryStorageImpl = {
ping.payload = JSON.parse(ping.payload);
}
} catch (e) {
this._log.trace("loadPingfile - unparseable ping " + aFilePath, e);
yield OS.File.remove(aFilePath).catch((ex) => {
this._log.error("loadPingFile - failed removing unparseable ping file", ex);
});
throw new PingParseError(e.message);
}

View File

@ -316,6 +316,9 @@ add_task(function* test_corrupted_pending_pings() {
h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").snapshot();
Assert.equal(h.sum, 1, "Telemetry must report a pending ping parse failure");
let exists = yield OS.File.exists(getSavePathForPingId(pendingPingId));
Assert.ok(!exists, "The unparseable ping should have been removed");
yield clearPendingPings();
});

View File

@ -11,6 +11,7 @@ support-files =
[test_basics.html]
[test_bug819670_getter_throws.html]
[test_cached_messages.html]
[test_commands_other.html]
[test_commands_registration.html]
[test_consoleapi.html]
[test_consoleapi_innerID.html]

View File

@ -0,0 +1,83 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the other command helpers</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the querySelector / querySelectorAll helpers</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let gState;
let gWin;
let tests;
function evaluateJS(input) {
return new Promise((resolve) => gState.client.evaluateJS(input, resolve));
}
function startTest() {
info ("Content window opened, attaching console to it");
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
ok (!gWin.document.nodePrincipal.equals(systemPrincipal),
"The test document is not using the system principal");
attachConsole([], state => {
gState = state;
runTests(tests, testEnd);
}, true);
}
tests = [
Task.async(function* keys() {
let response = yield evaluateJS("keys({foo: 'bar'})");
checkObject(response, {
from: gState.actor,
result: {
class: "Array",
preview: {
items: ["foo"]
}
}
});
nextTest();
}),
Task.async(function* values() {
let response = yield evaluateJS("values({foo: 'bar'})");
checkObject(response, {
from: gState.actor,
result: {
class: "Array",
preview: {
items: ["bar"]
}
}
});
nextTest();
}),
];
function testEnd() {
gWin.close();
gWin = null;
closeDebugger(gState, function() {
gState = null;
SimpleTest.finish();
});
}
window.onload = function() {
// Open a content window to test XRay functionality on built in functions.
gWin = window.open("data:text/html,");
info ("Waiting for content window to load");
gWin.onload = startTest;
}
</script>
</body>
</html>

View File

@ -14,16 +14,24 @@
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let gState;
let gWin;
function evaluateJS(input) {
return new Promise((resolve) => gState.client.evaluateJS(input, resolve));
}
function startTest() {
removeEventListener("load", startTest);
info ("Content window opened, attaching console to it");
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
ok (!gWin.document.nodePrincipal.equals(systemPrincipal),
"The test document is not using the system principal");
attachConsole([], state => {
gState = state;
let tests = [
setupWindow,
checkQuerySelector,
checkQuerySelectorAll,
checkQuerySelectorAllNotExist,
checkQuerySelectorAllException
@ -32,6 +40,27 @@ function startTest() {
}, true);
}
let setupWindow = Task.async(function*() {
info ("Shimming window functions for the content privileged tab");
yield evaluateJS("document.querySelector = function() { throw 'should not call qS'; }");
yield evaluateJS("document.querySelectorAll = function() { throw 'should not call qSA'; }");
nextTest();
});
let checkQuerySelector = Task.async(function*() {
info ("$ returns an DOMNode");
let response = yield evaluateJS("$('body')");
basicResultCheck(response, "$('body')", {
type: "object",
class: "HTMLBodyElement",
preview: {
kind: "DOMNode",
nodeName: "body"
}
});
nextTest();
});
let checkQuerySelectorAll = Task.async(function*() {
info ("$$ returns an array");
let response = yield evaluateJS("$$('body')");
@ -86,13 +115,20 @@ function basicResultCheck(response, input, output) {
}
function testEnd() {
gWin.close();
gWin = null;
closeDebugger(gState, function() {
gState = null;
SimpleTest.finish();
});
}
addEventListener("load", startTest);
window.onload = function() {
// Open a content window to test XRay functionality on built in functions.
gWin = window.open("data:text/html,");
info ("Waiting for content window to load");
gWin.onload = startTest;
}
</script>
</body>
</html>

View File

@ -43,21 +43,6 @@ const CONSOLE_WORKER_IDS = exports.CONSOLE_WORKER_IDS = [ 'SharedWorker', 'Servi
const MAX_AUTOCOMPLETIONS = exports.MAX_AUTOCOMPLETIONS = 1500;
let WebConsoleUtils = {
/**
* Convenience function to unwrap a wrapped object.
*
* @param aObject the object to unwrap.
* @return aObject unwrapped.
*/
unwrap: function WCU_unwrap(aObject)
{
try {
return XPCNativeWrapper.unwrap(aObject);
}
catch (ex) {
return aObject;
}
},
/**
* Wrap a string in an nsISupportsString object.
@ -1450,6 +1435,9 @@ ConsoleAPIListener.prototype =
return;
}
// Here, wrappedJSObject is not a security wrapper but a property defined
// by the XPCOM component which allows us to unwrap the XPCOM interface and
// access the underlying JSObject.
let apiMessage = aMessage.wrappedJSObject;
if (this.window && CONSOLE_WORKER_IDS.indexOf(apiMessage.innerID) == -1) {
let msgWindow = Services.wm.getCurrentInnerWindowWithId(apiMessage.innerID);
@ -1641,10 +1629,15 @@ WebConsoleCommands._registerOriginal("$", function JSTH_$(aOwner, aSelector)
*/
WebConsoleCommands._registerOriginal("$$", function JSTH_$$(aOwner, aSelector)
{
let results = aOwner.window.document.querySelectorAll(aSelector);
let nodes = aOwner.window.wrappedJSObject.Array.from(results);
let nodes = aOwner.window.document.querySelectorAll(aSelector);
return nodes;
// Calling aOwner.window.Array.from() doesn't work without accessing the
// wrappedJSObject, so just loop through the results instead.
let result = new aOwner.window.Array();
for (let i = 0; i < nodes.length; i++) {
result.push(nodes[i]);
}
return result;
});
/**
@ -1671,8 +1664,11 @@ WebConsoleCommands._registerOriginal("$_", {
*/
WebConsoleCommands._registerOriginal("$x", function JSTH_$x(aOwner, aXPath, aContext)
{
let nodes = new aOwner.window.wrappedJSObject.Array();
let doc = aOwner.window.document;
let nodes = new aOwner.window.Array();
// Not waiving Xrays, since we want the original Document.evaluate function,
// instead of anything that's been redefined.
let doc = aOwner.window.document;
aContext = aContext || doc;
let results = doc.evaluate(aXPath, aContext, null,
@ -1726,7 +1722,8 @@ WebConsoleCommands._registerOriginal("clearHistory", function JSTH_clearHistory(
*/
WebConsoleCommands._registerOriginal("keys", function JSTH_keys(aOwner, aObject)
{
return aOwner.window.wrappedJSObject.Object.keys(WebConsoleUtils.unwrap(aObject));
// Need to waive Xrays so we can iterate functions and accessor properties
return Cu.cloneInto(Object.keys(Cu.waiveXrays(aObject)), aOwner.window);
});
/**
@ -1738,14 +1735,16 @@ WebConsoleCommands._registerOriginal("keys", function JSTH_keys(aOwner, aObject)
*/
WebConsoleCommands._registerOriginal("values", function JSTH_values(aOwner, aObject)
{
let arrValues = new aOwner.window.wrappedJSObject.Array();
let obj = WebConsoleUtils.unwrap(aObject);
let values = [];
// Need to waive Xrays so we can iterate functions and accessor properties
let waived = Cu.waiveXrays(aObject);
let names = Object.getOwnPropertyNames(waived);
for (let prop in obj) {
arrValues.push(obj[prop]);
for (let name of names) {
values.push(waived[name]);
}
return arrValues;
return Cu.cloneInto(values, aOwner.window);
});
/**
@ -1833,7 +1832,7 @@ WebConsoleCommands._registerOriginal("pprint", function JSTH_pprint(aOwner, aObj
let output = [];
let obj = WebConsoleUtils.unwrap(aObject);
let obj = aObject;
for (let name in obj) {
let desc = WebConsoleUtils.getPropertyDescriptor(obj, name) || {};
if (desc.get || desc.set) {