Merge fx-team to m-c. a=merge
@ -22,6 +22,57 @@ loop.panel = (function(_, mozL10n) {
|
||||
*/
|
||||
var router;
|
||||
|
||||
var TabView = React.createClass({displayName: 'TabView',
|
||||
getInitialState: function() {
|
||||
return {
|
||||
selectedTab: "call"
|
||||
};
|
||||
},
|
||||
|
||||
handleSelectTab: function(event) {
|
||||
var tabName = event.target.dataset.tabName;
|
||||
this.setState({selectedTab: tabName});
|
||||
|
||||
if (this.props.onSelect) {
|
||||
this.props.onSelect(tabName);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
var tabButtons = [];
|
||||
var tabs = [];
|
||||
React.Children.forEach(this.props.children, function(tab, i) {
|
||||
var tabName = tab.props.name;
|
||||
var isSelected = (this.state.selectedTab == tabName);
|
||||
tabButtons.push(
|
||||
React.DOM.li({className: cx({selected: isSelected}),
|
||||
key: i,
|
||||
'data-tab-name': tabName,
|
||||
onClick: this.handleSelectTab}
|
||||
)
|
||||
);
|
||||
tabs.push(
|
||||
React.DOM.div({key: i, className: cx({tab: true, selected: isSelected})},
|
||||
tab.props.children
|
||||
)
|
||||
);
|
||||
}, this);
|
||||
return (
|
||||
React.DOM.div({className: "tab-view-container"},
|
||||
React.DOM.ul({className: "tab-view"}, tabButtons),
|
||||
tabs
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Tab = React.createClass({displayName: 'Tab',
|
||||
render: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Dropdown menu mixin.
|
||||
* @type {Object}
|
||||
@ -424,10 +475,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
NotificationListView({notifications: this.props.notifications}),
|
||||
CallUrlResult({client: this.props.client,
|
||||
notifications: this.props.notifications,
|
||||
callUrl: this.props.callUrl}),
|
||||
ToSView(null),
|
||||
TabView({onSelect: this.selectTab},
|
||||
Tab({name: "call"},
|
||||
CallUrlResult({client: this.props.client,
|
||||
notifications: this.props.notifications,
|
||||
callUrl: this.props.callUrl}),
|
||||
ToSView(null)
|
||||
),
|
||||
Tab({name: "contacts"},
|
||||
React.DOM.span(null, "contacts")
|
||||
)
|
||||
),
|
||||
React.DOM.div({className: "footer"},
|
||||
AvailabilityDropdown(null),
|
||||
AuthLink(null),
|
||||
|
@ -22,6 +22,57 @@ loop.panel = (function(_, mozL10n) {
|
||||
*/
|
||||
var router;
|
||||
|
||||
var TabView = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
selectedTab: "call"
|
||||
};
|
||||
},
|
||||
|
||||
handleSelectTab: function(event) {
|
||||
var tabName = event.target.dataset.tabName;
|
||||
this.setState({selectedTab: tabName});
|
||||
|
||||
if (this.props.onSelect) {
|
||||
this.props.onSelect(tabName);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
var tabButtons = [];
|
||||
var tabs = [];
|
||||
React.Children.forEach(this.props.children, function(tab, i) {
|
||||
var tabName = tab.props.name;
|
||||
var isSelected = (this.state.selectedTab == tabName);
|
||||
tabButtons.push(
|
||||
<li className={cx({selected: isSelected})}
|
||||
key={i}
|
||||
data-tab-name={tabName}
|
||||
onClick={this.handleSelectTab}>
|
||||
</li>
|
||||
);
|
||||
tabs.push(
|
||||
<div key={i} className={cx({tab: true, selected: isSelected})}>
|
||||
{tab.props.children}
|
||||
</div>
|
||||
);
|
||||
}, this);
|
||||
return (
|
||||
<div className="tab-view-container">
|
||||
<ul className="tab-view">{tabButtons}</ul>
|
||||
{tabs}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Tab = React.createClass({
|
||||
render: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Dropdown menu mixin.
|
||||
* @type {Object}
|
||||
@ -424,10 +475,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
return (
|
||||
<div>
|
||||
<NotificationListView notifications={this.props.notifications} />
|
||||
<CallUrlResult client={this.props.client}
|
||||
notifications={this.props.notifications}
|
||||
callUrl={this.props.callUrl} />
|
||||
<ToSView />
|
||||
<TabView onSelect={this.selectTab}>
|
||||
<Tab name="call">
|
||||
<CallUrlResult client={this.props.client}
|
||||
notifications={this.props.notifications}
|
||||
callUrl={this.props.callUrl} />
|
||||
<ToSView />
|
||||
</Tab>
|
||||
<Tab name="contacts">
|
||||
<span>contacts</span>
|
||||
</Tab>
|
||||
</TabView>
|
||||
<div className="footer">
|
||||
<AvailabilityDropdown />
|
||||
<AuthLink />
|
||||
|
@ -4,12 +4,6 @@
|
||||
|
||||
/* Panel styles */
|
||||
.panel {
|
||||
/* XXX force proper content positioning by adding extra margin space
|
||||
* taken away by reset.css
|
||||
*/
|
||||
margin-top: 7px;
|
||||
margin-bottom: 7px;
|
||||
|
||||
/* hide the extra margin space that the panel resizer now wants to show */
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -18,6 +12,74 @@
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.tab-view,
|
||||
.tab-view > li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.tab-view {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
background: #fafafa;
|
||||
border-top-right-radius: 2px;
|
||||
border-top-left-radius: 2px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tab-view > li {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
padding: 0 10px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 16px;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="call"] {
|
||||
background-image: url("../img/icons-16x16.svg#precall");
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="call"]:hover {
|
||||
background-image: url("../img/icons-16x16.svg#precall-hover");
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="call"].selected {
|
||||
background-image: url("../img/icons-16x16.svg#precall-active");
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="contacts"] {
|
||||
background-image: url("../img/icons-16x16.svg#contacts");
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="contacts"]:hover {
|
||||
background-image: url("../img/icons-16x16.svg#contacts-hover");
|
||||
}
|
||||
|
||||
.tab-view > li[data-tab-name="contacts"].selected {
|
||||
background-image: url("../img/icons-16x16.svg#contacts-active");
|
||||
}
|
||||
|
||||
.tab-view > li:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab.selected {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.share {
|
||||
background: #fbfbfb;
|
||||
}
|
||||
|
117
browser/components/loop/content/shared/img/icons-16x16.svg
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
use {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
use[id$="-hover"] {
|
||||
fill: #444;
|
||||
}
|
||||
|
||||
use[id$="-active"] {
|
||||
fill: #0095dd;
|
||||
}
|
||||
</style>
|
||||
<defs style="display:none">
|
||||
<path id="audio-shape" fill-rule="evenodd" clip-rule="evenodd" d="M11.429,6.857v2.286c0,1.894-1.535,3.429-3.429,3.429
|
||||
c-1.894,0-3.429-1.535-3.429-3.429V6.857H3.429v2.286c0,2.129,1.458,3.913,3.429,4.422v1.293H6.286
|
||||
c-0.746,0-1.379,0.477-1.615,1.143h6.658c-0.236-0.665-0.869-1.143-1.615-1.143H9.143v-1.293c1.971-0.508,3.429-2.292,3.429-4.422
|
||||
V6.857H11.429z M8,12c1.578,0,2.857-1.279,2.857-2.857V2.857C10.857,1.279,9.578,0,8,0C6.422,0,5.143,1.279,5.143,2.857v6.286
|
||||
C5.143,10.721,6.422,12,8,12z"/>
|
||||
<path id="block-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8,0C3.582,0,0,3.582,0,8c0,4.418,3.582,8,8,8
|
||||
c4.418,0,8-3.582,8-8C16,3.582,12.418,0,8,0z M8,2.442c1.073,0,2.075,0.301,2.926,0.821l-7.673,7.673
|
||||
C2.718,10.085,2.408,9.079,2.408,8C2.408,4.931,4.911,2.442,8,2.442z M8,13.557c-1.073,0-2.075-0.301-2.926-0.821l7.673-7.673
|
||||
C13.282,5.915,13.592,6.921,13.592,8C13.592,11.069,11.089,13.557,8,13.557z"/>
|
||||
<path id="contacts-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8,6.526c1.802,0,3.263-1.461,3.263-3.263
|
||||
C11.263,1.461,9.802,0,8,0C6.198,0,4.737,1.461,4.737,3.263C4.737,5.066,6.198,6.526,8,6.526z M14.067,11.421c0,0,0-0.001,0-0.001
|
||||
c0-1.676-1.397-3.119-3.419-3.807L8.001,10.26L5.354,7.613C3.331,8.3,1.933,9.744,1.933,11.42v0.001H1.93
|
||||
c0,1.679,0.328,3.246,0.896,4.579h10.348c0.568-1.333,0.896-2.9,0.896-4.579H14.067z"/>
|
||||
<g id="google-shape">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.001,9.278c-0.9,0.03-1.989,0.454-2.144,1.274
|
||||
c-0.292,1.54,1.284,2.004,2.455,1.932c1.097-0.067,1.737-0.593,1.813-1.26c0.063-0.554-0.184-1.153-0.959-1.644
|
||||
c-0.142-0.09-0.28-0.185-0.413-0.282C8.504,9.291,8.25,9.27,8.001,9.278z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.381,3.409C6.638,3.64,6.32,4.405,6.627,5.61
|
||||
C6.908,6.708,7.78,7.322,8.569,7.104c0.77-0.213,0.987-1.021,0.847-1.873C9.201,3.929,8.261,3.136,7.381,3.409z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8,0C3.582,0,0,3.582,0,8s3.582,8,8,8c4.418,0,8-3.582,8-8
|
||||
S12.418,0,8,0z M10.544,4.471c0.17,0.453,0.194,0.954,0.021,1.416c-0.163,0.436-0.495,0.811-0.982,1.096
|
||||
C9.307,7.146,9.167,7.351,9.151,7.548c-0.045,0.575,0.658,0.993,1.064,1.297c0.889,0.666,1.236,1.758,0.648,2.813
|
||||
c-0.562,1.007-1.901,1.457-3.322,1.462c-1.766-0.008-2.88-0.817-2.938-1.918C4.527,9.779,5.987,9.101,7.307,8.947
|
||||
c0.369-0.043,0.7-0.036,1.01-0.014C7.85,8.625,7.675,7.998,7.914,7.58c0.062-0.109,0.023-0.072-0.095-0.054
|
||||
C6.739,7.689,5.628,6.985,5.367,5.92c-0.132-0.54-0.05-1.105,0.156-1.547C5.97,3.413,6.964,2.88,8.067,2.88
|
||||
c1.147,0,2.209,0,3.334,0.009L10.612,3.4H9.714C10.093,3.665,10.384,4.046,10.544,4.471z"/>
|
||||
</g>
|
||||
<path id="history-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8,16c-4.418,0-8-3.582-8-8c0-4.418,3.582-8,8-8
|
||||
c4.418,0,8,3.582,8,8C16,12.418,12.418,16,8,16z M8,2.442C4.911,2.442,2.408,4.931,2.408,8c0,3.069,2.504,5.557,5.592,5.557
|
||||
S13.592,11.069,13.592,8C13.592,4.931,11.089,2.442,8,2.442z M7.649,9.048C7.206,8.899,6.882,8.493,6.882,8V4.645
|
||||
c0-0.618,0.501-1.119,1.118-1.119c0.618,0,1.119,0.501,1.119,1.119v3.078c1.176,1.22,2.237,3.633,2.237,3.633
|
||||
S8.844,10.252,7.649,9.048z"/>
|
||||
<path id="precall-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8.014,0.003c-4.411,0-7.987,3.576-7.987,7.986
|
||||
c0,1.642,0.496,3.168,1.346,4.437L0,15.997l3.568-1.372c1.271,0.853,2.8,1.352,4.446,1.352c4.411,0,7.986-3.576,7.986-7.987
|
||||
C16,3.579,12.424,0.003,8.014,0.003z"/>
|
||||
<path id="settings-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.77,8c0,0.804,0.262,1.548,0.634,1.678L16,9.887
|
||||
c-0.205,0.874-0.553,1.692-1.011,2.434l-0.567-0.272c-0.355-0.171-1.066,0.17-1.635,0.738c-0.569,0.569-0.909,1.279-0.738,1.635
|
||||
l0.273,0.568c-0.741,0.46-1.566,0.79-2.438,0.998l-0.205-0.584c-0.13-0.372-0.874-0.634-1.678-0.634s-1.548,0.262-1.678,0.634
|
||||
l-0.209,0.596c-0.874-0.205-1.692-0.553-2.434-1.011l0.272-0.567c0.171-0.355-0.17-1.066-0.739-1.635
|
||||
c-0.568-0.568-1.279-0.909-1.635-0.738l-0.568,0.273c-0.46-0.741-0.79-1.566-0.998-2.439l0.584-0.205
|
||||
C0.969,9.547,1.231,8.804,1.231,8c0-0.804-0.262-1.548-0.634-1.678L0,6.112c0.206-0.874,0.565-1.685,1.025-2.427l0.554,0.266
|
||||
c0.355,0.171,1.066-0.17,1.635-0.738c0.569-0.568,0.909-1.28,0.739-1.635L3.686,1.025c0.742-0.46,1.553-0.818,2.427-1.024
|
||||
l0.209,0.596C6.453,0.969,7.197,1.23,8.001,1.23s1.548-0.262,1.678-0.634l0.209-0.596c0.874,0.205,1.692,0.553,2.434,1.011
|
||||
l-0.272,0.567c-0.171,0.355,0.17,1.066,0.738,1.635c0.569,0.568,1.279,0.909,1.635,0.738l0.568-0.273
|
||||
c0.46,0.741,0.79,1.566,0.998,2.438l-0.584,0.205C15.032,6.452,14.77,7.196,14.77,8z M8.001,3.661C5.604,3.661,3.661,5.603,3.661,8
|
||||
c0,2.397,1.943,4.34,4.339,4.34c2.397,0,4.339-1.943,4.339-4.34C12.34,5.603,10.397,3.661,8.001,3.661z"/>
|
||||
<path id="tag-shape" fill-rule="evenodd" clip-rule="evenodd" d="M15.578,7.317L9.659,1.398
|
||||
C9.374,1.033,8.955,0.777,8.471,0.761L2.556,0C1.72-0.027-0.027,1.72,0,2.556l0.761,5.916c0.016,0.484,0.272,0.902,0.637,1.188
|
||||
l5.919,5.919c0.591,0.591,1.584,0.557,2.218-0.076l5.966-5.966C16.135,8.902,16.169,7.909,15.578,7.317z M4.222,4.163
|
||||
c-0.511,0.511-1.339,0.511-1.85,0c-0.511-0.511-0.511-1.339,0-1.85c0.511-0.511,1.339-0.511,1.85,0
|
||||
C4.733,2.823,4.733,3.652,4.222,4.163z"/>
|
||||
<path id="unblock-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8,16c-4.418,0-8-3.582-8-8c0-4.418,3.582-8,8-8
|
||||
c4.418,0,8,3.582,8,8C16,12.418,12.418,16,8,16z M8,2.442C4.911,2.442,2.408,4.931,2.408,8c0,3.069,2.504,5.557,5.592,5.557
|
||||
S13.592,11.069,13.592,8C13.592,4.931,11.089,2.442,8,2.442z"/>
|
||||
<path id="video-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.9,3.129l-3.476,3.073V3.873c0-0.877-0.663-1.587-1.482-1.587
|
||||
H1.482C0.663,2.286,0,2.996,0,3.873v8.254c0,0.877,0.663,1.587,1.482,1.587h8.461c0.818,0,1.482-0.711,1.482-1.587V9.762
|
||||
l3.476,3.073c0.3,0.321,0.714,0.416,1.1,0.331V2.798C15.614,2.713,15.2,2.808,14.9,3.129z"/>
|
||||
</defs>
|
||||
<use id="audio" xlink:href="#audio-shape"/>
|
||||
<use id="audio-hover" xlink:href="#audio-shape"/>
|
||||
<use id="audio-active" xlink:href="#audio-shape"/>
|
||||
<use id="block" xlink:href="#block-shape"/>
|
||||
<use id="block-hover" xlink:href="#block-shape"/>
|
||||
<use id="block-active" xlink:href="#block-shape"/>
|
||||
<use id="contacts" xlink:href="#contacts-shape"/>
|
||||
<use id="contacts-hover" xlink:href="#contacts-shape"/>
|
||||
<use id="contacts-active" xlink:href="#contacts-shape"/>
|
||||
<use id="google" xlink:href="#google-shape"/>
|
||||
<use id="google-hover" xlink:href="#google-shape"/>
|
||||
<use id="google-active" xlink:href="#google-shape"/>
|
||||
<use id="history" xlink:href="#history-shape"/>
|
||||
<use id="history-hover" xlink:href="#history-shape"/>
|
||||
<use id="history-active" xlink:href="#history-shape"/>
|
||||
<use id="precall" xlink:href="#precall-shape"/>
|
||||
<use id="precall-hover" xlink:href="#precall-shape"/>
|
||||
<use id="precall-active" xlink:href="#precall-shape"/>
|
||||
<use id="settings" xlink:href="#settings-shape"/>
|
||||
<use id="settings-hover" xlink:href="#settings-shape"/>
|
||||
<use id="settings-active" xlink:href="#settings-shape"/>
|
||||
<use id="tag" xlink:href="#tag-shape"/>
|
||||
<use id="tag-hover" xlink:href="#tag-shape"/>
|
||||
<use id="tag-active" xlink:href="#tag-shape"/>
|
||||
<use id="unblock" xlink:href="#unblock-shape"/>
|
||||
<use id="unblock-hover" xlink:href="#unblock-shape"/>
|
||||
<use id="unblock-active" xlink:href="#unblock-shape"/>
|
||||
<use id="video" xlink:href="#video-shape"/>
|
||||
<use id="video-hover" xlink:href="#video-shape"/>
|
||||
<use id="video-active" xlink:href="#video-shape"/>
|
||||
</svg>
|
After Width: | Height: | Size: 8.1 KiB |
@ -16,12 +16,6 @@ loop.shared.router = (function() {
|
||||
* @link http://mikeygee.com/blog/backbone.html
|
||||
*/
|
||||
var BaseRouter = Backbone.Router.extend({
|
||||
/**
|
||||
* Active view.
|
||||
* @type {Object}
|
||||
*/
|
||||
_activeView: undefined,
|
||||
|
||||
/**
|
||||
* Notifications collection.
|
||||
* @type {loop.shared.models.NotificationCollection}
|
||||
@ -46,17 +40,6 @@ loop.shared.router = (function() {
|
||||
Backbone.Router.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads and render current active view.
|
||||
*
|
||||
* @param {loop.shared.views.BaseView} view View.
|
||||
*/
|
||||
loadView: function(view) {
|
||||
this.clearActiveView();
|
||||
this._activeView = {type: "backbone", view: view.render().show()};
|
||||
this.updateView(this._activeView.view.$el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders a React component as current active view.
|
||||
*
|
||||
@ -64,34 +47,15 @@ loop.shared.router = (function() {
|
||||
*/
|
||||
loadReactComponent: function(reactComponent) {
|
||||
this.clearActiveView();
|
||||
this._activeView = {
|
||||
type: "react",
|
||||
view: React.renderComponent(reactComponent,
|
||||
document.querySelector("#main"))
|
||||
};
|
||||
React.renderComponent(reactComponent,
|
||||
document.querySelector("#main"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears current active view.
|
||||
*/
|
||||
clearActiveView: function() {
|
||||
if (!this._activeView) {
|
||||
return;
|
||||
}
|
||||
if (this._activeView.type === "react") {
|
||||
React.unmountComponentAtNode(document.querySelector("#main"));
|
||||
} else {
|
||||
this._activeView.view.remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates main div element with provided contents.
|
||||
*
|
||||
* @param {jQuery} $el Element.
|
||||
*/
|
||||
updateView: function($el) {
|
||||
$("#main").html($el);
|
||||
React.unmountComponentAtNode(document.querySelector("#main"));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -14,83 +14,6 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
var sharedModels = loop.shared.models;
|
||||
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* L10n view. Translates resulting view DOM fragment once rendered.
|
||||
*/
|
||||
var L10nView = (function() {
|
||||
var L10nViewImpl = Backbone.View.extend(), // Original View constructor
|
||||
originalExtend = L10nViewImpl.extend; // Original static extend fn
|
||||
|
||||
/**
|
||||
* Patches View extend() method so we can hook and patch any declared render
|
||||
* method.
|
||||
*
|
||||
* @return {Backbone.View} Extended view with patched render() method.
|
||||
*/
|
||||
L10nViewImpl.extend = function() {
|
||||
var ExtendedView = originalExtend.apply(this, arguments),
|
||||
originalRender = ExtendedView.prototype.render;
|
||||
|
||||
/**
|
||||
* Wraps original render() method to translate contents once they're
|
||||
* rendered.
|
||||
*
|
||||
* @return {Backbone.View} Extended view instance.
|
||||
*/
|
||||
ExtendedView.prototype.render = function() {
|
||||
if (originalRender) {
|
||||
originalRender.apply(this, arguments);
|
||||
l10n.translate(this.el);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return ExtendedView;
|
||||
};
|
||||
|
||||
return L10nViewImpl;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Base view.
|
||||
*/
|
||||
var BaseView = L10nView.extend({
|
||||
/**
|
||||
* Hides view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Base render implementation: renders an attached template if available.
|
||||
*
|
||||
* Note: You need to override this if you want to do fancier stuff, eg.
|
||||
* rendering the template using model data.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
render: function() {
|
||||
if (this.template) {
|
||||
this.$el.html(this.template());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Media control button.
|
||||
*
|
||||
@ -704,43 +627,11 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedBrowserView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_browser"></h2>',
|
||||
' <p data-l10n-id="powered_by_webrtc"></p>',
|
||||
' <p data-l10n-id="use_latest_firefox" ',
|
||||
' data-l10n-args=\'{"ff_url": "https://www.mozilla.org/firefox/"}\'>',
|
||||
' </p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedDeviceView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_device"></h2>',
|
||||
' <p data-l10n-id="sorry_device_unsupported"></p>',
|
||||
' <p data-l10n-id="use_firefox_windows_mac_linux"></p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
return {
|
||||
L10nView: L10nView,
|
||||
BaseView: BaseView,
|
||||
ConversationView: ConversationView,
|
||||
ConversationToolbar: ConversationToolbar,
|
||||
FeedbackView: FeedbackView,
|
||||
MediaControlButton: MediaControlButton,
|
||||
NotificationListView: NotificationListView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView
|
||||
NotificationListView: NotificationListView
|
||||
};
|
||||
})(_, window.OT, navigator.mozL10n || document.mozL10n);
|
||||
|
@ -14,83 +14,6 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
var sharedModels = loop.shared.models;
|
||||
var WINDOW_AUTOCLOSE_TIMEOUT_IN_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* L10n view. Translates resulting view DOM fragment once rendered.
|
||||
*/
|
||||
var L10nView = (function() {
|
||||
var L10nViewImpl = Backbone.View.extend(), // Original View constructor
|
||||
originalExtend = L10nViewImpl.extend; // Original static extend fn
|
||||
|
||||
/**
|
||||
* Patches View extend() method so we can hook and patch any declared render
|
||||
* method.
|
||||
*
|
||||
* @return {Backbone.View} Extended view with patched render() method.
|
||||
*/
|
||||
L10nViewImpl.extend = function() {
|
||||
var ExtendedView = originalExtend.apply(this, arguments),
|
||||
originalRender = ExtendedView.prototype.render;
|
||||
|
||||
/**
|
||||
* Wraps original render() method to translate contents once they're
|
||||
* rendered.
|
||||
*
|
||||
* @return {Backbone.View} Extended view instance.
|
||||
*/
|
||||
ExtendedView.prototype.render = function() {
|
||||
if (originalRender) {
|
||||
originalRender.apply(this, arguments);
|
||||
l10n.translate(this.el);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return ExtendedView;
|
||||
};
|
||||
|
||||
return L10nViewImpl;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Base view.
|
||||
*/
|
||||
var BaseView = L10nView.extend({
|
||||
/**
|
||||
* Hides view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Base render implementation: renders an attached template if available.
|
||||
*
|
||||
* Note: You need to override this if you want to do fancier stuff, eg.
|
||||
* rendering the template using model data.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
render: function() {
|
||||
if (this.template) {
|
||||
this.$el.html(this.template());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Media control button.
|
||||
*
|
||||
@ -704,43 +627,11 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedBrowserView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_browser"></h2>',
|
||||
' <p data-l10n-id="powered_by_webrtc"></p>',
|
||||
' <p data-l10n-id="use_latest_firefox" ',
|
||||
' data-l10n-args=\'{"ff_url": "https://www.mozilla.org/firefox/"}\'>',
|
||||
' </p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedDeviceView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_device"></h2>',
|
||||
' <p data-l10n-id="sorry_device_unsupported"></p>',
|
||||
' <p data-l10n-id="use_firefox_windows_mac_linux"></p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
return {
|
||||
L10nView: L10nView,
|
||||
BaseView: BaseView,
|
||||
ConversationView: ConversationView,
|
||||
ConversationToolbar: ConversationToolbar,
|
||||
FeedbackView: FeedbackView,
|
||||
MediaControlButton: MediaControlButton,
|
||||
NotificationListView: NotificationListView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView
|
||||
NotificationListView: NotificationListView
|
||||
};
|
||||
})(_, window.OT, navigator.mozL10n || document.mozL10n);
|
||||
|
@ -44,7 +44,8 @@ browser.jar:
|
||||
content/browser/loop/shared/img/svg/glyph-account-16x16.svg (content/shared/img/svg/glyph-account-16x16.svg)
|
||||
content/browser/loop/shared/img/svg/glyph-signin-16x16.svg (content/shared/img/svg/glyph-signin-16x16.svg)
|
||||
content/browser/loop/shared/img/svg/glyph-signout-16x16.svg (content/shared/img/svg/glyph-signout-16x16.svg)
|
||||
content/browser/loop/shared/img/audio-call-avatar.svg (content/shared/img/audio-call-avatar.svg)
|
||||
content/browser/loop/shared/img/audio-call-avatar.svg (content/shared/img/audio-call-avatar.svg)
|
||||
content/browser/loop/shared/img/icons-16x16.svg (content/shared/img/icons-16x16.svg)
|
||||
|
||||
# Shared scripts
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
|
@ -27,8 +27,47 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
/**
|
||||
* Homepage view.
|
||||
*/
|
||||
var HomeView = sharedViews.BaseView.extend({
|
||||
template: _.template('<p data-l10n-id="welcome"></p>')
|
||||
var HomeView = React.createClass({displayName: 'HomeView',
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.p(null, mozL10n.get("welcome"))
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedBrowserView = React.createClass({displayName: 'UnsupportedBrowserView',
|
||||
render: function() {
|
||||
var useLatestFF = mozL10n.get("use_latest_firefox", {
|
||||
"firefoxBrandNameLink": React.renderComponentToStaticMarkup(
|
||||
React.DOM.a({target: "_blank", href: "https://www.mozilla.org/firefox/"}, "Firefox")
|
||||
)
|
||||
});
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
React.DOM.h2(null, mozL10n.get("incompatible_browser")),
|
||||
React.DOM.p(null, mozL10n.get("powered_by_webrtc")),
|
||||
React.DOM.p({dangerouslySetInnerHTML: {__html: useLatestFF}})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Device view.
|
||||
*/
|
||||
var UnsupportedDeviceView = React.createClass({displayName: 'UnsupportedDeviceView',
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
React.DOM.h2(null, mozL10n.get("incompatible_device")),
|
||||
React.DOM.p(null, mozL10n.get("sorry_device_unsupported")),
|
||||
React.DOM.p(null, mozL10n.get("use_firefox_windows_mac_linux"))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@ -324,7 +363,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
|
||||
// Load default view
|
||||
this.loadView(new HomeView());
|
||||
this.loadReactComponent(HomeView(null));
|
||||
|
||||
this.listenTo(this._conversation, "timeout", this._onTimeout);
|
||||
},
|
||||
@ -470,15 +509,15 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
* Default entry point.
|
||||
*/
|
||||
home: function() {
|
||||
this.loadView(new HomeView());
|
||||
this.loadReactComponent(HomeView(null));
|
||||
},
|
||||
|
||||
unsupportedDevice: function() {
|
||||
this.loadView(new sharedViews.UnsupportedDeviceView());
|
||||
this.loadReactComponent(UnsupportedDeviceView(null));
|
||||
},
|
||||
|
||||
unsupportedBrowser: function() {
|
||||
this.loadView(new sharedViews.UnsupportedBrowserView());
|
||||
this.loadReactComponent(UnsupportedBrowserView(null));
|
||||
},
|
||||
|
||||
expired: function() {
|
||||
@ -579,6 +618,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
CallUrlExpiredView: CallUrlExpiredView,
|
||||
StartConversationView: StartConversationView,
|
||||
HomeView: HomeView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView,
|
||||
init: init,
|
||||
PromoteFirefoxView: PromoteFirefoxView,
|
||||
WebappHelper: WebappHelper,
|
||||
|
@ -27,8 +27,47 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
/**
|
||||
* Homepage view.
|
||||
*/
|
||||
var HomeView = sharedViews.BaseView.extend({
|
||||
template: _.template('<p data-l10n-id="welcome"></p>')
|
||||
var HomeView = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<p>{mozL10n.get("welcome")}</p>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedBrowserView = React.createClass({
|
||||
render: function() {
|
||||
var useLatestFF = mozL10n.get("use_latest_firefox", {
|
||||
"firefoxBrandNameLink": React.renderComponentToStaticMarkup(
|
||||
<a target="_blank" href="https://www.mozilla.org/firefox/">Firefox</a>
|
||||
)
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<h2>{mozL10n.get("incompatible_browser")}</h2>
|
||||
<p>{mozL10n.get("powered_by_webrtc")}</p>
|
||||
<p dangerouslySetInnerHTML={{__html: useLatestFF}}></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Device view.
|
||||
*/
|
||||
var UnsupportedDeviceView = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<h2>{mozL10n.get("incompatible_device")}</h2>
|
||||
<p>{mozL10n.get("sorry_device_unsupported")}</p>
|
||||
<p>{mozL10n.get("use_firefox_windows_mac_linux")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@ -324,7 +363,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
|
||||
// Load default view
|
||||
this.loadView(new HomeView());
|
||||
this.loadReactComponent(<HomeView />);
|
||||
|
||||
this.listenTo(this._conversation, "timeout", this._onTimeout);
|
||||
},
|
||||
@ -470,15 +509,15 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
* Default entry point.
|
||||
*/
|
||||
home: function() {
|
||||
this.loadView(new HomeView());
|
||||
this.loadReactComponent(<HomeView />);
|
||||
},
|
||||
|
||||
unsupportedDevice: function() {
|
||||
this.loadView(new sharedViews.UnsupportedDeviceView());
|
||||
this.loadReactComponent(<UnsupportedDeviceView />);
|
||||
},
|
||||
|
||||
unsupportedBrowser: function() {
|
||||
this.loadView(new sharedViews.UnsupportedBrowserView());
|
||||
this.loadReactComponent(<UnsupportedBrowserView />);
|
||||
},
|
||||
|
||||
expired: function() {
|
||||
@ -579,6 +618,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
CallUrlExpiredView: CallUrlExpiredView,
|
||||
StartConversationView: StartConversationView,
|
||||
HomeView: HomeView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView,
|
||||
init: init,
|
||||
PromoteFirefoxView: PromoteFirefoxView,
|
||||
WebappHelper: WebappHelper,
|
||||
|
@ -23,7 +23,7 @@ call_with_contact_title=Conversation with {{incomingCallIdentity}}
|
||||
welcome=Welcome to the {{clientShortname}} web client.
|
||||
incompatible_browser=Incompatible Browser
|
||||
powered_by_webrtc=The audio and video components of {{clientShortname}} are powered by WebRTC.
|
||||
use_latest_firefox.innerHTML=Please try this link in a WebRTC-enabled browser, such as <a href="{{ff_url}}">{{brandShortname}}</a>.
|
||||
use_latest_firefox=Please try this link in a WebRTC-enabled browser, such as {{firefoxBrandNameLink}}.
|
||||
incompatible_device=Incompatible device
|
||||
sorry_device_unsupported=Sorry, {{clientShortname}} does not currently support your device.
|
||||
use_firefox_windows_mac_linux=Please open this page using the latest {{brandShortname}} on Windows, Android, Mac or Linux.
|
||||
|
@ -126,7 +126,6 @@ describe("loop.conversation", function() {
|
||||
conversation: conversation,
|
||||
notifications: notifications
|
||||
});
|
||||
sandbox.stub(router, "loadView");
|
||||
sandbox.stub(conversation, "incoming");
|
||||
});
|
||||
|
||||
|
@ -78,7 +78,6 @@ describe("loop.panel", function() {
|
||||
addEventListener: sandbox.spy()
|
||||
});
|
||||
|
||||
sandbox.stub(router, "loadView");
|
||||
sandbox.stub(router, "loadReactComponent");
|
||||
});
|
||||
|
||||
|
@ -48,44 +48,6 @@ describe("loop.shared.router", function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("constructed", function() {
|
||||
var router, view, TestRouter;
|
||||
|
||||
beforeEach(function() {
|
||||
TestRouter = loop.shared.router.BaseRouter.extend({});
|
||||
var TestView = loop.shared.views.BaseView.extend({
|
||||
template: _.template("<p>plop</p>")
|
||||
});
|
||||
view = new TestView();
|
||||
router = new TestRouter({notifications: notifications});
|
||||
});
|
||||
|
||||
describe("#loadView", function() {
|
||||
it("should set the active view", function() {
|
||||
router.loadView(view);
|
||||
|
||||
expect(router._activeView).eql({
|
||||
type: "backbone",
|
||||
view: view
|
||||
});
|
||||
});
|
||||
|
||||
it("should load and render the passed view", function() {
|
||||
router.loadView(view);
|
||||
|
||||
expect($("#main p").text()).eql("plop");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#updateView", function() {
|
||||
it("should update the main element with provided contents", function() {
|
||||
router.updateView($("<p>plip</p>"));
|
||||
|
||||
expect($("#main p").text()).eql("plip");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("BaseConversationRouter", function() {
|
||||
|
@ -27,22 +27,6 @@ describe("loop.shared.views", function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("L10nView", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(l10n, "translate");
|
||||
});
|
||||
|
||||
it("should translate generated contents on render()", function() {
|
||||
var TestView = loop.shared.views.L10nView.extend();
|
||||
|
||||
var view = new TestView();
|
||||
view.render();
|
||||
|
||||
sinon.assert.calledOnce(l10n.translate);
|
||||
sinon.assert.calledWithExactly(l10n.translate, view.el);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MediaControlButton", function() {
|
||||
it("should render an enabled local audio button", function() {
|
||||
var comp = TestUtils.renderIntoDocument(sharedViews.MediaControlButton({
|
||||
|
@ -35,6 +35,7 @@ describe("loop.webapp", function() {
|
||||
beforeEach(function() {
|
||||
WebappRouter = loop.webapp.WebappRouter;
|
||||
sandbox.stub(WebappRouter.prototype, "navigate");
|
||||
sandbox.stub(WebappRouter.prototype, "loadReactComponent");
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@ -84,7 +85,6 @@ describe("loop.webapp", function() {
|
||||
conversation: conversation,
|
||||
notifications: notifications
|
||||
});
|
||||
sandbox.stub(router, "loadView");
|
||||
sandbox.stub(router, "navigate");
|
||||
});
|
||||
|
||||
@ -273,14 +273,23 @@ describe("loop.webapp", function() {
|
||||
});
|
||||
|
||||
describe("Routes", function() {
|
||||
beforeEach(function() {
|
||||
// In the router's constructor, it loads the home view, we don't
|
||||
// need to test it here, so reset the stub.
|
||||
router.loadReactComponent.reset();
|
||||
});
|
||||
|
||||
describe("#home", function() {
|
||||
it("should load the HomeView", function() {
|
||||
router.home();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWith(router.loadView,
|
||||
sinon.match.instanceOf(loop.webapp.HomeView));
|
||||
});
|
||||
sinon.assert.calledOnce(router.loadReactComponent);
|
||||
sinon.assert.calledWith(router.loadReactComponent,
|
||||
sinon.match(function(value) {
|
||||
return React.addons.TestUtils.isDescriptorOfType(
|
||||
value, loop.webapp.HomeView);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#expired", function() {
|
||||
@ -352,9 +361,12 @@ describe("loop.webapp", function() {
|
||||
it("should load the UnsupportedDeviceView", function() {
|
||||
router.unsupportedDevice();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWith(router.loadView,
|
||||
sinon.match.instanceOf(sharedViews.UnsupportedDeviceView));
|
||||
sinon.assert.calledOnce(router.loadReactComponent);
|
||||
sinon.assert.calledWith(router.loadReactComponent,
|
||||
sinon.match(function(value) {
|
||||
return React.addons.TestUtils.isDescriptorOfType(
|
||||
value, loop.webapp.UnsupportedDeviceView);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@ -362,9 +374,12 @@ describe("loop.webapp", function() {
|
||||
it("should load the UnsupportedBrowserView", function() {
|
||||
router.unsupportedBrowser();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWith(router.loadView,
|
||||
sinon.match.instanceOf(sharedViews.UnsupportedBrowserView));
|
||||
sinon.assert.calledOnce(router.loadReactComponent);
|
||||
sinon.assert.calledWith(router.loadReactComponent,
|
||||
sinon.match(function(value) {
|
||||
return React.addons.TestUtils.isDescriptorOfType(
|
||||
value, loop.webapp.UnsupportedBrowserView);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -27,14 +27,6 @@ var loopServer;
|
||||
// Ensure loop is always enabled for tests
|
||||
Services.prefs.setBoolPref("loop.enabled", true);
|
||||
|
||||
function hawkGetCallsRequest() {
|
||||
let response = {body: JSON.stringify({calls: [{callId: 4444333221, websocketToken: "0deadbeef0"}]})},
|
||||
// Call the first non-null then(resolve) function attached to the fakePromise.
|
||||
fakePromise = {then: (resolve) => {return resolve ? resolve(response) : fakePromise;},
|
||||
catch: () => {return fakePromise;}};
|
||||
return fakePromise;
|
||||
}
|
||||
|
||||
function setupFakeLoopServer() {
|
||||
loopServer = new HttpServer();
|
||||
loopServer.start(-1);
|
||||
@ -49,6 +41,26 @@ function setupFakeLoopServer() {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
|
||||
function tryAgain() {
|
||||
function tryNow() {
|
||||
tries++;
|
||||
if (aConditionFn()) {
|
||||
deferred.resolve();
|
||||
} else if (tries < aMaxTries) {
|
||||
tryAgain();
|
||||
} else {
|
||||
deferred.reject("Condition timed out: " + aConditionFn.toSource());
|
||||
}
|
||||
}
|
||||
do_timeout(aCheckInterval, tryNow);
|
||||
}
|
||||
let deferred = Promise.defer();
|
||||
let tries = 0;
|
||||
tryAgain();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to fake push registration and notifications for
|
||||
* MozLoopService tests. There is only one object created per test instance, as
|
||||
|
@ -6,8 +6,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Chat",
|
||||
"resource:///modules/Chat.jsm");
|
||||
let openChatOrig = Chat.open;
|
||||
|
||||
const loopServiceModule = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
|
||||
add_test(function test_get_do_not_disturb() {
|
||||
Services.prefs.setBoolPref("loop.do_not_disturb", false);
|
||||
|
||||
@ -39,20 +37,17 @@ add_test(function test_do_not_disturb_disabled_should_open_chat_window() {
|
||||
opened = true;
|
||||
};
|
||||
|
||||
let savedHawkClient = loopServiceModule.gHawkClient;
|
||||
loopServiceModule.gHawkClient = {request: hawkGetCallsRequest};
|
||||
|
||||
mockPushHandler.notify(1);
|
||||
|
||||
do_check_true(opened, "should open a chat window");
|
||||
|
||||
loopServiceModule.gHawkClient = savedHawkClient;
|
||||
|
||||
run_next_test();
|
||||
waitForCondition(function() opened).then(() => {
|
||||
run_next_test();
|
||||
}, () => {
|
||||
do_throw("should have opened a chat window");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_do_not_disturb_enabled_shouldnt_open_chat_window() {
|
||||
add_test(function test_do_not_disturb_enabled_shouldnt_open_chat_window() {
|
||||
MozLoopService.doNotDisturb = true;
|
||||
|
||||
// We registered in the previous test, so no need to do that on this one.
|
||||
@ -63,7 +58,10 @@ add_task(function test_do_not_disturb_enabled_shouldnt_open_chat_window() {
|
||||
|
||||
mockPushHandler.notify(1);
|
||||
|
||||
do_check_false(opened, "should not open a chat window");
|
||||
do_timeout(500, function() {
|
||||
do_check_false(opened, "should not open a chat window");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
function run_test()
|
||||
@ -75,6 +73,12 @@ function run_test()
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
loopServer.registerPathHandler("/calls", (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify({calls: [{callId: 4444333221, websocketToken: "0deadbeef0"}]}));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
|
||||
do_register_cleanup(function() {
|
||||
// Revert original Chat.open implementation
|
||||
|
@ -18,19 +18,19 @@ add_test(function test_openChatWindow_on_notification() {
|
||||
opened = true;
|
||||
};
|
||||
|
||||
let savedHawkClient = loopServiceModule.gHawkClient;
|
||||
loopServiceModule.gHawkClient = {request: hawkGetCallsRequest};
|
||||
|
||||
mockPushHandler.notify(1);
|
||||
|
||||
do_check_true(opened, "should open a chat window");
|
||||
waitForCondition(function() opened).then(() => {
|
||||
do_check_true(opened, "should open a chat window");
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref("loop.seenToS"), "seen",
|
||||
"should set the pref to 'seen'");
|
||||
do_check_eq(Services.prefs.getCharPref("loop.seenToS"), "seen",
|
||||
"should set the pref to 'seen'");
|
||||
|
||||
loopServiceModule.gHawkClient = savedHawkClient;
|
||||
run_next_test();
|
||||
}, () => {
|
||||
do_throw("should have opened a chat window");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
@ -43,6 +43,12 @@ function run_test()
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
loopServer.registerPathHandler("/calls", (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify({calls: [{callId: 4444333221, websocketToken: "0deadbeef0"}]}));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
|
||||
do_register_cleanup(function() {
|
||||
// Revert original Chat.open implementation
|
||||
|
@ -17,6 +17,9 @@
|
||||
var IncomingCallView = loop.conversation.IncomingCallView;
|
||||
|
||||
// 2. Standalone webapp
|
||||
var HomeView = loop.webapp.HomeView;
|
||||
var UnsupportedBrowserView = loop.webapp.UnsupportedBrowserView;
|
||||
var UnsupportedDeviceView = loop.webapp.UnsupportedDeviceView;
|
||||
var CallUrlExpiredView = loop.webapp.CallUrlExpiredView;
|
||||
var StartConversationView = loop.webapp.StartConversationView;
|
||||
|
||||
@ -314,6 +317,31 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "HomeView"},
|
||||
Example({summary: "Standalone Home View"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
HomeView(null)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
Section({name: "UnsupportedBrowserView"},
|
||||
Example({summary: "Standalone Unsupported Browser"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
UnsupportedBrowserView(null)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "UnsupportedDeviceView"},
|
||||
Example({summary: "Standalone Unsupported Device"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
UnsupportedDeviceView(null)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
@ -17,6 +17,9 @@
|
||||
var IncomingCallView = loop.conversation.IncomingCallView;
|
||||
|
||||
// 2. Standalone webapp
|
||||
var HomeView = loop.webapp.HomeView;
|
||||
var UnsupportedBrowserView = loop.webapp.UnsupportedBrowserView;
|
||||
var UnsupportedDeviceView = loop.webapp.UnsupportedDeviceView;
|
||||
var CallUrlExpiredView = loop.webapp.CallUrlExpiredView;
|
||||
var StartConversationView = loop.webapp.StartConversationView;
|
||||
|
||||
@ -316,6 +319,31 @@
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="HomeView">
|
||||
<Example summary="Standalone Home View">
|
||||
<div className="standalone">
|
||||
<HomeView />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
|
||||
<Section name="UnsupportedBrowserView">
|
||||
<Example summary="Standalone Unsupported Browser">
|
||||
<div className="standalone">
|
||||
<UnsupportedBrowserView />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="UnsupportedDeviceView">
|
||||
<Example summary="Standalone Unsupported Device">
|
||||
<div className="standalone">
|
||||
<UnsupportedDeviceView />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
</ShowCase>
|
||||
);
|
||||
}
|
||||
|
@ -627,7 +627,7 @@ OnSharedPreferenceChangeListener
|
||||
// This logic will need to be extended when
|
||||
// content language selection (Bug 881510) is implemented.
|
||||
if (!localeSwitchingIsEnabled &&
|
||||
"preferences_locale".equals(pref.getExtras().getString("resource", null))) {
|
||||
"preferences_locale".equals(pref.getExtras().getString("resource"))) {
|
||||
preferences.removePreference(pref);
|
||||
i--;
|
||||
continue;
|
||||
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 425 B After Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 495 B After Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 381 B |
@ -66,6 +66,9 @@ function execute_search_test(test) {
|
||||
}
|
||||
|
||||
function prep_search_test(test) {
|
||||
// Syncrhonously load the search service.
|
||||
Services.search.getVisibleEngines();
|
||||
|
||||
setHandlerFunc(execute_search_test, test);
|
||||
|
||||
let rel = test.rel || "search";
|
||||
|
@ -10,6 +10,7 @@ import java.util.Arrays;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Tabs.TabEvents;
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
|
||||
@ -19,7 +20,6 @@ import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
@ -37,7 +37,12 @@ abstract class BrowserToolbarTabletBase extends BrowserToolbar {
|
||||
protected final LinearLayout actionItemBar;
|
||||
|
||||
protected final BackButton backButton;
|
||||
private final OnClickListener backButtonOnClickListener;
|
||||
private final OnLongClickListener backButtonOnLongClickListener;
|
||||
|
||||
protected final ForwardButton forwardButton;
|
||||
private final OnClickListener forwardButtonOnClickListener;
|
||||
private final OnLongClickListener forwardButtonOnLongClickListener;
|
||||
|
||||
private final Interpolator buttonsInterpolator = new AccelerateInterpolator();
|
||||
|
||||
@ -52,39 +57,57 @@ abstract class BrowserToolbarTabletBase extends BrowserToolbar {
|
||||
setButtonEnabled(backButton, false);
|
||||
forwardButton = (ForwardButton) findViewById(R.id.forward);
|
||||
setButtonEnabled(forwardButton, false);
|
||||
initButtonListeners();
|
||||
|
||||
backButtonOnClickListener = new BackButtonOnClickListener();
|
||||
backButtonOnLongClickListener = new BackButtonOnLongClickListener();
|
||||
forwardButtonOnClickListener = new ForwardButtonOnClickListener();
|
||||
forwardButtonOnLongClickListener = new ForwardButtonOnLongClickListener();
|
||||
setNavigationButtonListeners(true);
|
||||
|
||||
focusOrder.addAll(Arrays.asList(tabsButton, (View) backButton, (View) forwardButton, this));
|
||||
focusOrder.addAll(urlDisplayLayout.getFocusOrder());
|
||||
focusOrder.addAll(Arrays.asList(actionItemBar, menuButton));
|
||||
}
|
||||
|
||||
private void initButtonListeners() {
|
||||
backButton.setOnClickListener(new Button.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Tabs.getInstance().getSelectedTab().doBack();
|
||||
}
|
||||
});
|
||||
backButton.setOnLongClickListener(new Button.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
return Tabs.getInstance().getSelectedTab().showBackHistory();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Enables or disables the click listeners on the back and forward buttons.
|
||||
*
|
||||
* This method is useful to remove and later add the listeners when a navigation button is hit
|
||||
* because calling `browser.go*()` twice in succession can cause the UI buttons to get out of
|
||||
* sync with gecko's browser state (bug 960746).
|
||||
*
|
||||
* @param disabled True if the listeners should be removed, false for them to be added.
|
||||
*/
|
||||
private void setNavigationButtonListeners(final boolean enabled) {
|
||||
if (enabled) {
|
||||
backButton.setOnClickListener(backButtonOnClickListener);
|
||||
backButton.setOnLongClickListener(backButtonOnLongClickListener);
|
||||
|
||||
forwardButton.setOnClickListener(new Button.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Tabs.getInstance().getSelectedTab().doForward();
|
||||
}
|
||||
});
|
||||
forwardButton.setOnLongClickListener(new Button.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
return Tabs.getInstance().getSelectedTab().showForwardHistory();
|
||||
}
|
||||
});
|
||||
forwardButton.setOnClickListener(forwardButtonOnClickListener);
|
||||
forwardButton.setOnLongClickListener(forwardButtonOnLongClickListener);
|
||||
} else {
|
||||
backButton.setOnClickListener(null);
|
||||
backButton.setOnLongClickListener(null);
|
||||
|
||||
forwardButton.setOnClickListener(null);
|
||||
forwardButton.setOnLongClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(final Tab tab, final Tabs.TabEvents msg, final Object data) {
|
||||
// STOP appears to be the first page load event where async nav issues are prevented,
|
||||
// SELECTED is for switching tabs, and LOAD_ERROR is called when a JavaScript exception
|
||||
// is thrown while loading a URI, which can prevent STOP from ever being called.
|
||||
//
|
||||
// See `setNavigationButtonListeners` javadoc for more information.
|
||||
if (msg == TabEvents.STOP ||
|
||||
msg == TabEvents.SELECTED ||
|
||||
msg == TabEvents.LOAD_ERROR) {
|
||||
setNavigationButtonListeners(true);
|
||||
}
|
||||
|
||||
super.onTabChanged(tab, msg, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -164,4 +187,36 @@ abstract class BrowserToolbarTabletBase extends BrowserToolbar {
|
||||
|
||||
button.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private class BackButtonOnClickListener implements OnClickListener {
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setNavigationButtonListeners(false);
|
||||
Tabs.getInstance().getSelectedTab().doBack();
|
||||
}
|
||||
}
|
||||
|
||||
private class BackButtonOnLongClickListener implements OnLongClickListener {
|
||||
@Override
|
||||
public boolean onLongClick(final View view) {
|
||||
setNavigationButtonListeners(false);
|
||||
return Tabs.getInstance().getSelectedTab().showBackHistory();
|
||||
}
|
||||
}
|
||||
|
||||
private class ForwardButtonOnClickListener implements OnClickListener {
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setNavigationButtonListeners(false);
|
||||
Tabs.getInstance().getSelectedTab().doForward();
|
||||
}
|
||||
}
|
||||
|
||||
private class ForwardButtonOnLongClickListener implements OnLongClickListener {
|
||||
@Override
|
||||
public boolean onLongClick(final View view) {
|
||||
setNavigationButtonListeners(false);
|
||||
return Tabs.getInstance().getSelectedTab().showForwardHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3936,50 +3936,52 @@ Tab.prototype = {
|
||||
// Check that type matches opensearch.
|
||||
let isOpenSearch = (type == "application/opensearchdescription+xml");
|
||||
if (isOpenSearch && target.title && /^(?:https?|ftp):/i.test(target.href)) {
|
||||
let visibleEngines = Services.search.getVisibleEngines();
|
||||
// NOTE: Engines are currently identified by name, but this can be changed
|
||||
// when Engines are identified by URL (see bug 335102).
|
||||
if (visibleEngines.some(function(e) {
|
||||
return e.name == target.title;
|
||||
})) {
|
||||
// This engine is already present, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.browser.engines) {
|
||||
// This engine has already been handled, do nothing.
|
||||
if (this.browser.engines.some(function(e) {
|
||||
return e.url == target.href;
|
||||
Services.search.init(() => {
|
||||
let visibleEngines = Services.search.getVisibleEngines();
|
||||
// NOTE: Engines are currently identified by name, but this can be changed
|
||||
// when Engines are identified by URL (see bug 335102).
|
||||
if (visibleEngines.some(function(e) {
|
||||
return e.name == target.title;
|
||||
})) {
|
||||
return;
|
||||
// This engine is already present, do nothing.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.browser.engines = [];
|
||||
}
|
||||
|
||||
// Get favicon.
|
||||
let iconURL = target.ownerDocument.documentURIObject.prePath + "/favicon.ico";
|
||||
if (this.browser.engines) {
|
||||
// This engine has already been handled, do nothing.
|
||||
if (this.browser.engines.some(function(e) {
|
||||
return e.url == target.href;
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.browser.engines = [];
|
||||
}
|
||||
|
||||
let newEngine = {
|
||||
title: target.title,
|
||||
url: target.href,
|
||||
iconURL: iconURL
|
||||
};
|
||||
// Get favicon.
|
||||
let iconURL = target.ownerDocument.documentURIObject.prePath + "/favicon.ico";
|
||||
|
||||
this.browser.engines.push(newEngine);
|
||||
let newEngine = {
|
||||
title: target.title,
|
||||
url: target.href,
|
||||
iconURL: iconURL
|
||||
};
|
||||
|
||||
// Don't send a message to display engines if we've already handled an engine.
|
||||
if (this.browser.engines.length > 1)
|
||||
return;
|
||||
this.browser.engines.push(newEngine);
|
||||
|
||||
// Broadcast message that this tab contains search engines that should be visible.
|
||||
let newEngineMessage = {
|
||||
type: "Link:OpenSearch",
|
||||
tabID: this.id,
|
||||
visible: true
|
||||
};
|
||||
// Don't send a message to display engines if we've already handled an engine.
|
||||
if (this.browser.engines.length > 1)
|
||||
return;
|
||||
|
||||
Messaging.sendRequest(newEngineMessage);
|
||||
// Broadcast message that this tab contains search engines that should be visible.
|
||||
let newEngineMessage = {
|
||||
type: "Link:OpenSearch",
|
||||
tabID: this.id,
|
||||
visible: true
|
||||
};
|
||||
|
||||
Messaging.sendRequest(newEngineMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1583,8 +1583,6 @@ nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
|
||||
_retval = finalCompleteValue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FindInReadable(inputValue, _retval, nsCaseInsensitiveStringComparator()),
|
||||
"Return value must include input value.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -730,9 +730,40 @@ Search.prototype = {
|
||||
let match = yield PlacesSearchAutocompleteProvider.findMatchByToken(
|
||||
this._searchString);
|
||||
if (match) {
|
||||
// The match doesn't contain a 'scheme://www.' prefix, but since we have
|
||||
// stripped it from the search string, here we could still be matching
|
||||
// 'https://www.g' to 'google.com'.
|
||||
// There are a couple cases where we don't want to match though:
|
||||
//
|
||||
// * If the protocol differs we should not match. For example if the user
|
||||
// searched https we should not return http.
|
||||
try {
|
||||
let prefixURI = NetUtil.newURI(this._strippedPrefix);
|
||||
let finalURI = NetUtil.newURI(match.url);
|
||||
if (prefixURI.scheme != finalURI.scheme)
|
||||
return;
|
||||
} catch (e) {}
|
||||
|
||||
// * If the user typed "www." but the final url doesn't have it, we
|
||||
// should not match as well, the two urls may point to different pages.
|
||||
if (this._strippedPrefix.endsWith("www.") &&
|
||||
!stripHttpAndTrim(match.url).startsWith("www."))
|
||||
return;
|
||||
|
||||
let value = this._strippedPrefix + match.token;
|
||||
|
||||
// In any case, we should never arrive here with a value that doesn't
|
||||
// match the search string. If this happens there is some case we
|
||||
// are not handling properly yet.
|
||||
if (!value.startsWith(this._originalSearchString)) {
|
||||
Components.utils.reportError(`Trying to inline complete in-the-middle
|
||||
${this._originalSearchString} to ${value}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._result.setDefaultIndex(0);
|
||||
this._addFrecencyMatch({
|
||||
value: match.token,
|
||||
value: value,
|
||||
comment: match.engineName,
|
||||
icon: match.iconUrl,
|
||||
style: "priority-search",
|
||||
|
@ -81,6 +81,72 @@ add_task(function* test_searchEngine_trailing_space_noautofill() {
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_searchEngine_www_noautofill() {
|
||||
Services.search.addEngineWithDetails("HamSearch", "", "", "",
|
||||
"GET", "http://ham.search/");
|
||||
let engine = Services.search.getEngineByName("HamSearch");
|
||||
engine.addParam("q", "{searchTerms}", null);
|
||||
do_register_cleanup(() => Services.search.removeEngine(engine));
|
||||
|
||||
do_log_info("Should not autoFill search engine if search string contains www. but engine doesn't");
|
||||
yield check_autocomplete({
|
||||
search: "www.ham",
|
||||
autofilled: "www.ham",
|
||||
completed: "www.ham"
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_searchEngine_different_scheme_noautofill() {
|
||||
Services.search.addEngineWithDetails("PieSearch", "", "", "",
|
||||
"GET", "https://pie.search/");
|
||||
let engine = Services.search.getEngineByName("PieSearch");
|
||||
engine.addParam("q", "{searchTerms}", null);
|
||||
do_register_cleanup(() => Services.search.removeEngine(engine));
|
||||
|
||||
do_log_info("Should not autoFill search engine if search string has a different scheme.");
|
||||
yield check_autocomplete({
|
||||
search: "http://pie",
|
||||
autofilled: "http://pie",
|
||||
completed: "http://pie"
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_searchEngine_matching_prefix_autofill() {
|
||||
Services.search.addEngineWithDetails("BeanSearch", "", "", "",
|
||||
"GET", "http://www.bean.search/");
|
||||
let engine = Services.search.getEngineByName("BeanSearch");
|
||||
engine.addParam("q", "{searchTerms}", null);
|
||||
do_register_cleanup(() => Services.search.removeEngine(engine));
|
||||
|
||||
|
||||
do_log_info("Should autoFill search engine if search string has matching prefix.");
|
||||
yield check_autocomplete({
|
||||
search: "http://www.be",
|
||||
autofilled: "http://www.bean.search",
|
||||
completed: "http://www.bean.search"
|
||||
})
|
||||
|
||||
do_log_info("Should autoFill search engine if search string has www prefix.");
|
||||
yield check_autocomplete({
|
||||
search: "www.be",
|
||||
autofilled: "www.bean.search",
|
||||
completed: "http://www.bean.search"
|
||||
});
|
||||
|
||||
do_log_info("Should autoFill search engine if search string has matching scheme.");
|
||||
yield check_autocomplete({
|
||||
search: "http://be",
|
||||
autofilled: "http://bean.search",
|
||||
completed: "http://www.bean.search"
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_prefix_autofill() {
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
|