mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-04 16:15:25 +00:00
Merge m-c to b2g-inbound a=merge
This commit is contained in:
commit
2cc342f7d3
3
.gitignore
vendored
3
.gitignore
vendored
@ -61,3 +61,6 @@ GTAGS
|
||||
GRTAGS
|
||||
GSYMS
|
||||
GPATH
|
||||
|
||||
# Git clone directory for updating web-platform-tests
|
||||
testing/web-platform/sync/
|
||||
|
@ -75,3 +75,6 @@ GPATH
|
||||
# Unit tests for Loop
|
||||
^browser/components/loop/standalone/content/config\.js$
|
||||
^browser/components/loop/standalone/node_modules/
|
||||
|
||||
# Git clone directory for updating web-platform-tests
|
||||
^testing/web-platform/sync/
|
||||
|
25
Makefile.in
25
Makefile.in
@ -315,27 +315,4 @@ config/export:
|
||||
|
||||
endif
|
||||
|
||||
# Interdependencies for parallel export.
|
||||
js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
|
||||
accessible/xpcom/export: xpcom/xpidl/export
|
||||
ifdef ENABLE_CLANG_PLUGIN
|
||||
js/src/export config/host: build/clang-plugin/export
|
||||
endif
|
||||
|
||||
# Interdependencies that moz.build world don't know about yet for compilation.
|
||||
# Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3)
|
||||
toolkit/library/target: widget/gtk/mozgtk/gtk3/target
|
||||
endif
|
||||
ifdef MOZ_LDAP_XPCOM
|
||||
ldap/target: config/external/nss/target mozglue/build/target
|
||||
toolkit/library/target: ldap/target
|
||||
endif
|
||||
ifndef MOZ_FOLD_LIBS
|
||||
ifndef MOZ_NATIVE_SQLITE
|
||||
config/external/nss/target: db/sqlite3/src/target
|
||||
endif
|
||||
endif
|
||||
ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
|
||||
mozglue/build/target: memory/replace/dummy/target
|
||||
endif
|
||||
# There used to be build interdependencies here. They are now in config/recurse.mk
|
||||
|
@ -677,6 +677,13 @@ nsAccessiblePivot::AdjustStartPosition(Accessible* aAccessible,
|
||||
}
|
||||
}
|
||||
|
||||
if (aAccessible == mPosition && mStartOffset != -1 && mEndOffset != -1) {
|
||||
HyperTextAccessible* text = aAccessible->AsHyperText();
|
||||
if (text) {
|
||||
matched = text->GetChildAtOffset(mStartOffset);
|
||||
}
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
|
@ -112,16 +112,6 @@
|
||||
toIndex: 5
|
||||
}]
|
||||
}],
|
||||
// XXX: Bug 980510: doing next after text traversal should
|
||||
// bring us to the next paragraph.
|
||||
[ContentMessages.simpleMoveNext, {
|
||||
speak: 'You\'re a good guy, mon frere. ' +
|
||||
'That means brother in French. ' +
|
||||
'I don\'t know how I know that. ' +
|
||||
'I took four years of Spanish.',
|
||||
speak_checkFunc: 'todo_is' // Bug 980510
|
||||
}],
|
||||
// XXX: extra move op here because of bug 980510.
|
||||
[ContentMessages.simpleMoveNext, {
|
||||
speak: 'You\'re a good guy, mon frere. ' +
|
||||
'That means brother in French. ' +
|
||||
|
1
aclocal.m4
vendored
1
aclocal.m4
vendored
@ -34,6 +34,7 @@ builtin(include, build/autoconf/python-virtualenv.m4)dnl
|
||||
builtin(include, build/autoconf/winsdk.m4)dnl
|
||||
builtin(include, build/autoconf/icu.m4)dnl
|
||||
builtin(include, build/autoconf/ffi.m4)dnl
|
||||
builtin(include, build/autoconf/clang-plugin.m4)dnl
|
||||
|
||||
MOZ_PROG_CHECKMSYS()
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
<head>
|
||||
<title>&loadError.label;</title>
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutneterror/netError.css" type="text/css" media="all" />
|
||||
<link rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
|
||||
<!-- If the location of the favicon is changed here, the FAVICON_ERRORPAGE_URL symbol in
|
||||
toolkit/components/places/src/nsFaviconService.h should be updated. -->
|
||||
<link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/warning-16.png"/>
|
||||
|
@ -109,9 +109,9 @@ function onSubmitStatus(subj, topic, data) {
|
||||
ok(!!remoteID, "serverCrashID should be set");
|
||||
|
||||
// Remove the submitted report file.
|
||||
let file = Services.dirsvc.get("UAppData", Ci.nsILocalFile);
|
||||
file.append("Crash Reports");
|
||||
file.append("submitted");
|
||||
let file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(Services.crashmanager._submittedDumpsDir);
|
||||
file.append(remoteID + ".txt");
|
||||
ok(file.exists(), "Submitted report file should exist");
|
||||
file.remove(false);
|
||||
|
@ -2,6 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const CRASH_URL = "http://example.com/browser/browser/base/content/test/plugins/plugin_crashCommentAndURL.html";
|
||||
@ -85,7 +86,7 @@ function doNextRun() {
|
||||
}
|
||||
}
|
||||
|
||||
function onCrash() {
|
||||
function onCrash(event) {
|
||||
try {
|
||||
let plugin = gBrowser.contentDocument.getElementById("plugin");
|
||||
let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
|
||||
@ -95,7 +96,13 @@ function onCrash() {
|
||||
currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
|
||||
"Submission UI visibility should be correct");
|
||||
if (!currentRun.shouldSubmissionUIBeVisible) {
|
||||
// Done with this run.
|
||||
// Done with this run. We don't submit the crash, so we will have to
|
||||
// remove the dump manually.
|
||||
let propBag = event.detail.QueryInterface(Ci.nsIPropertyBag2);
|
||||
let crashID = propBag.getPropertyAsAString("pluginDumpID");
|
||||
ok(!!crashID, "pluginDumpID should be set");
|
||||
CrashSubmit.delete(crashID);
|
||||
|
||||
doNextRun();
|
||||
return;
|
||||
}
|
||||
@ -116,8 +123,21 @@ function onSubmitStatus(subj, topic, data) {
|
||||
if (data != "success" && data != "failed")
|
||||
return;
|
||||
|
||||
let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag),
|
||||
"extra");
|
||||
let propBag = subj.QueryInterface(Ci.nsIPropertyBag);
|
||||
if (data == "success") {
|
||||
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
|
||||
ok(!!remoteID, "serverCrashID should be set");
|
||||
|
||||
// Remove the submitted report file.
|
||||
let file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(Services.crashmanager._submittedDumpsDir);
|
||||
file.append(remoteID + ".txt");
|
||||
ok(file.exists(), "Submitted report file should exist");
|
||||
file.remove(false);
|
||||
}
|
||||
|
||||
let extra = getPropertyBagValue(propBag, "extra");
|
||||
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
|
||||
|
||||
let val = getPropertyBagValue(extra, "PluginUserComment");
|
||||
|
@ -52,6 +52,7 @@ function CustomizeMode(aWindow) {
|
||||
this.window = aWindow;
|
||||
this.document = aWindow.document;
|
||||
this.browser = aWindow.gBrowser;
|
||||
this.areas = new Set();
|
||||
|
||||
// There are two palettes - there's the palette that can be overlayed with
|
||||
// toolbar items in browser.xul. This is invisible, and never seen by the
|
||||
@ -223,11 +224,16 @@ CustomizeMode.prototype = {
|
||||
customizer.parentNode.selectedPanel = customizer;
|
||||
customizer.hidden = false;
|
||||
|
||||
this._wrapToolbarItemSync(CustomizableUI.AREA_TABSTRIP);
|
||||
|
||||
let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true]):not([collapsed=true])");
|
||||
for (let toolbar of customizableToolbars)
|
||||
toolbar.setAttribute("customizing", true);
|
||||
|
||||
yield this._doTransition(true);
|
||||
|
||||
Services.obs.addObserver(this, "lightweight-theme-window-updated", false);
|
||||
|
||||
|
||||
// Let everybody in this window know that we're about to customize.
|
||||
CustomizableUI.dispatchToolboxEvent("customizationstarting", {}, window);
|
||||
|
||||
@ -254,10 +260,6 @@ CustomizeMode.prototype = {
|
||||
this._skipSourceNodeCheck = Services.prefs.getPrefType(kSkipSourceNodePref) == Ci.nsIPrefBranch.PREF_BOOL &&
|
||||
Services.prefs.getBoolPref(kSkipSourceNodePref);
|
||||
|
||||
let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true]):not([collapsed=true])");
|
||||
for (let toolbar of customizableToolbars)
|
||||
toolbar.setAttribute("customizing", true);
|
||||
|
||||
CustomizableUI.addListener(this);
|
||||
window.PanelUI.endBatchUpdate();
|
||||
this._customizing = true;
|
||||
@ -419,7 +421,7 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
|
||||
// And drop all area references.
|
||||
this.areas = [];
|
||||
this.areas.clear();
|
||||
|
||||
// Let everybody in this window know that we're starting to
|
||||
// exit customization mode.
|
||||
@ -500,15 +502,15 @@ CustomizeMode.prototype = {
|
||||
let deferred = Promise.defer();
|
||||
let deck = this.document.getElementById("content-deck");
|
||||
|
||||
let customizeTransitionEnd = function(aEvent) {
|
||||
let customizeTransitionEnd = (aEvent) => {
|
||||
if (aEvent != "timedout" &&
|
||||
(aEvent.originalTarget != deck || aEvent.propertyName != "margin-left")) {
|
||||
return;
|
||||
}
|
||||
this.window.clearTimeout(catchAllTimeout);
|
||||
// Bug 962677: We let the event loop breathe for before we do the final
|
||||
// stage of the transition to improve perceived performance.
|
||||
this.window.setTimeout(function () {
|
||||
// We request an animation frame to do the final stage of the transition
|
||||
// to improve perceived performance. (bug 962677)
|
||||
this.window.requestAnimationFrame(() => {
|
||||
deck.removeEventListener("transitionend", customizeTransitionEnd);
|
||||
|
||||
if (!aEntering) {
|
||||
@ -521,13 +523,14 @@ CustomizeMode.prototype = {
|
||||
CustomizableUI.dispatchToolboxEvent("customization-transitionend", aEntering, this.window);
|
||||
|
||||
deferred.resolve();
|
||||
}.bind(this), 0);
|
||||
}.bind(this);
|
||||
});
|
||||
};
|
||||
deck.addEventListener("transitionend", customizeTransitionEnd);
|
||||
|
||||
if (gDisableAnimation) {
|
||||
this.document.getElementById("tab-view-deck").setAttribute("fastcustomizeanimation", true);
|
||||
}
|
||||
|
||||
if (aEntering) {
|
||||
this.document.documentElement.setAttribute("customizing", true);
|
||||
this.document.documentElement.setAttribute("customize-entering", true);
|
||||
@ -797,7 +800,7 @@ CustomizeMode.prototype = {
|
||||
dispatchFunction(function() {
|
||||
let wrapper = this.wrapToolbarItem(aNode, aPlace);
|
||||
deferred.resolve(wrapper);
|
||||
}.bind(this))
|
||||
}.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
@ -969,22 +972,47 @@ CustomizeMode.prototype = {
|
||||
return toolbarItem;
|
||||
},
|
||||
|
||||
_wrapToolbarItems: function() {
|
||||
let window = this.window;
|
||||
// Add drag-and-drop event handlers to all of the customizable areas.
|
||||
return Task.spawn(function() {
|
||||
this.areas = [];
|
||||
for (let area of CustomizableUI.areas) {
|
||||
let target = CustomizableUI.getCustomizeTargetForArea(area, window);
|
||||
this._addDragHandlers(target);
|
||||
for (let child of target.children) {
|
||||
if (this.isCustomizableItem(child)) {
|
||||
yield this.deferredWrapToolbarItem(child, CustomizableUI.getPlaceForItem(child));
|
||||
}
|
||||
}
|
||||
this.areas.push(target);
|
||||
_wrapToolbarItem: function*(aArea) {
|
||||
let target = CustomizableUI.getCustomizeTargetForArea(aArea, this.window);
|
||||
if (!target || this.areas.has(target)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._addDragHandlers(target);
|
||||
for (let child of target.children) {
|
||||
if (this.isCustomizableItem(child) && !this.isWrappedToolbarItem(child)) {
|
||||
yield this.deferredWrapToolbarItem(child, CustomizableUI.getPlaceForItem(child)).then(null, ERROR);
|
||||
}
|
||||
}.bind(this)).then(null, ERROR);
|
||||
}
|
||||
this.areas.add(target);
|
||||
return target;
|
||||
},
|
||||
|
||||
_wrapToolbarItemSync: function(aArea) {
|
||||
let target = CustomizableUI.getCustomizeTargetForArea(aArea, this.window);
|
||||
if (!target || this.areas.has(target)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._addDragHandlers(target);
|
||||
try {
|
||||
for (let child of target.children) {
|
||||
if (this.isCustomizableItem(child) && !this.isWrappedToolbarItem(child)) {
|
||||
this.wrapToolbarItem(child, CustomizableUI.getPlaceForItem(child));
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
ERROR(ex, ex.stack);
|
||||
}
|
||||
|
||||
this.areas.add(target);
|
||||
return target;
|
||||
},
|
||||
|
||||
_wrapToolbarItems: function*() {
|
||||
for (let area of CustomizableUI.areas) {
|
||||
yield this._wrapToolbarItem(area);
|
||||
}
|
||||
},
|
||||
|
||||
_addDragHandlers: function(aTarget) {
|
||||
@ -1208,7 +1236,7 @@ CustomizeMode.prototype = {
|
||||
this._wrapItemsInArea(aContainer);
|
||||
this._addDragHandlers(aContainer);
|
||||
DragPositionManager.add(this.window, aArea, aContainer);
|
||||
this.areas.push(aContainer);
|
||||
this.areas.add(aContainer);
|
||||
}
|
||||
},
|
||||
|
||||
@ -1217,8 +1245,7 @@ CustomizeMode.prototype = {
|
||||
this._unwrapItemsInArea(aContainer);
|
||||
this._removeDragHandlers(aContainer);
|
||||
DragPositionManager.remove(this.window, aArea, aContainer);
|
||||
let index = this.areas.indexOf(aContainer);
|
||||
this.areas.splice(index, 1);
|
||||
this.areas.delete(aContainer);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -42,12 +42,12 @@ add_task(function*() {
|
||||
info("Check that removing the area registration from within customize mode works");
|
||||
CustomizableUI.unregisterArea(TOOLBARID);
|
||||
ok(CustomizableUI.inDefaultState, "Now that the toolbar is no longer registered, should be in default state.");
|
||||
ok(!(new Set(gCustomizeMode.areas)).has(toolbar), "Toolbar shouldn't be known to customize mode.");
|
||||
ok(!gCustomizeMode.areas.has(toolbar), "Toolbar shouldn't be known to customize mode.");
|
||||
|
||||
CustomizableUI.registerArea(TOOLBARID, {legacy: true, defaultPlacements: []});
|
||||
CustomizableUI.registerToolbarNode(toolbar, []);
|
||||
ok(!CustomizableUI.inDefaultState, "Now that the toolbar is registered again, should no longer be in default state.");
|
||||
ok((new Set(gCustomizeMode.areas)).has(toolbar), "Toolbar should be known to customize mode again.");
|
||||
ok(gCustomizeMode.areas.has(toolbar), "Toolbar should be known to customize mode again.");
|
||||
|
||||
simulateItemDrag(syncButton, toolbar);
|
||||
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
|
||||
@ -118,7 +118,7 @@ add_task(function*() {
|
||||
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
|
||||
// Closing the other window should not be counted against this window's customize mode:
|
||||
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
|
||||
isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance.");
|
||||
ok(gCustomizeMode.areas.has(toolbar), "Toolbar should still be a customizable area for this customize mode instance.");
|
||||
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
|
@ -627,23 +627,6 @@ let gInitializeTimerFunc = () => {
|
||||
* Public API
|
||||
*/
|
||||
this.MozLoopService = {
|
||||
#ifdef DEBUG
|
||||
// Test-only helpers
|
||||
get internal() {
|
||||
return MozLoopServiceInternal;
|
||||
},
|
||||
|
||||
get gFxAOAuthTokenData() {
|
||||
return gFxAOAuthTokenData;
|
||||
},
|
||||
|
||||
resetFxA: function() {
|
||||
gFxAOAuthClientPromise = null;
|
||||
gFxAOAuthClient = null;
|
||||
gFxAOAuthTokenData = null;
|
||||
},
|
||||
#endif
|
||||
|
||||
_DNSService: gDNSService,
|
||||
|
||||
set initializeTimerFunc(value) {
|
||||
|
@ -11,7 +11,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="loop/shared/css/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="loop/shared/css/conversation.css">
|
||||
</head>
|
||||
<body class="conversation-window" onload="loop.conversation.init();">
|
||||
<body class="fx-embedded" onload="loop.conversation.init();">
|
||||
|
||||
<div id="messages"></div>
|
||||
|
||||
|
@ -27,10 +27,14 @@ loop.conversation = (function(OT, mozL10n) {
|
||||
model: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
getInitialProps: function() {
|
||||
return {showDeclineMenu: false};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {showDeclineMenu: this.props.showDeclineMenu};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
window.addEventListener("click", this.clickHandler);
|
||||
window.addEventListener("blur", this._hideDeclineMenu);
|
||||
|
@ -27,10 +27,14 @@ loop.conversation = (function(OT, mozL10n) {
|
||||
model: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
getInitialProps: function() {
|
||||
return {showDeclineMenu: false};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {showDeclineMenu: this.props.showDeclineMenu};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
window.addEventListener("click", this.clickHandler);
|
||||
window.addEventListener("blur", this._hideDeclineMenu);
|
||||
|
@ -18,19 +18,11 @@ body {
|
||||
background: #fbfbfb;
|
||||
}
|
||||
|
||||
button {
|
||||
/* Resetting default <button> font properties; eg. strangely enough, FF mac
|
||||
wants to use Helvetica/12px whatever we define for parent elements */
|
||||
font-family: "Lucida Grande", sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@ -220,8 +212,9 @@ p {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-group .btn {
|
||||
.btn-chevron-menu-group .btn {
|
||||
flex: 1;
|
||||
border-radius: 2px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
@ -250,8 +243,8 @@ p {
|
||||
|
||||
.alert .close {
|
||||
position: relative;
|
||||
top: -.2em;
|
||||
right: -1em;
|
||||
top: -.1rem;
|
||||
right: -1rem;
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
@ -269,24 +262,25 @@ p {
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1em;
|
||||
line-height: 1rem;
|
||||
color: #000;
|
||||
opacity: .2;
|
||||
opacity: .4;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.close:before {
|
||||
/* \2716 is unicode representation of the close button icon */
|
||||
content: '\2716';
|
||||
}
|
||||
|
||||
.btn.close {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Transitions */
|
||||
.fade-out {
|
||||
transition: opacity 0.5s ease-in;
|
||||
@ -346,15 +340,19 @@ p {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.windows {
|
||||
/* Using star selector to override
|
||||
* the specificity of other selectors
|
||||
* if performance is an issue we could
|
||||
* explicitely list all the elements */
|
||||
.windows * {
|
||||
font-family: 'Segoe';
|
||||
}
|
||||
|
||||
.mac {
|
||||
.mac * {
|
||||
font-family: 'Lucida Grande';
|
||||
}
|
||||
|
||||
.linux {
|
||||
.linux * {
|
||||
/* XXX requires fallbacks */
|
||||
font-family: 'Ubuntu', sans-serif;
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Shared conversation window styles */
|
||||
.standalone .video-layout-wrapper {
|
||||
.standalone .video-layout-wrapper,
|
||||
.conversation .media video {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
@ -11,37 +12,25 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.standalone .conversation {
|
||||
margin: 0 auto;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.conversation-toolbar {
|
||||
z-index: 999; /* required to have it superimposed to the video element */
|
||||
border: 1px solid #5a5a5a;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.conversation .conversation-toolbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0,0,0,.70);
|
||||
}
|
||||
|
||||
/* desktop version */
|
||||
.conversation-window .conversation-toolbar {
|
||||
.fx-embedded .conversation-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 26px;
|
||||
background: rgba(0,0,0,.70);
|
||||
}
|
||||
|
||||
/* standalone version */
|
||||
.standalone .conversation-toolbar {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.standalone .conversation-toolbar {
|
||||
background: rgba(0,0,0,.50);
|
||||
padding: 20px;
|
||||
height: 64px;
|
||||
}
|
||||
@ -111,11 +100,11 @@
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.conversation-window .conversation-toolbar .btn-hangup {
|
||||
.fx-embedded .conversation-toolbar .btn-hangup {
|
||||
background-image: url(../img/hangup-inverse-14x14.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.conversation-window .conversation-toolbar .btn-hangup {
|
||||
.fx-embedded .conversation-toolbar .btn-hangup {
|
||||
background-image: url(../img/hangup-inverse-14x14@2x.png);
|
||||
}
|
||||
}
|
||||
@ -166,54 +155,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Video elements */
|
||||
|
||||
.conversation .media video {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
/* Nested video elements */
|
||||
|
||||
.conversation .media.nested {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* fluid aspect ratio trick, see http://stackoverflow.com/a/10441480/330911 */
|
||||
.conversation .media.nested .remote_wrapper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 75%; /* XXX forced 4:3 ratio, see bug 1020445 */
|
||||
}
|
||||
|
||||
.conversation .media.nested .remote {
|
||||
display: inline-block;
|
||||
position: absolute; /* workaround for lack of object-fit; see bug 1020445 */
|
||||
width: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.conversation .media.nested .local {
|
||||
.fx-embedded .remote_wrapper {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 0;
|
||||
width: 30%;
|
||||
max-width: 140px;
|
||||
/* next two lines are workaround for lack of object-fit; see bug 1020445 */
|
||||
height: 22.5%;
|
||||
max-height: 105px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.standalone .conversation .media.nested .local {
|
||||
/* required to have it superimposed on the control toolbar */
|
||||
.standalone .local-stream {
|
||||
/* required to have it superimposed to the control toolbar */
|
||||
z-index: 1001;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
@ -224,7 +176,7 @@
|
||||
float: left;
|
||||
}
|
||||
|
||||
.conversation .media.side-by-side .local {
|
||||
.conversation .media.side-by-side .local-stream {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@ -262,7 +214,6 @@
|
||||
.incoming-call-action-group .btn-group-chevron,
|
||||
.incoming-call-action-group .btn-group {
|
||||
width: 100%;
|
||||
max-width: 120px; /* required by the UI Showcase, but the not real code */
|
||||
}
|
||||
|
||||
/* XXX Once we get the incoming call avatar, bug 1047435, the H2 should
|
||||
@ -474,3 +425,151 @@
|
||||
color: #CCC;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fx-embedded .local-stream {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
bottom: 5px;
|
||||
/* next two lines are workaround for lack of object-fit; see bug 1020445 */
|
||||
max-width: 140px;
|
||||
width: 30%;
|
||||
height: 28%;
|
||||
max-height: 105px;
|
||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.conversation .media.nested .remote {
|
||||
display: inline-block;
|
||||
position: absolute; /* workaround for lack of object-fit; see bug 1020445 */
|
||||
width: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX this approach is fragile because it makes assumptions
|
||||
* about the generated OT markup, any change will break it
|
||||
*/
|
||||
.local-stream.local-stream-audio,
|
||||
.standalone .OT_subscriber .OT_video-poster,
|
||||
.fx-embedded .OT_video-container .OT_video-poster,
|
||||
.local-stream-audio .OT_publisher .OT_video-poster {
|
||||
background-image: url("../img/audio-call-avatar.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-color: #4BA6E7;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.fx-embedded .media.nested {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
@media screen and (min-width:640px) {
|
||||
|
||||
/* Force full height on all parents up to the video elements
|
||||
* this way we can ensure the aspect ratio and use height 100%
|
||||
* on the video element
|
||||
* */
|
||||
html, body, #main,
|
||||
.video-layout-wrapper,
|
||||
.conversation {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.standalone .conversation-toolbar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fx-embedded .local-stream {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.standalone .local-stream {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
max-width: 400px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
/* Nested video elements */
|
||||
.conversation .media.nested {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.standalone .remote_wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.standalone {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width:640px) {
|
||||
.standalone .video-layout-wrapper,
|
||||
.standalone .conversation {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.standalone .media {
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.standalone .OT_subscriber {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.standalone .media.nested {
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.standalone .local-stream {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Nested video elements */
|
||||
.conversation .media.nested {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
|
||||
.standalone .video_wrapper.remote_wrapper {
|
||||
/* Because of OT markup we need to set a high flex value
|
||||
* Flex rule assures remote and local streams stack on top of eachother
|
||||
* Computed width is not 100% unless the `width` rule */
|
||||
flex: 2;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width:420px) {
|
||||
/* Restore video height so that we get
|
||||
* vertical centering for free on a small screen
|
||||
**/
|
||||
.standalone .conversation .media video {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,11 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-email,
|
||||
.btn-copy {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.share > .action .btn:hover {
|
||||
background-color: #008ACB;
|
||||
border: 1px solid #008ACB;
|
||||
|
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="129 5 252 253" width="21pc" height="253pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2014-08-13 17:00Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.4 --></metadata><defs><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4ba6e9"/><stop offset="1" stop-color="#4ba7bf"/></linearGradient></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><rect x="129" y="5" width="252" height="252" fill="#4BA6E7"/><circle cx="255" cy="106" r="54.000088" fill="#badbeb"/><path d="M 159.01782 257 L 350.98218 257 C 351.46667 236.66908 342.1 216.2136 322.88218 200.69928 C 285.39187 170.43352 224.60813 170.43352 187.11782 200.69928 C 167.9 216.2136 158.53333 236.66909 159.01782 257 Z" fill="#badbeb"/></g></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -6,7 +6,7 @@
|
||||
|
||||
var loop = loop || {};
|
||||
loop.shared = loop.shared || {};
|
||||
loop.shared.router = (function(l10n) {
|
||||
loop.shared.router = (function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
@ -186,4 +186,4 @@ loop.shared.router = (function(l10n) {
|
||||
BaseRouter: BaseRouter,
|
||||
BaseConversationRouter: BaseConversationRouter
|
||||
};
|
||||
})(document.webL10n || document.mozL10n);
|
||||
})();
|
||||
|
@ -253,6 +253,25 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
this.stopPublishing);
|
||||
|
||||
this.props.model.startSession();
|
||||
|
||||
/**
|
||||
* OT inserts inline styles into the markup. Using a listener for
|
||||
* resize events helps us trigger a full width/height on the element
|
||||
* so that they update to the correct dimensions.
|
||||
* */
|
||||
window.addEventListener('orientationchange', this.updateVideoContainer);
|
||||
window.addEventListener('resize', this.updateVideoContainer);
|
||||
},
|
||||
|
||||
updateVideoContainer: function() {
|
||||
var localStreamParent = document.querySelector('.local .OT_publisher');
|
||||
var remoteStreamParent = document.querySelector('.remote .OT_subscriber');
|
||||
if (localStreamParent) {
|
||||
localStreamParent.style.width = "100%";
|
||||
}
|
||||
if (remoteStreamParent) {
|
||||
remoteStreamParent.style.height = "100%";
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
@ -345,20 +364,25 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": !this.state.video.enabled
|
||||
});
|
||||
/* jshint ignore:start */
|
||||
return (
|
||||
React.DOM.div({className: "video-layout-wrapper"},
|
||||
React.DOM.div({className: "conversation"},
|
||||
ConversationToolbar({video: this.state.video,
|
||||
audio: this.state.audio,
|
||||
publishStream: this.publishStream,
|
||||
hangup: this.hangup}),
|
||||
React.DOM.div({className: "media nested"},
|
||||
React.DOM.div({className: "video_wrapper remote_wrapper"},
|
||||
React.DOM.div({className: "video_inner remote"})
|
||||
),
|
||||
React.DOM.div({className: "local"})
|
||||
)
|
||||
React.DOM.div({className: localStreamClasses})
|
||||
),
|
||||
ConversationToolbar({video: this.state.video,
|
||||
audio: this.state.audio,
|
||||
publishStream: this.publishStream,
|
||||
hangup: this.hangup})
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -735,7 +759,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
/**
|
||||
* Adds a l10n rror notification to the stack and renders it.
|
||||
*
|
||||
* @param {String} messageId L10n message id
|
||||
* @param {String} messageId L10n message id
|
||||
*/
|
||||
errorL10n: function(messageId) {
|
||||
this.error(l10n.get(messageId));
|
||||
@ -797,4 +821,4 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView
|
||||
};
|
||||
})(_, window.OT, document.webL10n || document.mozL10n);
|
||||
})(_, window.OT, navigator.mozL10n || document.mozL10n);
|
||||
|
@ -253,6 +253,25 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
this.stopPublishing);
|
||||
|
||||
this.props.model.startSession();
|
||||
|
||||
/**
|
||||
* OT inserts inline styles into the markup. Using a listener for
|
||||
* resize events helps us trigger a full width/height on the element
|
||||
* so that they update to the correct dimensions.
|
||||
* */
|
||||
window.addEventListener('orientationchange', this.updateVideoContainer);
|
||||
window.addEventListener('resize', this.updateVideoContainer);
|
||||
},
|
||||
|
||||
updateVideoContainer: function() {
|
||||
var localStreamParent = document.querySelector('.local .OT_publisher');
|
||||
var remoteStreamParent = document.querySelector('.remote .OT_subscriber');
|
||||
if (localStreamParent) {
|
||||
localStreamParent.style.width = "100%";
|
||||
}
|
||||
if (remoteStreamParent) {
|
||||
remoteStreamParent.style.height = "100%";
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
@ -345,20 +364,25 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": !this.state.video.enabled
|
||||
});
|
||||
/* jshint ignore:start */
|
||||
return (
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation">
|
||||
<ConversationToolbar video={this.state.video}
|
||||
audio={this.state.audio}
|
||||
publishStream={this.publishStream}
|
||||
hangup={this.hangup} />
|
||||
<div className="media nested">
|
||||
<div className="video_wrapper remote_wrapper">
|
||||
<div className="video_inner remote"></div>
|
||||
</div>
|
||||
<div className="local"></div>
|
||||
<div className={localStreamClasses}></div>
|
||||
</div>
|
||||
<ConversationToolbar video={this.state.video}
|
||||
audio={this.state.audio}
|
||||
publishStream={this.publishStream}
|
||||
hangup={this.hangup} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -735,7 +759,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
/**
|
||||
* Adds a l10n rror notification to the stack and renders it.
|
||||
*
|
||||
* @param {String} messageId L10n message id
|
||||
* @param {String} messageId L10n message id
|
||||
*/
|
||||
errorL10n: function(messageId) {
|
||||
this.error(l10n.get(messageId));
|
||||
@ -797,4 +821,4 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView
|
||||
};
|
||||
})(_, window.OT, document.webL10n || document.mozL10n);
|
||||
})(_, window.OT, navigator.mozL10n || document.mozL10n);
|
||||
|
File diff suppressed because one or more lines are too long
@ -44,6 +44,7 @@ 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)
|
||||
|
||||
# Shared scripts
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
@ -54,7 +55,11 @@ browser.jar:
|
||||
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
|
||||
|
||||
# Shared libs
|
||||
#ifdef DEBUG
|
||||
content/browser/loop/shared/libs/react-0.11.1.js (content/shared/libs/react-0.11.1.js)
|
||||
#else
|
||||
content/browser/loop/shared/libs/react-0.11.1.js (content/shared/libs/react-0.11.1-prod.js)
|
||||
#endif
|
||||
content/browser/loop/shared/libs/lodash-2.4.1.js (content/shared/libs/lodash-2.4.1.js)
|
||||
content/browser/loop/shared/libs/jquery-2.1.0.js (content/shared/libs/jquery-2.1.0.js)
|
||||
content/browser/loop/shared/libs/backbone-1.1.2.js (content/shared/libs/backbone-1.1.2.js)
|
||||
|
@ -18,9 +18,6 @@ EXTRA_JS_MODULES.loop += [
|
||||
'LoopStorage.jsm',
|
||||
'MozLoopAPI.jsm',
|
||||
'MozLoopPushHandler.jsm',
|
||||
'MozLoopService.jsm',
|
||||
'MozLoopWorker.js',
|
||||
]
|
||||
|
||||
EXTRA_PP_JS_MODULES.loop += [
|
||||
'MozLoopService.jsm',
|
||||
]
|
||||
|
@ -109,6 +109,7 @@ body,
|
||||
|
||||
.standalone-header-title {
|
||||
font-size: 1.8rem;
|
||||
line-height: 2.2rem;
|
||||
}
|
||||
|
||||
.standalone-call-btn-label {
|
||||
@ -137,8 +138,9 @@ body,
|
||||
.start-audio-only-call {
|
||||
width: 100%;
|
||||
border: none;
|
||||
color: #111;
|
||||
background-color: #fff;
|
||||
background-size: 10px;
|
||||
background-color: #F0F0F0;
|
||||
background-image: url("../shared/img/audio-default-16x16@1.5x.png");
|
||||
background-position: 90% center;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
window.OTProperties.cssURL = window.OTProperties.assetURL + 'css/ot.css';
|
||||
</script>
|
||||
<script type="text/javascript" src="shared/libs/sdk.js"></script>
|
||||
<script type="text/javascript" src="libs/webl10n-20130617.js"></script>
|
||||
<script type="text/javascript" src="libs/l10n-gaia-4e35bf8f0569.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/react-0.11.1.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/jquery-2.1.0.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/lodash-2.4.1.js"></script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
/* jshint newcap:false */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.webapp = (function($, _, OT, webL10n) {
|
||||
loop.webapp = (function($, _, OT, mozL10n) {
|
||||
"use strict";
|
||||
|
||||
loop.config = loop.config || {};
|
||||
@ -16,8 +16,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
|
||||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
baseServerUrl = loop.config.serverUrl,
|
||||
__ = webL10n.get;
|
||||
baseServerUrl = loop.config.serverUrl;
|
||||
|
||||
/**
|
||||
* App router.
|
||||
@ -46,11 +45,11 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
}
|
||||
return (
|
||||
React.DOM.div({className: "promote-firefox"},
|
||||
React.DOM.h3(null, __("promote_firefox_hello_heading")),
|
||||
React.DOM.h3(null, mozL10n.get("promote_firefox_hello_heading")),
|
||||
React.DOM.p(null,
|
||||
React.DOM.a({className: "btn btn-large btn-accept",
|
||||
href: "https://www.mozilla.org/firefox/"},
|
||||
__("get_firefox_button")
|
||||
mozL10n.get("get_firefox_button")
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -72,8 +71,8 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
React.DOM.div({className: "expired-url-info"},
|
||||
React.DOM.div({className: "info-panel"},
|
||||
React.DOM.div({className: "firefox-logo"}),
|
||||
React.DOM.h1(null, __("call_url_unavailable_notification_heading")),
|
||||
React.DOM.h4(null, __("call_url_unavailable_notification_message2"))
|
||||
React.DOM.h1(null, mozL10n.get("call_url_unavailable_notification_heading")),
|
||||
React.DOM.h4(null, mozL10n.get("call_url_unavailable_notification_message2"))
|
||||
),
|
||||
PromoteFirefoxView({helper: this.props.helper})
|
||||
)
|
||||
@ -94,7 +93,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
"hide": !this.props.urlCreationDateString.length
|
||||
});
|
||||
|
||||
var callUrlCreationDateString = __("call_url_creation_date_label", {
|
||||
var callUrlCreationDateString = mozL10n.get("call_url_creation_date_label", {
|
||||
"call_url_creation_date": this.props.urlCreationDateString
|
||||
});
|
||||
|
||||
@ -102,7 +101,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
/* jshint ignore:start */
|
||||
React.DOM.header({className: "standalone-header container-box"},
|
||||
React.DOM.h1({className: "standalone-header-title"},
|
||||
React.DOM.strong(null, __("brandShortname")), " ", __("clientShortname")
|
||||
React.DOM.strong(null, mozL10n.get("brandShortname")), " ", mozL10n.get("clientShortname")
|
||||
),
|
||||
React.DOM.div({className: "loop-logo", title: "Firefox WebRTC! logo"}),
|
||||
React.DOM.h3({className: "call-url"},
|
||||
@ -141,11 +140,15 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
*
|
||||
*/
|
||||
|
||||
getInitialProps: function() {
|
||||
return {showCallOptionsMenu: false};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
urlCreationDateString: '',
|
||||
disableCallButton: false,
|
||||
showCallOptionsMenu: false
|
||||
showCallOptionsMenu: this.props.showCallOptionsMenu
|
||||
};
|
||||
},
|
||||
|
||||
@ -219,18 +222,16 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var tos_link_name = __("terms_of_use_link_text");
|
||||
var privacy_notice_name = __("privacy_notice_link_text");
|
||||
var tos_link_name = mozL10n.get("terms_of_use_link_text");
|
||||
var privacy_notice_name = mozL10n.get("privacy_notice_link_text");
|
||||
|
||||
var tosHTML = __("legal_text_and_links", {
|
||||
var tosHTML = mozL10n.get("legal_text_and_links", {
|
||||
"terms_of_use_url": "<a target=_blank href='" +
|
||||
"https://accounts.firefox.com/legal/terms'>" + tos_link_name + "</a>",
|
||||
"privacy_notice_url": "<a target=_blank href='" +
|
||||
"https://www.mozilla.org/privacy/'>" + privacy_notice_name + "</a>"
|
||||
});
|
||||
|
||||
var btnClassStartCall = "btn btn-large btn-accept " +
|
||||
loop.shared.utils.getTargetPlatform();
|
||||
var dropdownMenuClasses = React.addons.classSet({
|
||||
"native-dropdown-large-parent": true,
|
||||
"standalone-dropdown-menu": true,
|
||||
@ -250,7 +251,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
urlCreationDateString: this.state.urlCreationDateString}),
|
||||
|
||||
React.DOM.p({className: "standalone-call-btn-label"},
|
||||
__("initiate_call_button_label2")
|
||||
mozL10n.get("initiate_call_button_label2")
|
||||
),
|
||||
|
||||
React.DOM.div({id: "messages"}),
|
||||
@ -261,18 +262,18 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
React.DOM.div({className: "btn-group-chevron"},
|
||||
React.DOM.div({className: "btn-group"},
|
||||
|
||||
React.DOM.button({className: btnClassStartCall,
|
||||
React.DOM.button({className: "btn btn-large btn-accept",
|
||||
onClick: this._initiateOutgoingCall("audio-video"),
|
||||
disabled: this.state.disableCallButton,
|
||||
title: __("initiate_audio_video_call_tooltip2")},
|
||||
title: mozL10n.get("initiate_audio_video_call_tooltip2")},
|
||||
React.DOM.span({className: "standalone-call-btn-text"},
|
||||
__("initiate_audio_video_call_button2")
|
||||
mozL10n.get("initiate_audio_video_call_button2")
|
||||
),
|
||||
React.DOM.span({className: "standalone-call-btn-video-icon"})
|
||||
),
|
||||
|
||||
React.DOM.div({className: "btn-chevron",
|
||||
onClick: this._toggleCallOptionsMenu}
|
||||
onClick: this._toggleCallOptionsMenu}
|
||||
)
|
||||
|
||||
),
|
||||
@ -285,7 +286,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
React.DOM.button({className: "start-audio-only-call",
|
||||
onClick: this._initiateOutgoingCall("audio"),
|
||||
disabled: this.state.disableCallButton},
|
||||
__("initiate_audio_call_button2")
|
||||
mozL10n.get("initiate_audio_call_button2")
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -571,11 +572,9 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
router.navigate("unsupportedBrowser", {trigger: true});
|
||||
}
|
||||
|
||||
document.body.classList.add(loop.shared.utils.getTargetPlatform());
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
document.documentElement.lang = document.webL10n.getLanguage();
|
||||
document.documentElement.dir = document.webL10n.getDirection();
|
||||
document.documentElement.lang = mozL10n.language.code;
|
||||
document.documentElement.dir = mozL10n.language.direction;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -588,4 +587,4 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
WebappHelper: WebappHelper,
|
||||
WebappRouter: WebappRouter
|
||||
};
|
||||
})(jQuery, _, window.OT, document.webL10n);
|
||||
})(jQuery, _, window.OT, navigator.mozL10n);
|
||||
|
@ -8,7 +8,7 @@
|
||||
/* jshint newcap:false */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.webapp = (function($, _, OT, webL10n) {
|
||||
loop.webapp = (function($, _, OT, mozL10n) {
|
||||
"use strict";
|
||||
|
||||
loop.config = loop.config || {};
|
||||
@ -16,8 +16,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
|
||||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
baseServerUrl = loop.config.serverUrl,
|
||||
__ = webL10n.get;
|
||||
baseServerUrl = loop.config.serverUrl;
|
||||
|
||||
/**
|
||||
* App router.
|
||||
@ -46,11 +45,11 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
}
|
||||
return (
|
||||
<div className="promote-firefox">
|
||||
<h3>{__("promote_firefox_hello_heading")}</h3>
|
||||
<h3>{mozL10n.get("promote_firefox_hello_heading")}</h3>
|
||||
<p>
|
||||
<a className="btn btn-large btn-accept"
|
||||
href="https://www.mozilla.org/firefox/">
|
||||
{__("get_firefox_button")}
|
||||
{mozL10n.get("get_firefox_button")}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
@ -72,8 +71,8 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
<div className="expired-url-info">
|
||||
<div className="info-panel">
|
||||
<div className="firefox-logo" />
|
||||
<h1>{__("call_url_unavailable_notification_heading")}</h1>
|
||||
<h4>{__("call_url_unavailable_notification_message2")}</h4>
|
||||
<h1>{mozL10n.get("call_url_unavailable_notification_heading")}</h1>
|
||||
<h4>{mozL10n.get("call_url_unavailable_notification_message2")}</h4>
|
||||
</div>
|
||||
<PromoteFirefoxView helper={this.props.helper} />
|
||||
</div>
|
||||
@ -94,7 +93,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
"hide": !this.props.urlCreationDateString.length
|
||||
});
|
||||
|
||||
var callUrlCreationDateString = __("call_url_creation_date_label", {
|
||||
var callUrlCreationDateString = mozL10n.get("call_url_creation_date_label", {
|
||||
"call_url_creation_date": this.props.urlCreationDateString
|
||||
});
|
||||
|
||||
@ -102,7 +101,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
/* jshint ignore:start */
|
||||
<header className="standalone-header container-box">
|
||||
<h1 className="standalone-header-title">
|
||||
<strong>{__("brandShortname")}</strong> {__("clientShortname")}
|
||||
<strong>{mozL10n.get("brandShortname")}</strong> {mozL10n.get("clientShortname")}
|
||||
</h1>
|
||||
<div className="loop-logo" title="Firefox WebRTC! logo"></div>
|
||||
<h3 className="call-url">
|
||||
@ -141,11 +140,15 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
*
|
||||
*/
|
||||
|
||||
getInitialProps: function() {
|
||||
return {showCallOptionsMenu: false};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
urlCreationDateString: '',
|
||||
disableCallButton: false,
|
||||
showCallOptionsMenu: false
|
||||
showCallOptionsMenu: this.props.showCallOptionsMenu
|
||||
};
|
||||
},
|
||||
|
||||
@ -219,18 +222,16 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var tos_link_name = __("terms_of_use_link_text");
|
||||
var privacy_notice_name = __("privacy_notice_link_text");
|
||||
var tos_link_name = mozL10n.get("terms_of_use_link_text");
|
||||
var privacy_notice_name = mozL10n.get("privacy_notice_link_text");
|
||||
|
||||
var tosHTML = __("legal_text_and_links", {
|
||||
var tosHTML = mozL10n.get("legal_text_and_links", {
|
||||
"terms_of_use_url": "<a target=_blank href='" +
|
||||
"https://accounts.firefox.com/legal/terms'>" + tos_link_name + "</a>",
|
||||
"privacy_notice_url": "<a target=_blank href='" +
|
||||
"https://www.mozilla.org/privacy/'>" + privacy_notice_name + "</a>"
|
||||
});
|
||||
|
||||
var btnClassStartCall = "btn btn-large btn-accept " +
|
||||
loop.shared.utils.getTargetPlatform();
|
||||
var dropdownMenuClasses = React.addons.classSet({
|
||||
"native-dropdown-large-parent": true,
|
||||
"standalone-dropdown-menu": true,
|
||||
@ -250,7 +251,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
urlCreationDateString={this.state.urlCreationDateString} />
|
||||
|
||||
<p className="standalone-call-btn-label">
|
||||
{__("initiate_call_button_label2")}
|
||||
{mozL10n.get("initiate_call_button_label2")}
|
||||
</p>
|
||||
|
||||
<div id="messages"></div>
|
||||
@ -261,18 +262,18 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
<div className="btn-group-chevron">
|
||||
<div className="btn-group">
|
||||
|
||||
<button className={btnClassStartCall}
|
||||
<button className="btn btn-large btn-accept"
|
||||
onClick={this._initiateOutgoingCall("audio-video")}
|
||||
disabled={this.state.disableCallButton}
|
||||
title={__("initiate_audio_video_call_tooltip2")} >
|
||||
title={mozL10n.get("initiate_audio_video_call_tooltip2")} >
|
||||
<span className="standalone-call-btn-text">
|
||||
{__("initiate_audio_video_call_button2")}
|
||||
{mozL10n.get("initiate_audio_video_call_button2")}
|
||||
</span>
|
||||
<span className="standalone-call-btn-video-icon"></span>
|
||||
</button>
|
||||
|
||||
<div className="btn-chevron"
|
||||
onClick={this._toggleCallOptionsMenu}>
|
||||
onClick={this._toggleCallOptionsMenu}>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -285,7 +286,7 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
<button className="start-audio-only-call"
|
||||
onClick={this._initiateOutgoingCall("audio")}
|
||||
disabled={this.state.disableCallButton} >
|
||||
{__("initiate_audio_call_button2")}
|
||||
{mozL10n.get("initiate_audio_call_button2")}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@ -571,11 +572,9 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
router.navigate("unsupportedBrowser", {trigger: true});
|
||||
}
|
||||
|
||||
document.body.classList.add(loop.shared.utils.getTargetPlatform());
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
document.documentElement.lang = document.webL10n.getLanguage();
|
||||
document.documentElement.dir = document.webL10n.getDirection();
|
||||
document.documentElement.lang = mozL10n.language.code;
|
||||
document.documentElement.dir = mozL10n.language.direction;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -588,4 +587,4 @@ loop.webapp = (function($, _, OT, webL10n) {
|
||||
WebappHelper: WebappHelper,
|
||||
WebappRouter: WebappRouter
|
||||
};
|
||||
})(jQuery, _, window.OT, document.webL10n);
|
||||
})(jQuery, _, window.OT, navigator.mozL10n);
|
||||
|
@ -1,71 +1,2 @@
|
||||
## LOCALIZATION NOTE: In this file, don't translate the part between {{..}}
|
||||
[en]
|
||||
restart_call=Rejoin
|
||||
conversation_has_ended=Your conversation has ended.
|
||||
call_timeout_notification_text=Your call did not go through.
|
||||
missing_conversation_info=Missing conversation information.
|
||||
network_disconnected=The network connection terminated abruptly.
|
||||
peer_ended_conversation2=The person you were calling has ended the conversation.
|
||||
connection_error_see_console_notification=Call failed; see console for details.
|
||||
generic_failure_title=Something went wrong.
|
||||
generic_failure_with_reason2=You can try again or email a link to be reached at later.
|
||||
generic_failure_no_reason2=Would you like to try again?
|
||||
retry_call_button=Retry
|
||||
feedback_report_user_button=Report User
|
||||
unable_retrieve_call_info=Unable to retrieve conversation information.
|
||||
hangup_button_title=Hang up
|
||||
hangup_button_caption2=Exit
|
||||
mute_local_audio_button_title=Mute your audio
|
||||
unmute_local_audio_button_title=Unmute your audio
|
||||
mute_local_video_button_title=Mute your video
|
||||
unmute_local_video_button_title=Unmute your video
|
||||
outgoing_call_title=Start conversation?
|
||||
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>.
|
||||
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.
|
||||
connection_error_see_console_notification=Call failed; see console for details.
|
||||
call_url_unavailable_notification_heading=Oops!
|
||||
call_url_unavailable_notification_message2=Sorry, this URL is not available. It may be expired or entered incorrectly.
|
||||
promote_firefox_hello_heading=Download {{brandShortname}} to make free audio and video calls!
|
||||
get_firefox_button=Get {{brandShortname}}
|
||||
initiate_call_button_label2=Ready to start your conversation?
|
||||
initiate_audio_video_call_button2=Start
|
||||
initiate_audio_video_call_tooltip2=Start a video conversation
|
||||
initiate_audio_call_button2=Voice conversation
|
||||
reject_incoming_call=Cancel
|
||||
legal_text_and_links=By using this product you agree to the {{terms_of_use_url}} and {{privacy_notice_url}}
|
||||
terms_of_use_link_text=Terms of use
|
||||
privacy_notice_link_text=Privacy notice
|
||||
brandShortname=Firefox
|
||||
clientShortname=WebRTC!
|
||||
## LOCALIZATION NOTE (call_url_creation_date_label): Example output: (from May 26, 2014)
|
||||
call_url_creation_date_label=(from {{call_url_creation_date}})
|
||||
call_progress_connecting_description=Connecting…
|
||||
call_progress_ringing_description=Ringing…
|
||||
@import url(loop.en-US.properties)
|
||||
|
||||
[fr]
|
||||
call_timeout_notification_text=Votre appel n'a pas abouti.
|
||||
missing_conversation_info=Informations de communication manquantes.
|
||||
network_disconnected=La connexion réseau semble avoir été interrompue.
|
||||
unable_retrieve_call_info=Impossible de récupérer les informations liées à cet appel.
|
||||
hangup_button_title=Terminer l'appel
|
||||
hangup_button_caption=Raccrocher
|
||||
mute_local_audio_button_title=Couper la diffusion audio
|
||||
unmute_local_audio_button_title=Reprendre la diffusion audio
|
||||
mute_local_video_button_title=Couper la diffusion vidéo
|
||||
unmute_local_video_button_title=Reprendre la diffusion vidéo
|
||||
welcome=Bienvenue sur {{clientShortname}}.
|
||||
incompatible_browser=Navigateur non supporté
|
||||
powered_by_webrtc=Les fonctionnalités audio et vidéo de {{clientShortname}} utilisent WebRTC.
|
||||
use_latest_firefox.innerHTML=Veuillez essayer ce lien dans un navigateur acceptant WebRTC, par exemple <a href="{{ff_url}}">{{brandShortname}}</a>.
|
||||
incompatible_device=Plateforme non supportée
|
||||
sorry_device_unsupported=Désolé, {{clientShortname}} ne fonctionne actuellement pas sur votre appareil.
|
||||
use_firefox_windows_mac_linux=Merci d'ouvrir cette page avec une version récente de {{brandShortname}} pour Windows, Android, Mac ou Linux.
|
||||
call_url_unavailable_notification_heading=Oups !
|
||||
promote_firefox_hello_heading=Téléchargez {{brandShortname}} pour passer des appels audio et vidéo gratuitement !
|
||||
get_firefox_button=Téléchargez {{brandShortname}}
|
||||
|
@ -0,0 +1,48 @@
|
||||
## LOCALIZATION NOTE: In this file, don't translate the part between {{..}}
|
||||
restart_call=Rejoin
|
||||
conversation_has_ended=Your conversation has ended.
|
||||
call_timeout_notification_text=Your call did not go through.
|
||||
missing_conversation_info=Missing conversation information.
|
||||
network_disconnected=The network connection terminated abruptly.
|
||||
peer_ended_conversation2=The person you were calling has ended the conversation.
|
||||
connection_error_see_console_notification=Call failed; see console for details.
|
||||
generic_failure_title=Something went wrong.
|
||||
generic_failure_with_reason2=You can try again or email a link to be reached at later.
|
||||
generic_failure_no_reason2=Would you like to try again?
|
||||
retry_call_button=Retry
|
||||
feedback_report_user_button=Report User
|
||||
unable_retrieve_call_info=Unable to retrieve conversation information.
|
||||
hangup_button_title=Hang up
|
||||
hangup_button_caption2=Exit
|
||||
mute_local_audio_button_title=Mute your audio
|
||||
unmute_local_audio_button_title=Unmute your audio
|
||||
mute_local_video_button_title=Mute your video
|
||||
unmute_local_video_button_title=Unmute your video
|
||||
outgoing_call_title=Start conversation?
|
||||
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>.
|
||||
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.
|
||||
connection_error_see_console_notification=Call failed; see console for details.
|
||||
call_url_unavailable_notification_heading=Oops!
|
||||
call_url_unavailable_notification_message2=Sorry, this URL is not available. It may be expired or entered incorrectly.
|
||||
promote_firefox_hello_heading=Download {{brandShortname}} to make free audio and video calls!
|
||||
get_firefox_button=Get {{brandShortname}}
|
||||
initiate_call_button_label2=Ready to start your conversation?
|
||||
initiate_audio_video_call_button2=Start
|
||||
initiate_audio_video_call_tooltip2=Start a video conversation
|
||||
initiate_audio_call_button2=Voice conversation
|
||||
reject_incoming_call=Cancel
|
||||
legal_text_and_links=By using this product you agree to the {{terms_of_use_url}} and {{privacy_notice_url}}
|
||||
terms_of_use_link_text=Terms of use
|
||||
privacy_notice_link_text=Privacy notice
|
||||
brandShortname=Firefox
|
||||
clientShortname=WebRTC!
|
||||
## LOCALIZATION NOTE (call_url_creation_date_label): Example output: (from May 26, 2014)
|
||||
call_url_creation_date_label=(from {{call_url_creation_date}})
|
||||
call_progress_connecting_description=Connecting…
|
||||
call_progress_ringing_description=Ringing…
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ support-files =
|
||||
|
||||
[browser_CardDavImporter.js]
|
||||
[browser_fxa_login.js]
|
||||
skip-if = !debug || e10s
|
||||
skip-if = e10s
|
||||
[browser_loop_fxa_server.js]
|
||||
[browser_LoopContacts.js]
|
||||
[browser_mozLoop_appVersionInfo.js]
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const gFxAOAuthTokenData = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).gFxAOAuthTokenData;
|
||||
const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
|
||||
|
||||
add_task(function* setup() {
|
||||
@ -29,27 +30,27 @@ add_task(function* checkOAuthParams() {
|
||||
state: "state",
|
||||
};
|
||||
yield promiseOAuthParamsSetup(BASE_URL, params);
|
||||
let client = yield MozLoopService.internal.promiseFxAOAuthClient();
|
||||
let client = yield MozLoopServiceInternal.promiseFxAOAuthClient();
|
||||
for (let key of Object.keys(params)) {
|
||||
ise(client.parameters[key], params[key], "Check " + key + " was passed to the OAuth client");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* basicAuthorization() {
|
||||
let result = yield MozLoopService.internal.promiseFxAOAuthAuthorization();
|
||||
let result = yield MozLoopServiceInternal.promiseFxAOAuthAuthorization();
|
||||
is(result.code, "code1", "Check code");
|
||||
is(result.state, "state", "Check state");
|
||||
});
|
||||
|
||||
add_task(function* sameOAuthClientForTwoCalls() {
|
||||
MozLoopService.resetFxA();
|
||||
let client1 = yield MozLoopService.internal.promiseFxAOAuthClient();
|
||||
let client2 = yield MozLoopService.internal.promiseFxAOAuthClient();
|
||||
resetFxA();
|
||||
let client1 = yield MozLoopServiceInternal.promiseFxAOAuthClient();
|
||||
let client2 = yield MozLoopServiceInternal.promiseFxAOAuthClient();
|
||||
ise(client1, client2, "The same client should be returned");
|
||||
});
|
||||
|
||||
add_task(function* paramsInvalid() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
// Delete the params so an empty object is returned.
|
||||
yield promiseDeletedOAuthParams(BASE_URL);
|
||||
let result = null;
|
||||
@ -64,7 +65,7 @@ add_task(function* paramsInvalid() {
|
||||
});
|
||||
|
||||
add_task(function* params_nonJSON() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
Services.prefs.setCharPref("loop.server", "https://loop.invalid");
|
||||
let result = null;
|
||||
let loginPromise = MozLoopService.logInToFxA();
|
||||
@ -76,7 +77,7 @@ add_task(function* params_nonJSON() {
|
||||
});
|
||||
|
||||
add_task(function* invalidState() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -92,7 +93,7 @@ add_task(function* invalidState() {
|
||||
});
|
||||
|
||||
add_task(function* basicRegistration() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -102,14 +103,14 @@ add_task(function* basicRegistration() {
|
||||
};
|
||||
yield promiseOAuthParamsSetup(BASE_URL, params);
|
||||
|
||||
let tokenData = yield MozLoopService.internal.promiseFxAOAuthToken("code1", "state");
|
||||
let tokenData = yield MozLoopServiceInternal.promiseFxAOAuthToken("code1", "state");
|
||||
is(tokenData.access_token, "code1_access_token", "Check access_token");
|
||||
is(tokenData.scope, "profile", "Check scope");
|
||||
is(tokenData.token_type, "bearer", "Check token_type");
|
||||
});
|
||||
|
||||
add_task(function* registrationWithInvalidState() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -119,7 +120,7 @@ add_task(function* registrationWithInvalidState() {
|
||||
};
|
||||
yield promiseOAuthParamsSetup(BASE_URL, params);
|
||||
|
||||
let tokenPromise = MozLoopService.internal.promiseFxAOAuthToken("code1", "state");
|
||||
let tokenPromise = MozLoopServiceInternal.promiseFxAOAuthToken("code1", "state");
|
||||
yield tokenPromise.then(body => {
|
||||
ok(false, "Promise should have rejected");
|
||||
},
|
||||
@ -129,7 +130,7 @@ add_task(function* registrationWithInvalidState() {
|
||||
});
|
||||
|
||||
add_task(function* registrationWith401() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -140,7 +141,7 @@ add_task(function* registrationWith401() {
|
||||
};
|
||||
yield promiseOAuthParamsSetup(BASE_URL, params);
|
||||
|
||||
let tokenPromise = MozLoopService.internal.promiseFxAOAuthToken("code1", "state");
|
||||
let tokenPromise = MozLoopServiceInternal.promiseFxAOAuthToken("code1", "state");
|
||||
yield tokenPromise.then(body => {
|
||||
ok(false, "Promise should have rejected");
|
||||
},
|
||||
@ -150,7 +151,7 @@ add_task(function* registrationWith401() {
|
||||
});
|
||||
|
||||
add_task(function* basicAuthorizationAndRegistration() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -167,7 +168,7 @@ add_task(function* basicAuthorizationAndRegistration() {
|
||||
});
|
||||
|
||||
add_task(function* loginWithParams401() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -184,12 +185,12 @@ add_task(function* loginWithParams401() {
|
||||
},
|
||||
error => {
|
||||
ise(error.code, 401, "Check error code");
|
||||
ise(MozLoopService.gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
ise(gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* loginWithRegistration401() {
|
||||
MozLoopService.resetFxA();
|
||||
resetFxA();
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
@ -206,6 +207,6 @@ add_task(function* loginWithRegistration401() {
|
||||
},
|
||||
error => {
|
||||
ise(error.code, 401, "Check error code");
|
||||
ise(MozLoopService.gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
ise(gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
});
|
||||
});
|
||||
|
@ -7,9 +7,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const MozLoopServiceInternal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).
|
||||
MozLoopServiceInternal;
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
MozLoopService.doNotDisturb = false;
|
||||
yield MozLoopServiceInternal.clearError("testing");
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const MozLoopServiceInternal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).
|
||||
MozLoopServiceInternal;
|
||||
|
||||
var gMozLoopAPI;
|
||||
|
||||
function promiseGetMozLoopAPI() {
|
||||
@ -91,6 +94,13 @@ function promiseOAuthParamsSetup(baseURL, params) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function resetFxA() {
|
||||
let global = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
global.gFxAOAuthClientPromise = null;
|
||||
global.gFxAOAuthClient = null;
|
||||
global.gFxAOAuthTokenData = null;
|
||||
}
|
||||
|
||||
function promiseDeletedOAuthParams(baseURL) {
|
||||
let deferred = Promise.defer();
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
|
@ -20,7 +20,7 @@
|
||||
<script src="../../content/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script src="../../content/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script src="../../content/shared/libs/backbone-1.1.2.js"></script>
|
||||
<script src="../../standalone/content/libs/webl10n-20130617.js"></script>
|
||||
<script src="../../standalone/content/libs/l10n-gaia-4e35bf8f0569.js"></script>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<script src="vendor/mocha-1.17.1.js"></script>
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* jshint newcap:false */
|
||||
|
||||
var expect = chai.expect;
|
||||
var l10n = document.webL10n || document.mozL10n;
|
||||
var l10n = navigator.mozL10n || document.mozL10n;
|
||||
var TestUtils = React.addons.TestUtils;
|
||||
|
||||
describe("loop.shared.views", function() {
|
||||
|
@ -20,7 +20,7 @@
|
||||
<script src="../../content/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script src="../../content/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script src="../../content/shared/libs/backbone-1.1.2.js"></script>
|
||||
<script src="../../standalone/content/libs/webl10n-20130617.js"></script>
|
||||
<script src="../../standalone/content/libs/l10n-gaia-4e35bf8f0569.js"></script>
|
||||
<!-- test dependencies -->
|
||||
<script src="../shared/vendor/mocha-1.17.1.js"></script>
|
||||
<script src="../shared/vendor/chai-1.9.0.js"></script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
* for any requested string id.
|
||||
* @type {Object}
|
||||
*/
|
||||
document.webL10n = document.mozL10n = {
|
||||
navigator.mozL10n = document.mozL10n = {
|
||||
get: function(stringId, vars) {
|
||||
|
||||
// upcase the first letter
|
||||
|
@ -3,15 +3,21 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.showcase {
|
||||
width: 730px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.showcase-menu,
|
||||
.showcase {
|
||||
min-width: 350px;
|
||||
max-width: 730px;
|
||||
}
|
||||
|
||||
.showcase > header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
background-color: #fbfbfb;
|
||||
z-index: 1000;
|
||||
z-index: 100000;
|
||||
width: 100%;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
@ -26,15 +32,17 @@
|
||||
.showcase-menu > a {
|
||||
margin-right: .5em;
|
||||
padding: .4rem;
|
||||
margin-top: .2rem;
|
||||
}
|
||||
|
||||
.showcase > section {
|
||||
position: relative;
|
||||
padding-top: 10em;
|
||||
padding-top: 12em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.showcase > section > h1 {
|
||||
margin: 1em 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
@ -50,11 +58,18 @@
|
||||
margin-bottom: 6em;
|
||||
}
|
||||
|
||||
.showcase > section > h2 {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
.showcase > section .example > h3 {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
border-bottom: 1px dashed #aaa;
|
||||
margin: .5em 0;
|
||||
margin: 1em 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.showcase p.note {
|
||||
@ -64,21 +79,73 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.override-position * {
|
||||
/* Specific for toolbar component atm
|
||||
* disables position absolute so that the parent div can
|
||||
* compute the dimensions and prevent collapse */
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
/* Just for the showcase to look sane */
|
||||
.showcase .fx-embedded .local-stream {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.showcase p.note > strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images as fake videos for conversation view */
|
||||
.conversation .media.nested .remote,
|
||||
.conversation .media.nested .local {
|
||||
background-size: contain;
|
||||
/*
|
||||
* Switched to using height: 100% in standalone version
|
||||
* this mocks it for the ui so that the component has height
|
||||
* */
|
||||
.standalone .video-layout-wrapper,
|
||||
.standalone .remote_wrapper {
|
||||
min-height: 550px;
|
||||
}
|
||||
|
||||
.conversation .media.nested .remote {
|
||||
@media screen and (max-width:640px) {
|
||||
|
||||
.standalone .local-stream {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.standalone .local-stream,
|
||||
.conversation .media.nested .remote {
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.standalone .remote_wrapper {
|
||||
width: 100%;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.remote_wrapper {
|
||||
background-image: url("sample-img/video-screen-remote.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.local-stream {
|
||||
background-image: url("sample-img/video-screen-local.png");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.conversation .media.nested .local {
|
||||
background-image: url("sample-img/video-screen-local.png");
|
||||
.local-stream.local:not(.local-stream-audio) {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.incoming-call-action-group .btn-group-chevron,
|
||||
.incoming-call-action-group .btn-group {
|
||||
/* Prevent box overflow due to long string */
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.conversation .media.nested .remote {
|
||||
/* Height of obsolute box covers media control buttons. UI showcase only.
|
||||
* When tokbox inserts the markup into the page the problem goes away */
|
||||
bottom: auto;
|
||||
}
|
||||
|
@ -44,14 +44,20 @@
|
||||
}
|
||||
);
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockClient = {
|
||||
requestCallUrl: noop,
|
||||
requestCallUrlInfo: noop
|
||||
};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({}, {sdk: {}});
|
||||
var mockSDK = {};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({}, {
|
||||
sdk: mockSDK
|
||||
});
|
||||
mockConversationModel.startSession = noop;
|
||||
|
||||
// Fake notifier
|
||||
var mockNotifier = {};
|
||||
|
||||
var Example = React.createClass({displayName: 'Example',
|
||||
@ -121,13 +127,23 @@
|
||||
|
||||
Section({name: "IncomingCallView"},
|
||||
Example({summary: "Default", dashed: "true", style: {width: "280px"}},
|
||||
IncomingCallView({model: mockConversationModel})
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
IncomingCallView({model: mockConversationModel})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "IncomingCallView-ActiveState"},
|
||||
Example({summary: "Default", dashed: "true", style: {width: "280px"}},
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
IncomingCallView({model: mockConversationModel, showDeclineMenu: true})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "ConversationToolbar"},
|
||||
React.DOM.h3(null, "Desktop Conversation Window"),
|
||||
React.DOM.div({className: "conversation-window"},
|
||||
React.DOM.h2(null, "Desktop Conversation Window"),
|
||||
React.DOM.div({className: "fx-embedded override-position"},
|
||||
Example({summary: "Default (260x265)", dashed: "true"},
|
||||
ConversationToolbar({video: {enabled: true},
|
||||
audio: {enabled: true},
|
||||
@ -148,8 +164,8 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.DOM.h3(null, "Standalone"),
|
||||
React.DOM.div({className: "standalone"},
|
||||
React.DOM.h2(null, "Standalone"),
|
||||
React.DOM.div({className: "standalone override-position"},
|
||||
Example({summary: "Default"},
|
||||
ConversationToolbar({video: {enabled: true},
|
||||
audio: {enabled: true},
|
||||
@ -176,7 +192,8 @@
|
||||
React.DOM.div({className: "standalone"},
|
||||
StartConversationView({model: mockConversationModel,
|
||||
client: mockClient,
|
||||
notifier: mockNotifier})
|
||||
notifier: mockNotifier,
|
||||
showCallOptionsMenu: true})
|
||||
)
|
||||
)
|
||||
),
|
||||
@ -184,26 +201,70 @@
|
||||
Section({name: "ConversationView"},
|
||||
Example({summary: "Desktop conversation window", dashed: "true",
|
||||
style: {width: "260px", height: "265px"}},
|
||||
React.DOM.div({className: "conversation-window"},
|
||||
ConversationView({sdk: {},
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
ConversationView({sdk: mockSDK,
|
||||
model: mockConversationModel,
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true}})
|
||||
)
|
||||
),
|
||||
|
||||
Example({summary: "Desktop conversation window large", dashed: "true"},
|
||||
React.DOM.div({className: "breakpoint", 'data-breakpoint-width': "800px",
|
||||
'data-breakpoint-height': "600px"},
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
ConversationView({sdk: mockSDK,
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true},
|
||||
model: mockConversationModel})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Example({summary: "Desktop conversation window local audio stream",
|
||||
dashed: "true", style: {width: "260px", height: "265px"}},
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
ConversationView({sdk: mockSDK,
|
||||
video: {enabled: false},
|
||||
audio: {enabled: true},
|
||||
model: mockConversationModel})
|
||||
)
|
||||
),
|
||||
|
||||
Example({summary: "Standalone version"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
ConversationView({sdk: {},
|
||||
model: mockConversationModel,
|
||||
ConversationView({sdk: mockSDK,
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true}})
|
||||
audio: {enabled: true},
|
||||
model: mockConversationModel})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "ConversationView-640"},
|
||||
Example({summary: "640px breakpoint for conversation view"},
|
||||
React.DOM.div({className: "breakpoint",
|
||||
style: {"text-align":"center"},
|
||||
'data-breakpoint-width': "400px",
|
||||
'data-breakpoint-height': "780px"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
ConversationView({sdk: mockSDK,
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true},
|
||||
model: mockConversationModel})
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "ConversationView-LocalAudio"},
|
||||
Example({summary: "Local stream is audio only"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
ConversationView({sdk: mockSDK,
|
||||
video: {enabled: false},
|
||||
audio: {enabled: true},
|
||||
model: mockConversationModel})
|
||||
)
|
||||
),
|
||||
Example({summary: "Default"},
|
||||
ConversationView({sdk: {},
|
||||
model: mockConversationModel,
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true}})
|
||||
)
|
||||
),
|
||||
|
||||
@ -230,15 +291,77 @@
|
||||
Example({summary: "Non-Firefox User"},
|
||||
CallUrlExpiredView({helper: {isFirefox: returnFalse}})
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "AlertMessages"},
|
||||
Example({summary: "Various alerts"},
|
||||
React.DOM.div({className: "alert alert-warning"},
|
||||
React.DOM.button({className: "close"}),
|
||||
React.DOM.p({className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
)
|
||||
),
|
||||
React.DOM.br(null),
|
||||
React.DOM.div({className: "alert alert-error"},
|
||||
React.DOM.button({className: "close"}),
|
||||
React.DOM.p({className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Render components that have different styles across
|
||||
* CSS media rules in their own iframe to mimic the viewport
|
||||
* */
|
||||
function _renderComponentsInIframes() {
|
||||
var parents = document.querySelectorAll('.breakpoint');
|
||||
[].forEach.call(parents, appendChildInIframe);
|
||||
|
||||
/**
|
||||
* Extracts the component from the DOM and appends in the an iframe
|
||||
*
|
||||
* @type {HTMLElement} parent - Parent DOM node of a component & iframe
|
||||
* */
|
||||
function appendChildInIframe(parent) {
|
||||
var styles = document.querySelector('head').children;
|
||||
var component = parent.children[0];
|
||||
var iframe = document.createElement('iframe');
|
||||
var width = parent.dataset.breakpointWidth;
|
||||
var height = parent.dataset.breakpointHeight;
|
||||
|
||||
iframe.style.width = width;
|
||||
iframe.style.height = height;
|
||||
|
||||
parent.appendChild(iframe);
|
||||
iframe.src = "about:blank";
|
||||
// Workaround for bug 297685
|
||||
iframe.onload = function () {
|
||||
var iframeHead = iframe.contentDocument.querySelector('head');
|
||||
iframe.contentDocument.documentElement.querySelector('body')
|
||||
.appendChild(component);
|
||||
|
||||
[].forEach.call(styles, function(style) {
|
||||
iframeHead.appendChild(style.cloneNode(true));
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
var body = document.body;
|
||||
body.className = loop.shared.utils.getTargetPlatform();
|
||||
React.renderComponent(App(null), document.body);
|
||||
|
||||
React.renderComponent(App(null), body);
|
||||
|
||||
_renderComponentsInIframes();
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -44,14 +44,20 @@
|
||||
}
|
||||
);
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockClient = {
|
||||
requestCallUrl: noop,
|
||||
requestCallUrlInfo: noop
|
||||
};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({}, {sdk: {}});
|
||||
var mockSDK = {};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({}, {
|
||||
sdk: mockSDK
|
||||
});
|
||||
mockConversationModel.startSession = noop;
|
||||
|
||||
// Fake notifier
|
||||
var mockNotifier = {};
|
||||
|
||||
var Example = React.createClass({
|
||||
@ -121,13 +127,23 @@
|
||||
|
||||
<Section name="IncomingCallView">
|
||||
<Example summary="Default" dashed="true" style={{width: "280px"}}>
|
||||
<IncomingCallView model={mockConversationModel} />
|
||||
<div className="fx-embedded">
|
||||
<IncomingCallView model={mockConversationModel} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="IncomingCallView-ActiveState">
|
||||
<Example summary="Default" dashed="true" style={{width: "280px"}}>
|
||||
<div className="fx-embedded" >
|
||||
<IncomingCallView model={mockConversationModel} showDeclineMenu={true} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="ConversationToolbar">
|
||||
<h3>Desktop Conversation Window</h3>
|
||||
<div className="conversation-window">
|
||||
<h2>Desktop Conversation Window</h2>
|
||||
<div className="fx-embedded override-position">
|
||||
<Example summary="Default (260x265)" dashed="true">
|
||||
<ConversationToolbar video={{enabled: true}}
|
||||
audio={{enabled: true}}
|
||||
@ -148,8 +164,8 @@
|
||||
</Example>
|
||||
</div>
|
||||
|
||||
<h3>Standalone</h3>
|
||||
<div className="standalone">
|
||||
<h2>Standalone</h2>
|
||||
<div className="standalone override-position">
|
||||
<Example summary="Default">
|
||||
<ConversationToolbar video={{enabled: true}}
|
||||
audio={{enabled: true}}
|
||||
@ -176,7 +192,8 @@
|
||||
<div className="standalone">
|
||||
<StartConversationView model={mockConversationModel}
|
||||
client={mockClient}
|
||||
notifier={mockNotifier} />
|
||||
notifier={mockNotifier}
|
||||
showCallOptionsMenu={true} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
@ -184,26 +201,70 @@
|
||||
<Section name="ConversationView">
|
||||
<Example summary="Desktop conversation window" dashed="true"
|
||||
style={{width: "260px", height: "265px"}}>
|
||||
<div className="conversation-window">
|
||||
<ConversationView sdk={{}}
|
||||
<div className="fx-embedded">
|
||||
<ConversationView sdk={mockSDK}
|
||||
model={mockConversationModel}
|
||||
video={{enabled: true}}
|
||||
audio={{enabled: true}} />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example summary="Desktop conversation window large" dashed="true">
|
||||
<div className="breakpoint" data-breakpoint-width="800px"
|
||||
data-breakpoint-height="600px">
|
||||
<div className="fx-embedded">
|
||||
<ConversationView sdk={mockSDK}
|
||||
video={{enabled: true}}
|
||||
audio={{enabled: true}}
|
||||
model={mockConversationModel} />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example summary="Desktop conversation window local audio stream"
|
||||
dashed="true" style={{width: "260px", height: "265px"}}>
|
||||
<div className="fx-embedded">
|
||||
<ConversationView sdk={mockSDK}
|
||||
video={{enabled: false}}
|
||||
audio={{enabled: true}}
|
||||
model={mockConversationModel} />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example summary="Standalone version">
|
||||
<div className="standalone">
|
||||
<ConversationView sdk={{}}
|
||||
model={mockConversationModel}
|
||||
<ConversationView sdk={mockSDK}
|
||||
video={{enabled: true}}
|
||||
audio={{enabled: true}} />
|
||||
audio={{enabled: true}}
|
||||
model={mockConversationModel} />
|
||||
</div>
|
||||
</Example>
|
||||
<Example summary="Default">
|
||||
<ConversationView sdk={{}}
|
||||
model={mockConversationModel}
|
||||
video={{enabled: true}}
|
||||
audio={{enabled: true}} />
|
||||
</Section>
|
||||
|
||||
<Section name="ConversationView-640">
|
||||
<Example summary="640px breakpoint for conversation view">
|
||||
<div className="breakpoint"
|
||||
style={{"text-align":"center"}}
|
||||
data-breakpoint-width="400px"
|
||||
data-breakpoint-height="780px">
|
||||
<div className="standalone">
|
||||
<ConversationView sdk={mockSDK}
|
||||
video={{enabled: true}}
|
||||
audio={{enabled: true}}
|
||||
model={mockConversationModel} />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="ConversationView-LocalAudio">
|
||||
<Example summary="Local stream is audio only">
|
||||
<div className="standalone">
|
||||
<ConversationView sdk={mockSDK}
|
||||
video={{enabled: false}}
|
||||
audio={{enabled: true}}
|
||||
model={mockConversationModel} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
@ -231,14 +292,76 @@
|
||||
<CallUrlExpiredView helper={{isFirefox: returnFalse}} />
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="AlertMessages">
|
||||
<Example summary="Various alerts">
|
||||
<div className="alert alert-warning">
|
||||
<button className="close"></button>
|
||||
<p className="message">
|
||||
The person you were calling has ended the conversation.
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<div className="alert alert-error">
|
||||
<button className="close"></button>
|
||||
<p className="message">
|
||||
The person you were calling has ended the conversation.
|
||||
</p>
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
</ShowCase>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Render components that have different styles across
|
||||
* CSS media rules in their own iframe to mimic the viewport
|
||||
* */
|
||||
function _renderComponentsInIframes() {
|
||||
var parents = document.querySelectorAll('.breakpoint');
|
||||
[].forEach.call(parents, appendChildInIframe);
|
||||
|
||||
/**
|
||||
* Extracts the component from the DOM and appends in the an iframe
|
||||
*
|
||||
* @type {HTMLElement} parent - Parent DOM node of a component & iframe
|
||||
* */
|
||||
function appendChildInIframe(parent) {
|
||||
var styles = document.querySelector('head').children;
|
||||
var component = parent.children[0];
|
||||
var iframe = document.createElement('iframe');
|
||||
var width = parent.dataset.breakpointWidth;
|
||||
var height = parent.dataset.breakpointHeight;
|
||||
|
||||
iframe.style.width = width;
|
||||
iframe.style.height = height;
|
||||
|
||||
parent.appendChild(iframe);
|
||||
iframe.src = "about:blank";
|
||||
// Workaround for bug 297685
|
||||
iframe.onload = function () {
|
||||
var iframeHead = iframe.contentDocument.querySelector('head');
|
||||
iframe.contentDocument.documentElement.querySelector('body')
|
||||
.appendChild(component);
|
||||
|
||||
[].forEach.call(styles, function(style) {
|
||||
iframeHead.appendChild(style.cloneNode(true));
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
var body = document.body;
|
||||
body.className = loop.shared.utils.getTargetPlatform();
|
||||
React.renderComponent(<App />, document.body);
|
||||
|
||||
React.renderComponent(<App />, body);
|
||||
|
||||
_renderComponentsInIframes();
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -2200,22 +2200,54 @@ function truncateString(str, maxLength) {
|
||||
function parseAttributeValues(attr, doc) {
|
||||
attr = attr.trim();
|
||||
|
||||
// Handle bad user inputs by appending a " or ' if it fails to parse without them.
|
||||
let el = DOMParser.parseFromString("<div " + attr + "></div>", "text/html").body.childNodes[0] ||
|
||||
DOMParser.parseFromString("<div " + attr + "\"></div>", "text/html").body.childNodes[0] ||
|
||||
DOMParser.parseFromString("<div " + attr + "'></div>", "text/html").body.childNodes[0];
|
||||
// Prepare other versions of the string to be parsed by appending a " or '
|
||||
// and using those if the first one fails to parse without these characters
|
||||
let stringsToParse = [
|
||||
"<div " + attr + "></div>",
|
||||
"<div " + attr + "\"></div>",
|
||||
"<div " + attr + "'></div>"
|
||||
];
|
||||
|
||||
// Try to parse as XML, this way, if the string is wellformed, this will
|
||||
// preserve the case.
|
||||
let parsedAttributes = [];
|
||||
for (let str of stringsToParse) {
|
||||
let parsed = DOMParser.parseFromString(str, "text/xml");
|
||||
// The XML parser generates a valid XML document even when parsing errors
|
||||
// occur, in which case the document contains a <parsererror> node, so check
|
||||
// that the document contains our expected DIV
|
||||
if (parsed.childNodes[0].localName === "div") {
|
||||
for (let {name, value} of parsed.childNodes[0].attributes) {
|
||||
parsedAttributes.push({ name, value });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the XML parsing failed, parse as HTML to get malformed attributes
|
||||
if (parsedAttributes.length === 0) {
|
||||
for (let str of stringsToParse) {
|
||||
let parsed = DOMParser.parseFromString(str, "text/html");
|
||||
// Check that the parsed document does contain the expected DIV as a child
|
||||
// of <body>
|
||||
if (parsed.body.childNodes[0]) {
|
||||
for (let {name, value} of parsed.body.childNodes[0].attributes) {
|
||||
parsedAttributes.push({ name, value });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let div = doc.createElement("div");
|
||||
|
||||
let attributes = [];
|
||||
for (let attribute of el.attributes) {
|
||||
for (let {name, value} of parsedAttributes) {
|
||||
// Try to set on an element in the document, throws exception on bad input.
|
||||
// Prevents InvalidCharacterError - "String contains an invalid character".
|
||||
try {
|
||||
div.setAttribute(attribute.name, attribute.value);
|
||||
attributes.push({
|
||||
name: attribute.name,
|
||||
value: attribute.value
|
||||
});
|
||||
div.setAttribute(name, value);
|
||||
attributes.push({ name, value });
|
||||
}
|
||||
catch(e) { }
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ support-files =
|
||||
doc_markup_pagesize_01.html
|
||||
doc_markup_pagesize_02.html
|
||||
doc_markup_search.html
|
||||
doc_markup_svg_attributes.html
|
||||
doc_markup_toggle.html
|
||||
doc_markup_tooltip.png
|
||||
head.js
|
||||
@ -80,6 +81,7 @@ skip-if = e10s # Bug 1036421 - Tag editing isn't remote-safe
|
||||
[browser_markupview_tag_edit_06.js]
|
||||
[browser_markupview_tag_edit_07.js]
|
||||
[browser_markupview_tag_edit_08.js]
|
||||
[browser_markupview_tag_edit_09.js]
|
||||
[browser_markupview_textcontent_edit_01.js]
|
||||
[browser_markupview_toggle_01.js]
|
||||
[browser_markupview_toggle_02.js]
|
||||
|
@ -0,0 +1,74 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that editing a mixed-case attribute preserves the case
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_markup_svg_attributes.html";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let {inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
yield inspector.markup.expandAll();
|
||||
yield selectNode("svg", inspector);
|
||||
|
||||
yield testWellformedMixedCase(inspector);
|
||||
yield testMalformedMixedCase(inspector);
|
||||
});
|
||||
|
||||
function* testWellformedMixedCase(inspector) {
|
||||
info("Modifying a mixed-case attribute, " +
|
||||
"expecting the attribute's case to be preserved");
|
||||
|
||||
info("Listening to markup mutations");
|
||||
let onMutated = inspector.once("markupmutation");
|
||||
|
||||
info("Focusing the viewBox attribute editor");
|
||||
let {editor} = yield getContainerForSelector("svg", inspector);
|
||||
let attr = editor.attrs["viewBox"].querySelector(".editable");
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
||||
info("Editing the attribute value and waiting for the mutation event");
|
||||
let input = inplaceEditor(attr).input;
|
||||
input.value = "viewBox=\"0 0 1 1\"";
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
yield onMutated;
|
||||
|
||||
assertAttributes("svg", {
|
||||
"viewBox": "0 0 1 1",
|
||||
"width": "200",
|
||||
"height": "200"
|
||||
});
|
||||
}
|
||||
|
||||
function* testMalformedMixedCase(inspector) {
|
||||
info("Modifying a mixed-case attribute, making sure to generate a parsing" +
|
||||
"error, and expecting the attribute's case to NOT be preserved");
|
||||
// See /browser/devtools/markupview/markup-view.js:parseAttributeValues
|
||||
// When attributes are malformed, they cannot be parsed with the XML parser
|
||||
// and so we fall back to the HTML parser which lowercases attributes.
|
||||
|
||||
info("Listening to markup mutations");
|
||||
let onMutated = inspector.once("markupmutation");
|
||||
|
||||
info("Focusing the viewBox attribute editor");
|
||||
let {editor} = yield getContainerForSelector("svg", inspector);
|
||||
let attr = editor.attrs["viewBox"].querySelector(".editable");
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
||||
info("Editing the attribute value and waiting for the mutation event");
|
||||
let input = inplaceEditor(attr).input;
|
||||
input.value = "viewBox=\"<>\"";
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
yield onMutated;
|
||||
|
||||
assertAttributes("svg", {
|
||||
"viewbox": "<>",
|
||||
"width": "200",
|
||||
"height": "200"
|
||||
});
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<svg viewBox="0 0 2 2" width=200 height=200>
|
||||
<circle cx=1 cy=1 r=1 fill=lime />
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,3 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
@ -429,13 +427,6 @@ ChromeActions.prototype = {
|
||||
.getService(Ci.nsIClipboardHelper);
|
||||
clipboard.copyString(data);
|
||||
},
|
||||
unsafeSetClipboard: function (data) {
|
||||
if (typeof data !== 'string') {
|
||||
return;
|
||||
}
|
||||
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||
clipboard.copyString(data);
|
||||
},
|
||||
endActivation: function () {
|
||||
if (ActivationQueue.currentNonActive === this) {
|
||||
ActivationQueue.activateNext();
|
||||
@ -552,8 +543,7 @@ RequestListener.prototype.receive = function(event) {
|
||||
}
|
||||
if (sync) {
|
||||
var response = actions[action].call(this.actions, data);
|
||||
var detail = event.detail;
|
||||
detail.response = response;
|
||||
event.detail.response = response;
|
||||
} else {
|
||||
var response;
|
||||
if (event.detail.callback) {
|
||||
@ -680,35 +670,29 @@ var ActivationQueue = {
|
||||
|
||||
function activateShumwayScripts(window, preview) {
|
||||
function loadScripts(scripts, callback) {
|
||||
function scriptLoaded() {
|
||||
leftToLoad--;
|
||||
if (leftToLoad === 0) {
|
||||
function loadScript(i) {
|
||||
if (i >= scripts.length) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
var leftToLoad = scripts.length;
|
||||
var document = window.document.wrappedJSObject;
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
var script = document.createElement('script');
|
||||
script.type = "text/javascript";
|
||||
script.src = scripts[i];
|
||||
script.onload = scriptLoaded;
|
||||
script.onload = function () {
|
||||
loadScript(i + 1);
|
||||
};
|
||||
head.appendChild(script);
|
||||
}
|
||||
var document = window.document.wrappedJSObject;
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
loadScript(0);
|
||||
}
|
||||
|
||||
function initScripts() {
|
||||
if (preview) {
|
||||
loadScripts(['resource://shumway/web/preview.js'], function () {
|
||||
window.wrappedJSObject.runSniffer();
|
||||
});
|
||||
} else {
|
||||
loadScripts(['resource://shumway/shumway.js',
|
||||
'resource://shumway/web/avm-sandbox.js'], function () {
|
||||
window.wrappedJSObject.runViewer();
|
||||
});
|
||||
}
|
||||
loadScripts(['resource://shumway/shumway.gfx.js',
|
||||
'resource://shumway/web/viewer.js'], function () {
|
||||
window.wrappedJSObject.runViewer();
|
||||
});
|
||||
}
|
||||
|
||||
window.wrappedJSObject.SHUMWAY_ROOT = "resource://shumway/";
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
Binary file not shown.
Binary file not shown.
127
browser/extensions/shumway/content/gfx/gl/shaders/blurh.frag
Normal file
127
browser/extensions/shumway/content/gfx/gl/shaders/blurh.frag
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
out vec4 FragmentColor;
|
||||
|
||||
uniform float offset[5] = float[]( 0.0, 1.0, 2.0, 3.0, 4.0 );
|
||||
uniform float weight[5] = float[]( 0.2270270270, 0.1945945946, 0.1216216216,
|
||||
0.0540540541, 0.0162162162 );
|
||||
|
||||
void main(void)
|
||||
{
|
||||
FragmentColor = texture2D( uSampler, vec2(vCoordinate) * weight[0];
|
||||
for (int i=1; i<5; i++) {
|
||||
FragmentColor +=
|
||||
texture2D( uSampler, ( vec2(gl_FragCoord)+vec2(0.0, offset[i]) )/1024.0 )
|
||||
* weight[i];
|
||||
FragmentColor +=
|
||||
texture2D( uSampler, ( vec2(gl_FragCoord)-vec2(0.0, offset[i]) )/1024.0 )
|
||||
* weight[i];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
const int sampleRadius = 16;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
float dy = 1.0 / 512.0;
|
||||
vec4 sample = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
sample += texture2D(uSampler, vCoordinate + vec2(0, float(i) * dy));
|
||||
}
|
||||
gl_FragColor = sample / float(samples);
|
||||
// gl_FragColor = texture2D(uSampler, vCoordinate);
|
||||
}
|
||||
*/
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
vec4 sum = vec4(0.0);
|
||||
float blur = 1.0 / 512.0 * 1.0;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0 * blur, vCoordinate.y)) * 0.05;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0 * blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0 * blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0 * blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0 * blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0 * blur, vCoordinate.y)) * 0.05;
|
||||
gl_FragColor = sum;
|
||||
// gl_FragColor = texture2D(uSampler, vCoordinate);
|
||||
}
|
||||
|
||||
/*
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
vec4 sum = vec4(0.0);
|
||||
float blur = 0.1;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0 * blur, vCoordinate.y)) * 0.05;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0 * blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0 * blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0 * blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0 * blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0 * blur, vCoordinate.y)) * 0.05;
|
||||
gl_FragColor = sum;
|
||||
// gl_FragColor = texture2D(uSampler, vCoordinate);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(uSampler, vCoordinate);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
precision mediump float;
|
||||
varying vec2 vCoordinate;
|
||||
varying float vColor;
|
||||
uniform float blur;
|
||||
uniform sampler2D uSampler;
|
||||
void main(void) {
|
||||
vec4 sum = vec4(0.0);
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0*blur, vCoordinate.y)) * 0.05;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0*blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0*blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0*blur, vCoordinate.y)) * 0.12;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0*blur, vCoordinate.y)) * 0.09;
|
||||
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0*blur, vCoordinate.y)) * 0.05;
|
||||
gl_FragColor = sum;
|
||||
}
|
||||
|
||||
*/
|
16
browser/extensions/shumway/content/gfx/gl/shaders/blurv.frag
Normal file
16
browser/extensions/shumway/content/gfx/gl/shaders/blurv.frag
Normal file
@ -0,0 +1,16 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
const int sampleRadius = 8;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
float dx = 0.01;
|
||||
vec4 sample = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
sample += texture2D(uSampler, vCoordinate + vec2(0, float(i) * dy));
|
||||
}
|
||||
gl_FragColor = sample / float(samples);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
uniform vec2 uResolution;
|
||||
uniform mat3 uTransformMatrix;
|
||||
uniform float uZ;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec4 aColor;
|
||||
attribute vec2 aCoordinate;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
|
||||
position *= vec2(1.0, -1.0);
|
||||
// position *= vec2(40.0, -4.0);
|
||||
gl_Position = vec4(vec3(position, uZ), 1.0);
|
||||
vColor = aColor;
|
||||
vCoordinate = aCoordinate;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform mat4 uColorMatrix;
|
||||
uniform vec4 uColorVector;
|
||||
uniform sampler2D uSampler[8];
|
||||
varying vec2 vCoordinate;
|
||||
varying float vKind;
|
||||
varying float vSampler;
|
||||
|
||||
void main() {
|
||||
vec4 color;
|
||||
int kind = int(floor(vKind + 0.5));
|
||||
if (kind == 0) {
|
||||
color = vColor;
|
||||
} else if (kind == 1 || kind == 2) {
|
||||
int sampler = int(floor(vSampler + 0.5));
|
||||
if (sampler == 0) {
|
||||
color = vColor * texture2D(uSampler[0], vCoordinate);
|
||||
} else if (sampler == 1) {
|
||||
color = vColor * texture2D(uSampler[1], vCoordinate);
|
||||
} else if (sampler == 2) {
|
||||
color = vColor * texture2D(uSampler[2], vCoordinate);
|
||||
} else if (sampler == 3) {
|
||||
color = vColor * texture2D(uSampler[3], vCoordinate);
|
||||
} else if (sampler == 4) {
|
||||
color = vColor * texture2D(uSampler[4], vCoordinate);
|
||||
} else if (sampler == 5) {
|
||||
color = vColor * texture2D(uSampler[5], vCoordinate);
|
||||
} else if (sampler == 6) {
|
||||
color = vColor * texture2D(uSampler[6], vCoordinate);
|
||||
} else if (sampler == 7) {
|
||||
color = vColor * texture2D(uSampler[7], vCoordinate);
|
||||
}
|
||||
if (kind == 2) {
|
||||
color = color * uColorMatrix + uColorVector;
|
||||
}
|
||||
} else {
|
||||
color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
// color.rgb *= color.a;
|
||||
if (color.a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
gl_FragColor = color;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
uniform vec2 uResolution;
|
||||
uniform mat3 uTransformMatrix;
|
||||
uniform mat4 uTransformMatrix3D;
|
||||
|
||||
attribute vec4 aPosition;
|
||||
attribute vec4 aColor;
|
||||
attribute vec2 aCoordinate;
|
||||
attribute float aKind;
|
||||
attribute float aSampler;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vCoordinate;
|
||||
varying float vKind;
|
||||
varying float vSampler;
|
||||
|
||||
void main() {
|
||||
gl_Position = uTransformMatrix3D * aPosition;
|
||||
vColor = aColor;
|
||||
vCoordinate = aCoordinate;
|
||||
vKind = aKind;
|
||||
vSampler = aSampler;
|
||||
}
|
18
browser/extensions/shumway/content/gfx/gl/shaders/curve.frag
Normal file
18
browser/extensions/shumway/content/gfx/gl/shaders/curve.frag
Normal file
@ -0,0 +1,18 @@
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 uColor;
|
||||
varying vec2 vTextureCoordinate;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = uColor;
|
||||
gl_FragColor = vec4(vTextureCoordinate.x, vTextureCoordinate.y, 0, 0.5);
|
||||
|
||||
float u = vTextureCoordinate.x;
|
||||
float v = vTextureCoordinate.y;
|
||||
float r = u * u - v;
|
||||
if (r < 0.0) {
|
||||
gl_FragColor = vec4(1, 0, 0, 1);
|
||||
} else {
|
||||
gl_FragColor = vec4(1, 0, 0, 0.2);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vColor;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
uniform vec2 uResolution;
|
||||
uniform mat3 uTransformMatrix;
|
||||
uniform float uZ;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec4 aColor;
|
||||
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
|
||||
position *= vec2(1.0, -1.0);
|
||||
gl_Position = vec4(vec3(position, uZ), 1.0);
|
||||
vColor = aColor;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform sampler2D uSampler;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
// gl_FragColor = vColor;
|
||||
// gl_FragColor = vec4(vTextureCoordinate.x, vTextureCoordinate.y, 0, 0.5);
|
||||
// gl_FragColor = gl_FragColor; // + texture2D(uSampler, vCoordinate);
|
||||
gl_FragColor = texture2D(uSampler, vCoordinate);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
uniform vec2 uResolution;
|
||||
uniform mat3 uTransformMatrix;
|
||||
uniform float uZ;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec4 aColor;
|
||||
attribute vec2 aCoordinate;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vCoordinate;
|
||||
|
||||
void main() {
|
||||
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
|
||||
position *= vec2(1.0, -1.0);
|
||||
// position *= vec2(40.0, -4.0);
|
||||
gl_Position = vec4(vec3(position, uZ), 1.0);
|
||||
vColor = aColor;
|
||||
vCoordinate = aCoordinate;
|
||||
}
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
16832
browser/extensions/shumway/content/shumway.gfx.js
Normal file
16832
browser/extensions/shumway/content/shumway.gfx.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
14133
browser/extensions/shumway/content/shumway.parser.js
Normal file
14133
browser/extensions/shumway/content/shumway.parser.js
Normal file
File diff suppressed because it is too large
Load Diff
67581
browser/extensions/shumway/content/shumway.player.js
Normal file
67581
browser/extensions/shumway/content/shumway.player.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
0.8.271
|
||||
2717b0c
|
||||
0.9.2697
|
||||
25bfcc9
|
||||
|
@ -1,219 +0,0 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
// Extenstion communication object
|
||||
var FirefoxCom = (function FirefoxComClosure() {
|
||||
return {
|
||||
/**
|
||||
* Creates an event that the extension is listening for and will
|
||||
* synchronously respond to.
|
||||
* NOTE: It is reccomended to use request() instead since one day we may not
|
||||
* be able to synchronously reply.
|
||||
* @param {String} action The action to trigger.
|
||||
* @param {String} data Optional data to send.
|
||||
* @return {*} The response.
|
||||
*/
|
||||
requestSync: function(action, data) {
|
||||
var request = document.createTextNode('');
|
||||
document.documentElement.appendChild(request);
|
||||
|
||||
var sender = document.createEvent('CustomEvent');
|
||||
sender.initCustomEvent('shumway.message', true, false,
|
||||
{action: action, data: data, sync: true});
|
||||
request.dispatchEvent(sender);
|
||||
var response = sender.detail.response;
|
||||
document.documentElement.removeChild(request);
|
||||
return response;
|
||||
},
|
||||
/**
|
||||
* Creates an event that the extension is listening for and will
|
||||
* asynchronously respond by calling the callback.
|
||||
* @param {String} action The action to trigger.
|
||||
* @param {String} data Optional data to send.
|
||||
* @param {Function} callback Optional response callback that will be called
|
||||
* with one data argument.
|
||||
*/
|
||||
request: function(action, data, callback) {
|
||||
var request = document.createTextNode('');
|
||||
request.setUserData('action', action, null);
|
||||
request.setUserData('data', data, null);
|
||||
request.setUserData('sync', false, null);
|
||||
if (callback) {
|
||||
request.setUserData('callback', callback, null);
|
||||
|
||||
document.addEventListener('shumway.response', function listener(event) {
|
||||
var node = event.target,
|
||||
response = event.detail.response;
|
||||
|
||||
document.documentElement.removeChild(node);
|
||||
|
||||
document.removeEventListener('shumway.response', listener, false);
|
||||
return callback(response);
|
||||
}, false);
|
||||
}
|
||||
document.documentElement.appendChild(request);
|
||||
|
||||
var sender = document.createEvent('CustomEvent');
|
||||
sender.initCustomEvent('shumway.message', true, false,
|
||||
{action: action, data: data, sync: false});
|
||||
return request.dispatchEvent(sender);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
function fallback() {
|
||||
FirefoxCom.requestSync('fallback', null)
|
||||
}
|
||||
|
||||
var BYTES_TO_LOAD = 32768;
|
||||
var BYTES_TO_PARSE = 32768;
|
||||
|
||||
function runSniffer() {
|
||||
var flashParams = JSON.parse(FirefoxCom.requestSync('getPluginParams', null));
|
||||
document.head.getElementsByTagName('base')[0].href = flashParams.baseUrl;
|
||||
movieUrl = flashParams.url;
|
||||
document.getElementById('playbutton').addEventListener('click', function() {
|
||||
switchToFullMode();
|
||||
});
|
||||
document.getElementById('fullmode').addEventListener('click', function() {
|
||||
switchToFullMode();
|
||||
return false;
|
||||
});
|
||||
document.getElementById('fallback').addEventListener('click', function() {
|
||||
fallback();
|
||||
return false;
|
||||
});
|
||||
FirefoxCom.requestSync('loadFile', {url: movieUrl, sessionId: 0, limit: BYTES_TO_LOAD});
|
||||
}
|
||||
|
||||
var subscription, movieUrl, buffers = [];;
|
||||
|
||||
addEventListener("message", function handlerMessage(e) {
|
||||
var args = e.data;
|
||||
switch (args.callback) {
|
||||
case "loadFile":
|
||||
if (args.sessionId != 0) {
|
||||
return;
|
||||
}
|
||||
switch (args.topic) {
|
||||
case "progress":
|
||||
buffers.push(args.array);
|
||||
break;
|
||||
case "error":
|
||||
console.error('Unable to download ' + movieUrl + ': ' + args.error);
|
||||
break;
|
||||
case "close":
|
||||
parseSwf();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
|
||||
function inflateData(bytes, outputLength) {
|
||||
verifyDeflateHeader(bytes);
|
||||
var stream = new Stream(bytes, 2);
|
||||
var output = {
|
||||
data: new Uint8Array(outputLength),
|
||||
available: 0,
|
||||
completed: false
|
||||
};
|
||||
var state = {};
|
||||
// inflate while we can
|
||||
try {
|
||||
do {
|
||||
inflateBlock(stream, output, state);
|
||||
} while (!output.completed && stream.pos < stream.end
|
||||
&& output.available < outputLength);
|
||||
} catch (e) {
|
||||
console.log('inflate aborted: ' + e);
|
||||
}
|
||||
return new Stream(output.data, 0, Math.min(output.available, outputLength));
|
||||
}
|
||||
|
||||
function parseSwf() {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < buffers.length; i++)
|
||||
sum += buffers[i].length;
|
||||
var data = new Uint8Array(sum), j = 0;
|
||||
for (var i = 0; i < buffers.length; i++) {
|
||||
data.set(buffers[i], j); j += buffers[i].length;
|
||||
}
|
||||
|
||||
var backgroundColor;
|
||||
try {
|
||||
var magic1 = data[0];
|
||||
var magic2 = data[1];
|
||||
var magic3 = data[2];
|
||||
if ((magic1 !== 70 && magic1 !== 67) || magic2 !== 87 || magic3 !== 83)
|
||||
throw new Error('unsupported file format');
|
||||
|
||||
var compressed = magic1 === 67;
|
||||
var stream = compressed ? inflateData(data.subarray(8), BYTES_TO_PARSE) :
|
||||
new Stream(data, 8, data.length - 8);
|
||||
var bytes = stream.bytes;
|
||||
|
||||
var SWF_TAG_CODE_SET_BACKGROUND_COLOR = 9;
|
||||
var PREFETCH_SIZE = 17 /* RECT */ +
|
||||
4 /* Frames rate and count */;;
|
||||
stream.ensure(PREFETCH_SIZE);
|
||||
var rectFieldSize = bytes[stream.pos] >> 3;
|
||||
stream.pos += ((5 + 4 * rectFieldSize + 7) >> 3) + 4; // skipping other header fields
|
||||
|
||||
// for now just sniffing background color
|
||||
while (stream.pos < stream.end &&
|
||||
!backgroundColor) {
|
||||
stream.ensure(2);
|
||||
var tagCodeAndLength = stream.getUint16(stream.pos, true);
|
||||
stream.pos += 2;
|
||||
var tagCode = tagCodeAndLength >> 6;
|
||||
var length = tagCodeAndLength & 0x3F;
|
||||
if (length == 0x3F) {
|
||||
stream.ensure(4);
|
||||
length = stream.getInt32(stream.pos, true);
|
||||
stream.pos += 4;
|
||||
if (length < 0) throw new Error('invalid length');
|
||||
}
|
||||
stream.ensure(length);
|
||||
switch (tagCode) {
|
||||
case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
|
||||
backgroundColor = 'rgb(' + bytes[stream.pos] + ', ' +
|
||||
bytes[stream.pos + 1] + ', ' +
|
||||
bytes[stream.pos + 2] + ')';
|
||||
break;
|
||||
}
|
||||
stream.pos += length;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('parsing aborted: ' + e);
|
||||
}
|
||||
if (backgroundColor) {
|
||||
document.body.style.backgroundColor = backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.keyCode == 119 && e.ctrlKey) { // Ctrl+F8
|
||||
window.location.replace("data:application/x-moz-playpreview;,application/x-shockwave-flash,full,paused=true");
|
||||
}
|
||||
}, false);
|
||||
|
||||
function switchToFullMode() {
|
||||
window.location.replace("data:application/x-moz-playpreview;,application/x-shockwave-flash,full");
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2013 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<base href=""/>
|
||||
|
||||
<script src="../lib/DataView.js/DataView.js"></script>
|
||||
|
||||
<!-- Load SWF Dependencies -->
|
||||
<script src="../flash/util.js"></script>
|
||||
<script src="../swf/inflate.js"></script>
|
||||
<script src="../swf/stream.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: rgba(128, 128, 128, 0.5);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
#screen {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
}
|
||||
#container {
|
||||
position: fixed;
|
||||
top: 50%; left: 0; right: 0; bottom: 50%;
|
||||
}
|
||||
#content {
|
||||
margin-top: -64px;
|
||||
text-align: center;
|
||||
}
|
||||
#playbutton {
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://global/skin/media/videoClickToPlayButton.svg);
|
||||
border: none 0px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
cursor: pointer;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#playbutton > span {
|
||||
overflow: hidden;
|
||||
width: 0px; height: 0px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 160px) , screen and (max-height: 160px) {
|
||||
#playbutton {
|
||||
display: none;
|
||||
}
|
||||
#content {
|
||||
margin-top: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
#screen {
|
||||
transition: opacity 0.5s linear;
|
||||
-webkit-transition: opacity 0.5s linear;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
#screen:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.shumwayButton {
|
||||
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9) );
|
||||
background:-moz-linear-gradient( center top, #f9f9f9 5%, #e9e9e9 100% );
|
||||
background-color:#f9f9f9;
|
||||
-moz-border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
border-radius:4px;
|
||||
border:1px solid #a0a0a0;
|
||||
display:inline-block;
|
||||
color:#666666;
|
||||
font-family:arial;
|
||||
font-size:11px;
|
||||
font-weight:bold;
|
||||
padding:6px 11px;
|
||||
text-decoration:none;
|
||||
text-shadow:1px 1px 0px #ffffff;
|
||||
width: 70px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.shumwayButton:hover {
|
||||
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9) );
|
||||
background:-moz-linear-gradient( center top, #e9e9e9 5%, #f9f9f9 100% );
|
||||
background-color:#e9e9e9;
|
||||
}
|
||||
.shumwayButton:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id='screen'>
|
||||
<div id='container'>
|
||||
<div id='content'>
|
||||
<button id='playbutton'><span>Play</span></button>
|
||||
<div id='toolbar'>
|
||||
<a class="shumwayButton" id="fullmode">Shumway</a>
|
||||
<a class="shumwayButton" id="fallback">Flash</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -31,7 +31,7 @@ limitations under the License.
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#viewer {
|
||||
#stageContainer {
|
||||
position:fixed !important;
|
||||
left:0;top:0;bottom:0;right:0;
|
||||
overflow: hidden;
|
||||
@ -80,6 +80,12 @@ limitations under the License.
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#playerWindow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 100px), screen and (max-height: 40px) {
|
||||
body.started #overlay {
|
||||
display: none;
|
||||
@ -89,7 +95,8 @@ limitations under the License.
|
||||
</head>
|
||||
|
||||
<body contextmenu="shumwayMenu">
|
||||
<div id="viewer"></div>
|
||||
<iframe id="playerWindow" width="9" height="9" src=""></iframe>
|
||||
<div id="stageContainer"></div>
|
||||
<section>
|
||||
<div id="overlay">
|
||||
<a id="fallback" href="#">Shumway <span class="icon">×</span></a>
|
||||
@ -97,7 +104,6 @@ limitations under the License.
|
||||
</div>
|
||||
<menu type="context" id="shumwayMenu">
|
||||
<menuitem label="Show URL" id="showURLMenu"></menuitem>
|
||||
<menuitem label="Copy Profile" id="copyProfileMenu"></menuitem>
|
||||
<menuitem label="Open in Inspector" id="inspectorMenu"></menuitem>
|
||||
<menuitem label="Report Problems" id="reportMenu"></menuitem>
|
||||
<menuitem label="Fallback to Flash" id="fallbackMenu" hidden></menuitem>
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
@ -22,7 +20,7 @@ var FirefoxCom = (function FirefoxComClosure() {
|
||||
/**
|
||||
* Creates an event that the extension is listening for and will
|
||||
* synchronously respond to.
|
||||
* NOTE: It is reccomended to use request() instead since one day we may not
|
||||
* NOTE: It is recommended to use request() instead since one day we may not
|
||||
* be able to synchronously reply.
|
||||
* @param {String} action The action to trigger.
|
||||
* @param {String} data Optional data to send.
|
||||
@ -80,14 +78,30 @@ function fallback() {
|
||||
FirefoxCom.requestSync('fallback', null)
|
||||
}
|
||||
|
||||
var playerglobalInfo = {
|
||||
window.print = function(msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
var viewerPlayerglobalInfo = {
|
||||
abcs: SHUMWAY_ROOT + "playerglobal/playerglobal.abcs",
|
||||
catalog: SHUMWAY_ROOT + "playerglobal/playerglobal.json"
|
||||
};
|
||||
|
||||
var builtinPath = SHUMWAY_ROOT + "avm2/generated/builtin/builtin.abc";
|
||||
var avm1Path = SHUMWAY_ROOT + "avm2/generated/avm1lib/avm1lib.abc";
|
||||
|
||||
var playerWindow;
|
||||
var playerWindowLoaded = new Promise(function(resolve) {
|
||||
var playerWindowIframe = document.getElementById("playerWindow");
|
||||
playerWindowIframe.addEventListener('load', function () {
|
||||
playerWindow = playerWindowIframe.contentWindow;
|
||||
resolve();
|
||||
});
|
||||
playerWindowIframe.src = 'resource://shumway/web/viewer.player.html';
|
||||
});
|
||||
|
||||
function runViewer() {
|
||||
var flashParams = JSON.parse(FirefoxCom.requestSync('getPluginParams', null));
|
||||
FileLoadingService.setBaseUrl(flashParams.baseUrl);
|
||||
|
||||
movieUrl = flashParams.url;
|
||||
if (!movieUrl) {
|
||||
@ -110,7 +124,9 @@ function runViewer() {
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
parseSwf(movieUrl, movieParams, objectParams);
|
||||
playerWindowLoaded.then(function () {
|
||||
parseSwf(movieUrl, movieParams, objectParams);
|
||||
});
|
||||
|
||||
if (isOverlay) {
|
||||
document.getElementById('overlay').className = 'enabled';
|
||||
@ -134,8 +150,6 @@ function runViewer() {
|
||||
inspectorMenu.addEventListener('click', showInInspector);
|
||||
var reportMenu = document.getElementById('reportMenu');
|
||||
reportMenu.addEventListener('click', reportIssue);
|
||||
|
||||
document.getElementById('copyProfileMenu').addEventListener('click', copyProfile);
|
||||
}
|
||||
|
||||
function showURL() {
|
||||
@ -171,152 +185,86 @@ function reportIssue() {
|
||||
FirefoxCom.requestSync('reportIssue', JSON.stringify(prunedExceptions));
|
||||
}
|
||||
|
||||
function copyProfile() {
|
||||
function toArray(v) {
|
||||
var array = [];
|
||||
for (var i = 0; i < v.length; i++) {
|
||||
array.push(v[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
var profile = {
|
||||
loops: {counts: toArray($L), lines: $LL},
|
||||
functions: {counts: toArray($F), lines: $FL},
|
||||
allocations: {counts: toArray($A), lines: $AL}
|
||||
};
|
||||
FirefoxCom.request('unsafeSetClipboard', JSON.stringify(profile));
|
||||
}
|
||||
|
||||
var movieUrl, movieParams, objectParams;
|
||||
|
||||
window.addEventListener("message", function handlerMessage(e) {
|
||||
var args = e.data;
|
||||
switch (args.callback) {
|
||||
case "loadFile":
|
||||
var session = FileLoadingService.sessions[args.sessionId];
|
||||
if (session) {
|
||||
session.notify(args);
|
||||
}
|
||||
case 'loadFile':
|
||||
playerWindow.postMessage({
|
||||
type: "loadFileResponse",
|
||||
args: args
|
||||
}, '*');
|
||||
break;
|
||||
case 'loadFileRequest':
|
||||
FirefoxCom.request('loadFile', args.data, null);
|
||||
break;
|
||||
case 'reportTelemetry':
|
||||
FirefoxCom.request('reportTelemetry', args.data, null);
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
|
||||
var TelemetryService = {
|
||||
reportTelemetry: function (data) {
|
||||
FirefoxCom.request('reportTelemetry', data, null);
|
||||
}
|
||||
};
|
||||
var easelHost;
|
||||
|
||||
var FileLoadingService = {
|
||||
get baseUrl() { return movieUrl; },
|
||||
nextSessionId: 1, // 0 - is reserved
|
||||
sessions: [],
|
||||
createSession: function () {
|
||||
var sessionId = this.nextSessionId++;
|
||||
return this.sessions[sessionId] = {
|
||||
open: function (request) {
|
||||
var self = this;
|
||||
var path = FileLoadingService.resolveUrl(request.url);
|
||||
console.log('Session #' + sessionId +': loading ' + path);
|
||||
FirefoxCom.requestSync('loadFile', {url: path, method: request.method,
|
||||
mimeType: request.mimeType, postData: request.data,
|
||||
checkPolicyFile: request.checkPolicyFile, sessionId: sessionId});
|
||||
},
|
||||
notify: function (args) {
|
||||
switch (args.topic) {
|
||||
case "open": this.onopen(); break;
|
||||
case "close":
|
||||
this.onclose();
|
||||
FileLoadingService.sessions[sessionId] = null;
|
||||
console.log('Session #' + sessionId +': closed');
|
||||
break;
|
||||
case "error":
|
||||
this.onerror && this.onerror(args.error);
|
||||
break;
|
||||
case "progress":
|
||||
console.log('Session #' + sessionId + ': loaded ' + args.loaded + '/' + args.total);
|
||||
this.onprogress && this.onprogress(args.array, {bytesLoaded: args.loaded, bytesTotal: args.total});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
setBaseUrl: function (url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url || '#';
|
||||
a.setAttribute('style', 'display: none;');
|
||||
document.body.appendChild(a);
|
||||
FileLoadingService.baseUrl = a.href;
|
||||
document.body.removeChild(a);
|
||||
},
|
||||
resolveUrl: function (url) {
|
||||
if (url.indexOf('://') >= 0) return url;
|
||||
|
||||
var base = FileLoadingService.baseUrl;
|
||||
base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
|
||||
if (url.indexOf('/') === 0) {
|
||||
var m = /^[^:]+:\/\/[^\/]+/.exec(base);
|
||||
if (m) base = m[0];
|
||||
}
|
||||
return base + url;
|
||||
function processExternalCommand(command) {
|
||||
switch (command.action) {
|
||||
case 'isEnabled':
|
||||
command.result = true;
|
||||
break;
|
||||
case 'initJS':
|
||||
FirefoxCom.initJS(function (functionName, args) {
|
||||
return easelHost.sendExernalCallback(functionName, args);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
command.result = FirefoxCom.requestSync('externalCom', command);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function parseSwf(url, movieParams, objectParams) {
|
||||
var enableVerifier = Shumway.AVM2.Runtime.enableVerifier;
|
||||
var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE;
|
||||
|
||||
var compilerSettings = JSON.parse(
|
||||
FirefoxCom.requestSync('getCompilerSettings', null));
|
||||
enableVerifier.value = compilerSettings.verifier;
|
||||
|
||||
// init misc preferences
|
||||
turboMode.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.turboMode', def: false});
|
||||
hud.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.hud', def: false});
|
||||
forceHidpi.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.force_hidpi', def: false});
|
||||
dummyAnimation.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.dummyMode', def: false});
|
||||
var turboMode = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.turboMode', def: false});
|
||||
Shumway.GFX.backend.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.webgl', def: false}) ? 1 : 0;
|
||||
Shumway.GFX.hud.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.hud', def: false});
|
||||
//forceHidpi.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.force_hidpi', def: false});
|
||||
//dummyAnimation.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.dummyMode', def: false});
|
||||
|
||||
console.log("Compiler settings: " + JSON.stringify(compilerSettings));
|
||||
console.log("Parsing " + url + "...");
|
||||
console.info("Compiler settings: " + JSON.stringify(compilerSettings));
|
||||
console.info("Parsing " + url + "...");
|
||||
function loaded() {
|
||||
FirefoxCom.request('endActivation', null);
|
||||
}
|
||||
|
||||
createAVM2(builtinPath, playerglobalInfo, avm1Path,
|
||||
compilerSettings.sysCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET,
|
||||
compilerSettings.appCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET,
|
||||
function (avm2) {
|
||||
console.time("Initialize Renderer");
|
||||
SWF.embed(url, document, document.getElementById("viewer"), {
|
||||
url: url,
|
||||
movieParams: movieParams,
|
||||
objectParams: objectParams,
|
||||
onComplete: loaded,
|
||||
onBeforeFrame: frame
|
||||
});
|
||||
});
|
||||
var easel = createEasel();
|
||||
easelHost = new Shumway.GFX.Window.WindowEaselHost(easel, playerWindow, window);
|
||||
easelHost.processExternalCommand = processExternalCommand;
|
||||
|
||||
var data = {
|
||||
type: 'runSwf',
|
||||
settings: Shumway.Settings.getSettings(),
|
||||
flashParams: {
|
||||
compilerSettings: compilerSettings,
|
||||
movieParams: movieParams,
|
||||
objectParams: objectParams,
|
||||
turboMode: turboMode,
|
||||
url: url,
|
||||
baseUrl: url
|
||||
}
|
||||
};
|
||||
playerWindow.postMessage(data, '*');
|
||||
}
|
||||
|
||||
var pauseExecution = false;
|
||||
var initializeFrameControl = true;
|
||||
function frame(e) {
|
||||
if (initializeFrameControl) {
|
||||
// marking that movie is started
|
||||
document.body.classList.add("started");
|
||||
function createEasel() {
|
||||
var Stage = Shumway.GFX.Stage;
|
||||
var Easel = Shumway.GFX.Easel;
|
||||
var Canvas2DStageRenderer = Shumway.GFX.Canvas2DStageRenderer;
|
||||
|
||||
TelemetryService.reportTelemetry({topic: "firstFrame"});
|
||||
|
||||
// skipping frame 0
|
||||
initializeFrameControl = false;
|
||||
return;
|
||||
}
|
||||
if (pauseExecution) {
|
||||
e.cancel = true;
|
||||
}
|
||||
Shumway.GFX.WebGL.SHADER_ROOT = SHUMWAY_ROOT + "gfx/gl/shaders/";
|
||||
var backend = Shumway.GFX.backend.value | 0;
|
||||
return new Easel(document.getElementById("stageContainer"), backend);
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.keyCode == 119 && e.ctrlKey) { // Ctrl+F8
|
||||
pauseExecution = !pauseExecution;
|
||||
}
|
||||
}, false);
|
30
browser/extensions/shumway/content/web/viewer.player.html
Normal file
30
browser/extensions/shumway/content/web/viewer.player.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2013 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<base href=""/>
|
||||
|
||||
<script src="../shumway.player.js"></script>
|
||||
<script src="viewerPlayer.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Shumway Player
|
||||
</body>
|
||||
</html>
|
174
browser/extensions/shumway/content/web/viewerPlayer.js
Normal file
174
browser/extensions/shumway/content/web/viewerPlayer.js
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var release = true;
|
||||
var SHUMWAY_ROOT = "resource://shumway/";
|
||||
|
||||
var viewerPlayerglobalInfo = {
|
||||
abcs: SHUMWAY_ROOT + "playerglobal/playerglobal.abcs",
|
||||
catalog: SHUMWAY_ROOT + "playerglobal/playerglobal.json"
|
||||
};
|
||||
|
||||
var avm2Root = SHUMWAY_ROOT + "avm2/";
|
||||
var builtinPath = avm2Root + "generated/builtin/builtin.abc";
|
||||
var avm1Path = avm2Root + "generated/avm1lib/avm1lib.abc";
|
||||
|
||||
window.print = function(msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
function runSwfPlayer(flashParams) {
|
||||
var EXECUTION_MODE = Shumway.AVM2.Runtime.ExecutionMode;
|
||||
|
||||
var compilerSettings = flashParams.compilerSettings;
|
||||
var sysMode = compilerSettings.sysCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET;
|
||||
var appMode = compilerSettings.appCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET;
|
||||
var asyncLoading = true;
|
||||
var baseUrl = flashParams.baseUrl;
|
||||
var movieParams = flashParams.movieParams;
|
||||
var objectParams = flashParams.objectParams;
|
||||
var movieUrl = flashParams.url;
|
||||
|
||||
Shumway.frameRateOption.value = flashParams.turboMode ? 60 : -1;
|
||||
Shumway.AVM2.Verifier.enabled.value = compilerSettings.verifier;
|
||||
|
||||
Shumway.createAVM2(builtinPath, viewerPlayerglobalInfo, avm1Path, sysMode, appMode, function (avm2) {
|
||||
function runSWF(file) {
|
||||
var player = new Shumway.Player.Window.WindowPlayer(window, window.parent);
|
||||
|
||||
Shumway.ExternalInterfaceService.instance = player.createExternalInterfaceService();
|
||||
|
||||
player.load(file);
|
||||
}
|
||||
file = Shumway.FileLoadingService.instance.setBaseUrl(baseUrl);
|
||||
if (asyncLoading) {
|
||||
runSWF(movieUrl);
|
||||
} else {
|
||||
new Shumway.BinaryFileReader(movieUrl).readAll(null, function(buffer, error) {
|
||||
if (!buffer) {
|
||||
throw "Unable to open the file " + file + ": " + error;
|
||||
}
|
||||
runSWF(movieUrl, buffer);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var LOADER_WORKER_PATH = SHUMWAY_ROOT + 'web/worker.js';
|
||||
|
||||
function setupServices() {
|
||||
Shumway.Telemetry.instance = {
|
||||
reportTelemetry: function (data) {
|
||||
window.parent.postMessage({
|
||||
callback: 'reportTelemetry',
|
||||
data: data
|
||||
}, '*');
|
||||
}
|
||||
};
|
||||
|
||||
Shumway.FileLoadingService.instance = {
|
||||
get baseUrl() {
|
||||
return movieUrl;
|
||||
},
|
||||
nextSessionId: 1, // 0 - is reserved
|
||||
sessions: [],
|
||||
createSession: function () {
|
||||
var sessionId = this.nextSessionId++;
|
||||
return this.sessions[sessionId] = {
|
||||
open: function (request) {
|
||||
var self = this;
|
||||
var path = Shumway.FileLoadingService.instance.resolveUrl(request.url);
|
||||
console.log('Session #' + sessionId + ': loading ' + path);
|
||||
window.parent.postMessage({
|
||||
callback: 'loadFileRequest',
|
||||
data: {url: path, method: request.method,
|
||||
mimeType: request.mimeType, postData: request.data,
|
||||
checkPolicyFile: request.checkPolicyFile, sessionId: sessionId}
|
||||
}, '*');
|
||||
},
|
||||
notify: function (args) {
|
||||
switch (args.topic) {
|
||||
case "open":
|
||||
this.onopen();
|
||||
break;
|
||||
case "close":
|
||||
this.onclose();
|
||||
Shumway.FileLoadingService.instance.sessions[sessionId] = null;
|
||||
console.log('Session #' + sessionId + ': closed');
|
||||
break;
|
||||
case "error":
|
||||
this.onerror && this.onerror(args.error);
|
||||
break;
|
||||
case "progress":
|
||||
console.log('Session #' + sessionId + ': loaded ' + args.loaded + '/' + args.total);
|
||||
this.onprogress && this.onprogress(args.array, {bytesLoaded: args.loaded, bytesTotal: args.total});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
setBaseUrl: function (url) {
|
||||
var baseUrl;
|
||||
if (typeof URL !== 'undefined') {
|
||||
baseUrl = new URL(url, document.location.href).href;
|
||||
} else {
|
||||
var a = document.createElement('a');
|
||||
a.href = url || '#';
|
||||
a.setAttribute('style', 'display: none;');
|
||||
document.body.appendChild(a);
|
||||
baseUrl = a.href;
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
Shumway.FileLoadingService.instance.baseUrl = baseUrl;
|
||||
return baseUrl;
|
||||
},
|
||||
resolveUrl: function (url) {
|
||||
if (url.indexOf('://') >= 0) return url;
|
||||
|
||||
var base = Shumway.FileLoadingService.instance.baseUrl;
|
||||
base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
|
||||
if (url.indexOf('/') === 0) {
|
||||
var m = /^[^:]+:\/\/[^\/]+/.exec(base);
|
||||
if (m) base = m[0];
|
||||
}
|
||||
return base + url;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener('message', function onWindowMessage(e) {
|
||||
var data = e.data;
|
||||
if (typeof data !== 'object' || data === null) {
|
||||
return;
|
||||
}
|
||||
switch (data.type) {
|
||||
case "loadFileResponse":
|
||||
var args = data.args;
|
||||
var session = Shumway.FileLoadingService.instance.sessions[args.sessionId];
|
||||
if (session) {
|
||||
session.notify(args);
|
||||
}
|
||||
break;
|
||||
case "runSwf":
|
||||
if (data.settings) {
|
||||
Shumway.Settings.setSettings(data.settings);
|
||||
}
|
||||
setupServices();
|
||||
runSwfPlayer(data.flashParams);
|
||||
document.body.style.backgroundColor = 'green';
|
||||
break;
|
||||
}
|
||||
}, true);
|
19
browser/extensions/shumway/content/web/worker.js
Normal file
19
browser/extensions/shumway/content/web/worker.js
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
importScripts(['../shumway.parser.js']);
|
||||
|
||||
var loader = new Shumway.SWF.ResourceLoader(this, true);
|
@ -51,6 +51,7 @@ pref("layers.componentalpha.enabled", false);
|
||||
pref("apz.touch_start_tolerance", "0.1"); // dpi * tolerance = pixel threshold
|
||||
pref("apz.pan_repaint_interval", 50); // prefer 20 fps
|
||||
pref("apz.fling_repaint_interval", 50); // prefer 20 fps
|
||||
pref("apz.smooth_scroll_repaint_interval", 50); // prefer 20 fps
|
||||
pref("apz.fling_stopped_threshold", "0.2");
|
||||
pref("apz.x_skate_size_multiplier", "2.5");
|
||||
pref("apz.y_skate_size_multiplier", "2.5");
|
||||
|
@ -13,6 +13,7 @@ browser.jar:
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
|
||||
skin/classic/browser/aboutSocialError.css
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
|
@ -5,6 +5,7 @@
|
||||
browser.jar:
|
||||
% skin browser classic/1.0 %skin/classic/browser/
|
||||
skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css)
|
||||
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
|
||||
|
1
browser/themes/shared/aboutNetError.css
Normal file
1
browser/themes/shared/aboutNetError.css
Normal file
@ -0,0 +1 @@
|
||||
/* This deliberately left empty for themes to use/override. */
|
@ -15,6 +15,7 @@ browser.jar:
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
|
||||
skin/classic/browser/aboutSocialError.css
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
@ -428,6 +429,7 @@ browser.jar:
|
||||
skin/classic/aero/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/aero/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/aero/browser/aboutCertError_sectionExpanded.png
|
||||
skin/classic/aero/browser/aboutNetError.css (../shared/aboutNetError.css)
|
||||
skin/classic/aero/browser/aboutSocialError.css
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/aero/browser/aboutSyncTabs.css
|
||||
|
56
build/autoconf/clang-plugin.m4
Normal file
56
build/autoconf/clang-plugin.m4
Normal file
@ -0,0 +1,56 @@
|
||||
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
||||
dnl License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
AC_DEFUN([MOZ_CONFIG_CLANG_PLUGIN], [
|
||||
|
||||
MOZ_ARG_ENABLE_BOOL(clang-plugin,
|
||||
[ --enable-clang-plugin Enable building with the mozilla clang plugin ],
|
||||
ENABLE_CLANG_PLUGIN=1,
|
||||
ENABLE_CLANG_PLUGIN= )
|
||||
if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||
if test -z "$CLANG_CC"; then
|
||||
AC_MSG_ERROR([Can't use clang plugin without clang.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for llvm-config])
|
||||
if test -z "$LLVMCONFIG"; then
|
||||
LLVMCONFIG=`which llvm-config`
|
||||
fi
|
||||
|
||||
if test -z "$LLVMCONFIG"; then
|
||||
LLVMCONFIG=`$CXX -print-prog-name=llvm-config`
|
||||
fi
|
||||
|
||||
if test ! -x "$LLVMCONFIG"; then
|
||||
AC_MSG_RESULT([not found])
|
||||
AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$LLVMCONFIG])
|
||||
|
||||
if test -z "$LLVMCONFIG"; then
|
||||
AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
|
||||
fi
|
||||
LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags`
|
||||
LLVM_LDFLAGS=`$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader | xargs`
|
||||
|
||||
if test "${OS_ARCH}" = "Darwin"; then
|
||||
CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization"
|
||||
CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis"
|
||||
CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex"
|
||||
CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers"
|
||||
else
|
||||
CLANG_LDFLAGS="-lclangASTMatchers"
|
||||
fi
|
||||
|
||||
AC_DEFINE(MOZ_CLANG_PLUGIN)
|
||||
fi
|
||||
|
||||
AC_SUBST(LLVM_CXXFLAGS)
|
||||
AC_SUBST(LLVM_LDFLAGS)
|
||||
AC_SUBST(CLANG_LDFLAGS)
|
||||
|
||||
AC_SUBST(ENABLE_CLANG_PLUGIN)
|
||||
|
||||
])
|
@ -2,58 +2,16 @@
|
||||
# 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/.
|
||||
|
||||
CXX := @CXX@
|
||||
CXXFLAGS := @CXXFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
VPATH := @srcdir@
|
||||
DSO_LDOPTS := @DSO_LDOPTS@
|
||||
DLL_SUFFIX := @DLL_SUFFIX@
|
||||
# LLVM_CXXFLAGS comes with its own optimization flags.
|
||||
MOZ_OPTIMIZE =
|
||||
|
||||
# Helper for end
|
||||
NULL :=
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
CPPSRCS := \
|
||||
clang-plugin.cpp \
|
||||
$(NULL)
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
TESTSRCS := \
|
||||
TestCustomHeap.cpp \
|
||||
TestMustOverride.cpp \
|
||||
TestNonHeapClass.cpp \
|
||||
TestStackClass.cpp \
|
||||
$(NULL)
|
||||
|
||||
OBJS := $(patsubst %.cpp,%.o,$(CPPSRCS))
|
||||
TESTS := $(patsubst %.cpp,test-%,$(TESTSRCS))
|
||||
|
||||
PLUGIN := libclang-plugin.$(DLL_SUFFIX)
|
||||
|
||||
all: $(PLUGIN) $(TESTS)
|
||||
|
||||
$(OBJS): %.o: %.cpp Makefile
|
||||
$(CXX) -o $@ -c $(CXXFLAGS) $<
|
||||
|
||||
$(PLUGIN): $(OBJS)
|
||||
rm -f $@
|
||||
$(CXX) $(DSO_LDOPTS) -o $@ $(CXXFLAGS) $(OBJS) $(LDFLAGS)
|
||||
|
||||
TESTFLAGS := -fsyntax-only -Xclang -verify \
|
||||
-Xclang -load -Xclang $(CURDIR)/$(PLUGIN) \
|
||||
-Xclang -add-plugin -Xclang moz-check
|
||||
|
||||
$(TESTS): test-%: tests/%.cpp $(PLUGIN)
|
||||
$(CXX) $(TESTFLAGS) $<
|
||||
|
||||
compile libs export tools: all
|
||||
|
||||
distclean clean:
|
||||
rm -f $(OBJS) $(TESTS) $(PLUGIN)
|
||||
|
||||
check:
|
||||
|
||||
libs: binaries
|
||||
|
||||
binaries: all
|
||||
@touch $@
|
||||
|
||||
.PHONY: compile libs export tools distclean clean check
|
||||
# In the current moz.build world, we need to override essentially every
|
||||
# variable to limit ourselves to what we need to build the clang plugin.
|
||||
OS_CXXFLAGS := $(LLVM_CXXFLAGS) -fno-rtti -fno-exceptions
|
||||
OS_COMPILE_CXXFLAGS :=
|
||||
OS_LDFLAGS := $(LLVM_LDFLAGS) $(CLANG_LDFLAGS)
|
||||
DSO_LDOPTS := -shared
|
||||
|
67
build/clang-plugin/configure
vendored
67
build/clang-plugin/configure
vendored
@ -1,67 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
PLATFORM=`uname`
|
||||
|
||||
# Default srcdir to this directory
|
||||
srcdir=$(dirname $0)
|
||||
|
||||
for option; do
|
||||
case "$option" in
|
||||
-*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
|
||||
*) optarg= ;;
|
||||
esac
|
||||
|
||||
case "$option" in
|
||||
--srcdir=*) srcdir="$optarg";;
|
||||
esac
|
||||
done
|
||||
|
||||
if test -z "$CXX"; then
|
||||
CXX=`which clang++`
|
||||
fi
|
||||
|
||||
echo -n "checking for llvm-config... "
|
||||
|
||||
if test -z "$LLVMCONFIG"; then
|
||||
LLVMCONFIG=`which llvm-config`
|
||||
fi
|
||||
|
||||
if test -z "$LLVMCONFIG"; then
|
||||
LLVMCONFIG=`dirname $CXX`/llvm-config
|
||||
fi
|
||||
|
||||
if test ! -x "$LLVMCONFIG"; then
|
||||
echo "configure: error: Cannot find an llvm-config binary for building a clang plugin" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$LLVMCONFIG"
|
||||
|
||||
LLVMLIBS="core mc analysis asmparser mcparser bitreader"
|
||||
LLVMCXXFLAGS=`$LLVMCONFIG --cxxflags`
|
||||
LLVMLDFLAGS=`$LLVMCONFIG --ldflags`
|
||||
LLVMLDFLAGS="$LLVMLDFLAGS `$LLVMCONFIG --libs $LLVMLIBS`"
|
||||
|
||||
if [ $PLATFORM == Darwin ]; then
|
||||
DSO_LDOPTS="-dynamiclib -shared"
|
||||
CLANGLDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization \
|
||||
-lclangParse -lclangSema -lclangAnalysis -lclangEdit -lclangAST \
|
||||
-lclangLex -lclangBasic -lclangASTMatchers"
|
||||
DLL_SUFFIX="dylib"
|
||||
else
|
||||
DSO_LDOPTS="-shared"
|
||||
CLANGLDFLAGS=-lclangASTMatchers
|
||||
DLL_SUFFIX="so"
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS $LLVMCXXFLAGS -fno-rtti -fno-exceptions"
|
||||
LDFLAGS="$LDFLAGS $LLVMLDFLAGS $CLANGLDFLAGS"
|
||||
|
||||
cat $srcdir/Makefile.in | sed \
|
||||
-e "s%@CXX@%$CXX%" \
|
||||
-e "s%@CXXFLAGS@%$CXXFLAGS%" \
|
||||
-e "s%@LDFLAGS@%$LDFLAGS%" \
|
||||
-e "s%@srcdir@%$srcdir%" \
|
||||
-e "s%@DSO_LDOPTS@%$DSO_LDOPTS%" \
|
||||
-e "s%@DLL_SUFFIX@%$DLL_SUFFIX%" \
|
||||
> Makefile
|
18
build/clang-plugin/moz.build
Normal file
18
build/clang-plugin/moz.build
Normal file
@ -0,0 +1,18 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
SharedLibrary('clang-plugin')
|
||||
|
||||
SOURCES += [
|
||||
'clang-plugin.cpp',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
DIRS += [
|
||||
'tests',
|
||||
]
|
14
build/clang-plugin/tests/Makefile.in
Normal file
14
build/clang-plugin/tests/Makefile.in
Normal file
@ -0,0 +1,14 @@
|
||||
# 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/.
|
||||
|
||||
# Build without any warning flags, and with clang verify flag for a
|
||||
# syntax-only build (no codegen).
|
||||
OS_CXXFLAGS := $(filter-out -W%,$(OS_CXXFLAGS)) -fsyntax-only -Xclang -verify
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
target:: $(OBJS)
|
||||
|
||||
# We don't actually build anything.
|
||||
.PHONY: $(OBJS)
|
15
build/clang-plugin/tests/moz.build
Normal file
15
build/clang-plugin/tests/moz.build
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
'TestCustomHeap.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestNonHeapClass.cpp',
|
||||
'TestStackClass.cpp',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
NO_VISIBILITY_FLAGS = True
|
@ -43,6 +43,8 @@ SEARCH_PATHS = [
|
||||
'xpcom/idl-parser',
|
||||
'testing',
|
||||
'testing/xpcshell',
|
||||
'testing/web-platform',
|
||||
'testing/web-platform/harness',
|
||||
'testing/marionette/client',
|
||||
'testing/marionette/client/marionette',
|
||||
'testing/marionette/transport',
|
||||
@ -80,6 +82,7 @@ MACH_MODULES = [
|
||||
'testing/mochitest/mach_commands.py',
|
||||
'testing/xpcshell/mach_commands.py',
|
||||
'testing/talos/mach_commands.py',
|
||||
'testing/web-platform/mach_commands.py',
|
||||
'testing/xpcshell/mach_commands.py',
|
||||
'tools/docs/mach_commands.py',
|
||||
'tools/mercurial/mach_commands.py',
|
||||
|
@ -3,6 +3,7 @@
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
NO_EXPAND_LIBS = 1
|
||||
ENABLE_CLANG_PLUGIN :=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -75,16 +75,14 @@ endif
|
||||
# TIERS (like for js/src).
|
||||
CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
|
||||
|
||||
# The compile tier has different rules from other tiers.
|
||||
ifeq ($(CURRENT_TIER),compile)
|
||||
|
||||
# Need a list of compile targets because we can't use pattern rules:
|
||||
# https://savannah.gnu.org/bugs/index.php?42833
|
||||
.PHONY: $(compile_targets)
|
||||
$(compile_targets):
|
||||
$(call SUBMAKE,$(@F),$(@D))
|
||||
|
||||
else
|
||||
# The compile tier has different rules from other tiers.
|
||||
ifneq ($(CURRENT_TIER),compile)
|
||||
|
||||
# Recursion rule for all directories traversed for all subtiers in the
|
||||
# current tier.
|
||||
@ -108,11 +106,6 @@ $(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CUR
|
||||
# nsinstall.py there.
|
||||
ifneq (,$(filter config/host, $(compile_targets)))
|
||||
$(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): config/host
|
||||
|
||||
# Ensure rules for config/host and its possible dependencies.
|
||||
.PHONY: $(filter %/host, $(compile_targets))
|
||||
$(filter %/host, $(compile_targets)):
|
||||
$(call SUBMAKE,host,$(@D))
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -163,3 +156,32 @@ endif # ifeq (.,$(DEPTH))
|
||||
recurse:
|
||||
@$(RECURSED_COMMAND)
|
||||
$(LOOP_OVER_DIRS)
|
||||
|
||||
ifeq (.,$(DEPTH))
|
||||
# Interdependencies for parallel export.
|
||||
js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
|
||||
accessible/xpcom/export: xpcom/xpidl/export
|
||||
ifdef ENABLE_CLANG_PLUGIN
|
||||
$(filter-out build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target
|
||||
build/clang-plugin/tests/target: build/clang-plugin/target
|
||||
endif
|
||||
|
||||
# Interdependencies that moz.build world don't know about yet for compilation.
|
||||
# Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3)
|
||||
toolkit/library/target: widget/gtk/mozgtk/gtk3/target
|
||||
endif
|
||||
ifdef MOZ_LDAP_XPCOM
|
||||
ldap/target: config/external/nss/target mozglue/build/target
|
||||
toolkit/library/target: ldap/target
|
||||
endif
|
||||
ifndef MOZ_FOLD_LIBS
|
||||
ifndef MOZ_NATIVE_SQLITE
|
||||
config/external/nss/target: db/sqlite3/src/target
|
||||
endif
|
||||
endif
|
||||
ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
|
||||
mozglue/build/target: memory/replace/dummy/target
|
||||
endif
|
||||
|
||||
endif
|
||||
|
18
configure.in
18
configure.in
@ -7250,18 +7250,7 @@ dnl ========================================================
|
||||
dnl = Enable using the clang plugin to build
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_ENABLE_BOOL(clang-plugin,
|
||||
[ --enable-clang-plugin Enable building with the mozilla clang plugin ],
|
||||
ENABLE_CLANG_PLUGIN=1,
|
||||
ENABLE_CLANG_PLUGIN= )
|
||||
if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||
if test -z "$CLANG_CC"; then
|
||||
AC_MSG_ERROR([Can't use clang plugin without clang.])
|
||||
fi
|
||||
AC_DEFINE(MOZ_CLANG_PLUGIN)
|
||||
fi
|
||||
|
||||
AC_SUBST(ENABLE_CLANG_PLUGIN)
|
||||
MOZ_CONFIG_CLANG_PLUGIN
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable stripping of libs & executables
|
||||
@ -9112,11 +9101,6 @@ HOST_CXXFLAGS="$_SUBDIR_HOST_CXXFLAGS"
|
||||
HOST_LDFLAGS="$_SUBDIR_HOST_LDFLAGS"
|
||||
RC=
|
||||
|
||||
if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
AC_OUTPUT_SUBDIRS(build/clang-plugin)
|
||||
fi
|
||||
|
||||
# Run the SpiderMonkey 'configure' script.
|
||||
dist=$MOZ_BUILD_ROOT/dist
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
|
@ -6396,10 +6396,11 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
||||
NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(aDocument->GetWindow()))) {
|
||||
return true;
|
||||
}
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
// We can use the junk scope here, because we're just using it for
|
||||
// regexp evaluation, not actual script execution.
|
||||
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope());
|
||||
|
||||
// The pattern has to match the entire value.
|
||||
aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
|
||||
|
@ -2004,6 +2004,7 @@ GK_ATOM(ondataavailable, "ondataavailable")
|
||||
GK_ATOM(onwarning, "onwarning")
|
||||
GK_ATOM(onstart, "onstart")
|
||||
GK_ATOM(onstop, "onstop")
|
||||
GK_ATOM(onphoto, "onphoto")
|
||||
#ifdef MOZ_GAMEPAD
|
||||
GK_ATOM(ongamepadbuttondown, "ongamepadbuttondown")
|
||||
GK_ATOM(ongamepadbuttonup, "ongamepadbuttonup")
|
||||
|
@ -1111,8 +1111,7 @@ nsXMLHttpRequest::Status()
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t readyState;
|
||||
GetReadyState(&readyState);
|
||||
uint16_t readyState = ReadyState();
|
||||
if (readyState == UNSENT || readyState == OPENED) {
|
||||
return 0;
|
||||
}
|
||||
@ -1136,14 +1135,8 @@ nsXMLHttpRequest::Status()
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
if (!httpChannel) {
|
||||
|
||||
// Let's simulate the http protocol for jar/app requests:
|
||||
nsCOMPtr<nsIJARChannel> jarChannel = GetCurrentJARChannel();
|
||||
if (jarChannel) {
|
||||
return 200; // Ok
|
||||
}
|
||||
|
||||
return 0;
|
||||
// Pretend like we got a 200 response, since our load was successful
|
||||
return 200;
|
||||
}
|
||||
|
||||
uint32_t status;
|
||||
@ -1159,32 +1152,34 @@ IMPL_CSTRING_GETTER(GetStatusText)
|
||||
void
|
||||
nsXMLHttpRequest::GetStatusText(nsCString& aStatusText)
|
||||
{
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
|
||||
// Return an empty status text on all error loads.
|
||||
aStatusText.Truncate();
|
||||
|
||||
if (!httpChannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we don't leak status information from denied cross-site
|
||||
// requests.
|
||||
if (IsDeniedCrossSiteRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check the current XHR state to see if it is valid to obtain the statusText
|
||||
// value. This check is to prevent the status text for redirects from being
|
||||
// available before all the redirects have been followed and HTTP headers have
|
||||
// been received.
|
||||
uint16_t readyState;
|
||||
GetReadyState(&readyState);
|
||||
if (readyState != OPENED && readyState != UNSENT) {
|
||||
httpChannel->GetResponseStatusText(aStatusText);
|
||||
uint16_t readyState = ReadyState();
|
||||
if (readyState == UNSENT || readyState == OPENED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mErrorLoad) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
if (httpChannel) {
|
||||
httpChannel->GetResponseStatusText(aStatusText);
|
||||
} else {
|
||||
aStatusText.AssignLiteral("OK");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -23,7 +23,7 @@ function testFile(file, contents, test) {
|
||||
// Load file using URL.createObjectURL and XMLHttpRequest
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("GET", URL.createObjectURL(file));
|
||||
xhr.onload = getXHRLoadHandler(contents, contents.length, false,
|
||||
xhr.onload = getXHRLoadHandler(contents, contents.length,
|
||||
"XMLHttpRequest load of " + test);
|
||||
xhr.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
xhr.send();
|
||||
@ -59,7 +59,7 @@ function testFile(file, contents, test) {
|
||||
"request content-length in XMLHttpRequest send of " + test);
|
||||
};
|
||||
xhr.addEventListener("load",
|
||||
getXHRLoadHandler(contents, contents.length, true,
|
||||
getXHRLoadHandler(contents, contents.length,
|
||||
"XMLHttpRequest send of " + test),
|
||||
false);
|
||||
xhr.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
@ -88,18 +88,12 @@ function getFileReaderLoadHandler(expectedResult, expectedLength, testName) {
|
||||
}
|
||||
}
|
||||
|
||||
function getXHRLoadHandler(expectedResult, expectedLength, statusWorking, testName) {
|
||||
function getXHRLoadHandler(expectedResult, expectedLength, testName) {
|
||||
return function (event) {
|
||||
is(event.target.readyState, 4,
|
||||
"[XHR] readyState in test " + testName);
|
||||
if (statusWorking) {
|
||||
is(event.target.status, 200,
|
||||
"[XHR] no error in test " + testName);
|
||||
}
|
||||
else {
|
||||
todo_is(event.target.status, 200,
|
||||
"[XHR] no error in test " + testName);
|
||||
}
|
||||
is(event.target.status, 200,
|
||||
"[XHR] no error in test " + testName);
|
||||
// Do not use |is(convertXHRBinary(event.target.responseText), expectedResult, "...");| that may output raw binary data.
|
||||
var convertedData = convertXHRBinary(event.target.responseText);
|
||||
is(convertedData.length, expectedResult.length,
|
||||
|
@ -558,6 +558,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||
run-if = os == 'linux'
|
||||
[test_bug1008126.html]
|
||||
run-if = os == 'linux'
|
||||
[test_bug1057176.html]
|
||||
[test_caretPositionFromPoint.html]
|
||||
[test_classList.html]
|
||||
# This test fails on the Mac for some reason
|
||||
|
@ -22,23 +22,33 @@ function runTests() {
|
||||
|
||||
var path = "/tests/content/base/test/";
|
||||
|
||||
var passFiles = [['file_XHR_pass1.xml', 'GET', 200, 'text/xml'],
|
||||
['file_XHR_pass2.txt', 'GET', 200, 'text/plain'],
|
||||
['file_XHR_pass3.txt', 'GET', 200, 'text/plain'],
|
||||
['data:text/xml,%3Cres%3Ehello%3C/res%3E%0A', 'GET', 0, 'text/xml'],
|
||||
['data:text/plain,hello%20pass%0A', 'GET', 0, 'text/plain'],
|
||||
['data:,foo', 'GET', 0, 'text/plain;charset=US-ASCII', 'foo'],
|
||||
['data:text/plain;base64,Zm9v', 'GET', 0, 'text/plain', 'foo'],
|
||||
['data:text/plain,foo#bar', 'GET', 0, 'text/plain', 'foo'],
|
||||
['data:text/plain,foo%23bar', 'GET', 0, 'text/plain', 'foo#bar'],
|
||||
var passFiles = [['file_XHR_pass1.xml', 'GET', 200, 'OK', 'text/xml'],
|
||||
['file_XHR_pass2.txt', 'GET', 200, 'OK', 'text/plain'],
|
||||
['file_XHR_pass3.txt', 'GET', 200, 'OK', 'text/plain'],
|
||||
['data:text/xml,%3Cres%3Ehello%3C/res%3E%0A', 'GET', 200, 'OK', 'text/xml'],
|
||||
['data:text/plain,hello%20pass%0A', 'GET', 200, 'OK', 'text/plain'],
|
||||
['data:,foo', 'GET', 200, 'OK', 'text/plain;charset=US-ASCII', 'foo'],
|
||||
['data:text/plain;base64,Zm9v', 'GET', 200, 'OK', 'text/plain', 'foo'],
|
||||
['data:text/plain,foo#bar', 'GET', 200, 'OK', 'text/plain', 'foo'],
|
||||
['data:text/plain,foo%23bar', 'GET', 200, 'OK', 'text/plain', 'foo#bar'],
|
||||
];
|
||||
|
||||
var blob = new Blob(["foo"], { type: "text/plain" });
|
||||
var blobURL = URL.createObjectURL(blob);
|
||||
|
||||
passFiles.push([blobURL, 'GET', 200, 'OK', 'text/plain', 'foo']);
|
||||
|
||||
var failFiles = [['//example.com' + path + 'file_XHR_pass1.xml', 'GET'],
|
||||
['ftp://localhost' + path + 'file_XHR_pass1.xml', 'GET'],
|
||||
['file_XHR_fail1.txt', 'GET'],
|
||||
];
|
||||
|
||||
for (i = 0; i < passFiles.length; ++i) {
|
||||
// Function to give our hacked is() a scope
|
||||
(function(oldIs) {
|
||||
function is(actual, expected, message) {
|
||||
oldIs(actual, expected, message + " for " + passFiles[i][0]);
|
||||
}
|
||||
xhr = new XMLHttpRequest();
|
||||
is(xhr.getResponseHeader("Content-Type"), null, "should be null");
|
||||
is(xhr.getAllResponseHeaders(), "", "should be empty string");
|
||||
@ -46,21 +56,25 @@ for (i = 0; i < passFiles.length; ++i) {
|
||||
xhr.open(passFiles[i][1], passFiles[i][0], false);
|
||||
xhr.send(null);
|
||||
is(xhr.status, passFiles[i][2], "wrong status");
|
||||
is(xhr.getResponseHeader("Content-Type"), passFiles[i][3], "wrong content type");
|
||||
is(xhr.statusText, passFiles[i][3], "wrong statusText");
|
||||
is(xhr.getResponseHeader("Content-Type"), passFiles[i][4], "wrong content type");
|
||||
var headers = xhr.getAllResponseHeaders();
|
||||
ok(/(?:^|\n)Content-Type:\s*([^\r\n]*)\r\n/i.test(headers) &&
|
||||
RegExp.$1 === passFiles[i][3], "wrong response headers");
|
||||
RegExp.$1 === passFiles[i][4], "wrong response headers");
|
||||
if (xhr.responseXML) {
|
||||
is((new XMLSerializer()).serializeToString(xhr.responseXML.documentElement),
|
||||
passFiles[i][4] || "<res>hello</res>", "wrong responseXML");
|
||||
is(xhr.response, passFiles[i][4] || "<res>hello</res>\n", "wrong response");
|
||||
passFiles[i][5] || "<res>hello</res>", "wrong responseXML");
|
||||
is(xhr.response, passFiles[i][5] || "<res>hello</res>\n", "wrong response");
|
||||
}
|
||||
else {
|
||||
is(xhr.responseText, passFiles[i][4] || "hello pass\n", "wrong responseText");
|
||||
is(xhr.response, passFiles[i][4] || "hello pass\n", "wrong response");
|
||||
is(xhr.responseText, passFiles[i][5] || "hello pass\n", "wrong responseText");
|
||||
is(xhr.response, passFiles[i][5] || "hello pass\n", "wrong response");
|
||||
}
|
||||
})(is);
|
||||
}
|
||||
|
||||
URL.revokeObjectURL(blobURL);
|
||||
|
||||
for (i = 0; i < failFiles.length; ++i) {
|
||||
xhr = new XMLHttpRequest();
|
||||
var didthrow = false;
|
||||
|
32
content/base/test/test_bug1057176.html
Normal file
32
content/base/test/test_bug1057176.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1057176
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1057176</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1057176 **/
|
||||
var doc = document.implementation.createDocument(null, null);
|
||||
var elem = doc.createElementNS("http://www.w3.org/1999/xhtml", "input");
|
||||
elem.pattern = "abc";
|
||||
elem.value = "def";
|
||||
ok(!elem.validity.valid, '"def" should not match the pattern "abc"');
|
||||
elem.value = "abc";
|
||||
ok(elem.validity.valid, '"abc" should match the pattern "abc"');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1057176">Mozilla Bug 1057176</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -541,17 +541,49 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
|
||||
}
|
||||
|
||||
// Encoder callback when encoding is complete.
|
||||
class EncodeCallback : public EncodeCompleteCallback
|
||||
{
|
||||
public:
|
||||
EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback)
|
||||
: mGlobal(aGlobal)
|
||||
, mFileCallback(aCallback) {}
|
||||
|
||||
// This is called on main thread.
|
||||
nsresult ReceiveBlob(already_AddRefed<DOMFile> aBlob)
|
||||
{
|
||||
nsRefPtr<DOMFile> blob = aBlob;
|
||||
uint64_t size;
|
||||
nsresult rv = blob->GetSize(&size);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(mGlobal);
|
||||
JS_updateMallocCounter(jsapi.cx(), size);
|
||||
}
|
||||
|
||||
mozilla::ErrorResult error;
|
||||
mFileCallback->Call(blob, error);
|
||||
|
||||
mGlobal = nullptr;
|
||||
mFileCallback = nullptr;
|
||||
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsRefPtr<FileCallback> mFileCallback;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
nsRefPtr<EncodeCompleteCallback> callback = new EncodeCallback(global, &aCallback);
|
||||
aRv = ImageEncoder::ExtractDataAsync(type,
|
||||
params,
|
||||
usingCustomParseOptions,
|
||||
imageBuffer,
|
||||
format,
|
||||
GetSize(),
|
||||
mCurrentContext,
|
||||
global,
|
||||
aCallback);
|
||||
callback);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user