Merge mozilla-central to b2g-inbound a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-07-17 16:47:32 +02:00
Родитель 86e789ebf7 005b9f88a5
Коммит 26bf315c56
473 изменённых файлов: 7105 добавлений и 3305 удалений

Просмотреть файл

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1038799 - And be wary of your ccache too.
Clobber to work around bug 959928.

Просмотреть файл

@ -29,8 +29,9 @@ XPCOMUtils.defineLazyModuleGetter(this, 'States',
this.EXPORTED_SYMBOLS = ['EventManager'];
this.EventManager = function EventManager(aContentScope) {
this.EventManager = function EventManager(aContentScope, aContentControl) {
this.contentScope = aContentScope;
this.contentControl = aContentControl;
this.addEventListener = this.contentScope.addEventListener.bind(
this.contentScope);
this.removeEventListener = this.contentScope.removeEventListener.bind(
@ -99,7 +100,7 @@ this.EventManager.prototype = {
{
let attempts = 0;
let delta = aEvent.deltaX || aEvent.deltaY;
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
null,
{ moveMethod: delta > 0 ? 'moveNext' : 'movePrevious',
onScreenOnly: true, noOpIfOnScreen: true, delay: 500 });
@ -183,7 +184,7 @@ this.EventManager.prototype = {
}
case Events.SCROLLING_START:
{
this.contentScope.contentControl.autoMove(aEvent.accessible);
this.contentControl.autoMove(aEvent.accessible);
break;
}
case Events.TEXT_CARET_MOVED:
@ -254,7 +255,7 @@ this.EventManager.prototype = {
if (vc.position &&
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
Utils.isInSubtree(vc.position, aEvent.accessible))) {
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
evt.targetPrevSibling || evt.targetParent,
{ moveToFocused: true, delay: 500 });
}
@ -279,19 +280,19 @@ this.EventManager.prototype = {
let acc = aEvent.accessible;
let doc = aEvent.accessibleDocument;
if (acc.role != Roles.DOCUMENT && doc.role != Roles.CHROME_WINDOW) {
this.contentScope.contentControl.autoMove(acc);
this.contentControl.autoMove(acc);
}
break;
}
case Events.DOCUMENT_LOAD_COMPLETE:
{
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
aEvent.accessible, { delay: 500 });
break;
}
case Events.VALUE_CHANGE:
{
let position = this.contentScope.contentControl.vc.position;
let position = this.contentControl.vc.position;
let target = aEvent.accessible;
if (position === target ||
Utils.getEmbeddedControl(position) === target) {

Просмотреть файл

@ -140,16 +140,16 @@ addMessageListener(
addMessageListener('AccessFu:Scroll', scroll);
addMessageListener('AccessFu:AdjustRange', adjustRange);
if (!eventManager) {
eventManager = new EventManager(this);
}
eventManager.start();
if (!contentControl) {
contentControl = new ContentControl(this);
}
contentControl.start();
if (!eventManager) {
eventManager = new EventManager(this, contentControl);
}
eventManager.start();
sendAsyncMessage('AccessFu:ContentStarted');
});

Просмотреть файл

@ -124,14 +124,9 @@ else # MOZ_WIDGET_TOOLKIT != cocoa
libs::
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY)
endif
ifndef SKIP_COPY_XULRUNNER
ifdef LIBXUL_SDK
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
endif
endif # SKIP_COPY_XULRUNNER
$(NSINSTALL) -D $(DIST)/bin/chrome/icons/default
# Copy the app icon for b2g-desktop

Просмотреть файл

@ -473,17 +473,6 @@ pref("services.push.adaptive.gap", 60000); // 1 minute
pref("services.push.adaptive.upperLimit", 1740000); // 29 min
// enable udp wakeup support
pref("services.push.udp.wakeupEnabled", true);
// This value should be the prefix to be added to the current PDP context[1]
// domain or a full-qualified domain name.
// If finished with a dot, it will be added as a prefix to the PDP context
// domain. If not, will be used as the DNS query.
// If the DNS query is unsuccessful, the push agent will send a null netid and
// is a server decision what to do with the device. If the MCC-MNC identifies a
// unique network the server will change to UDP mode. Otherwise, a websocket
// connection will be maintained.
// [1] Packet Data Protocol
// http://en.wikipedia.org/wiki/GPRS_core_network#PDP_context
pref("services.push.udp.well-known_netidAddress", "_wakeup_.");
// NetworkStats
#ifdef MOZ_WIDGET_GONK

Просмотреть файл

@ -10,4 +10,5 @@ support-files =
[test_filepicker_path.html]
[test_permission_deny.html]
[test_permission_gum_remember.html]
skip-if = (toolkit == 'gonk' && debug) # Bug 1019572 - debug-only timeout
[test_systemapp.html]

Просмотреть файл

@ -135,7 +135,6 @@ tools repackage:: $(PROGRAM)
endif
ifdef LIBXUL_SDK #{
ifndef SKIP_COPY_XULRUNNER #{
libs::
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{
rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(dist_dest)/Contents/Frameworks
@ -143,5 +142,4 @@ else
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
endif #} cocoa
endif #} SKIP_COPY_XULRUNNER
endif #} LIBXUL_SDK

Просмотреть файл

@ -1519,6 +1519,7 @@ pref("loop.enabled", false);
#endif
pref("loop.server", "https://loop.services.mozilla.com");
pref("loop.seenToS", "unseen");
pref("loop.do_not_disturb", false);
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
@ -1606,3 +1607,6 @@ pref("experiments.manifest.certs.1.commonName", "*.cdn.mozilla.net");
pref("experiments.manifest.certs.1.issuerName", "CN=Cybertrust Public SureServer SV CA,O=Cybertrust Inc");
// Whether experiments are supported by the current application profile.
pref("experiments.supported", true);
// Enable the OpenH264 plugin support in the addon manager.
pref("media.openh264.providerEnabled", true);

Просмотреть файл

@ -578,12 +578,18 @@ SocialShare = {
}
},
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(0);
},
onShowing: function() {
this.anchor.setAttribute("open", "true");
this.iframe.addEventListener("click", this._onclick, true);
},
onHidden: function() {
this.anchor.removeAttribute("open");
this.iframe.removeEventListener("click", this._onclick, true);
this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
this.currentShare = null;
},
@ -704,10 +710,13 @@ SocialShare = {
let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
}
};
SocialSidebar = {
_openStartTime: 0,
// Whether the sidebar can be shown for this window.
get canShow() {
if (!SocialUI.enabled || document.mozFullScreen)
@ -780,6 +789,11 @@ SocialSidebar = {
"hidden": broadcaster.hidden,
"origin": sidebarOrigin
};
if (broadcaster.hidden) {
Services.telemetry.getHistogramById("SOCIAL_SIDEBAR_OPEN_DURATION").add(Date.now() / 1000 - this._openStartTime);
} else {
this._openStartTime = Date.now() / 1000;
}
// Save a global state for users who do not restore state.
if (broadcaster.hidden)
@ -877,11 +891,16 @@ SocialSidebar = {
this._updateCheckedMenuItems(this.opened && this.provider ? this.provider.origin : null);
},
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(3);
},
_loadListener: function SocialSidebar_loadListener() {
let sbrowser = document.getElementById("social-sidebar-browser");
sbrowser.removeEventListener("load", SocialSidebar._loadListener, true);
document.getElementById("social-sidebar-button").removeAttribute("loading");
SocialSidebar.setSidebarVisibilityState(true);
sbrowser.addEventListener("click", SocialSidebar._onclick, true);
},
unloadSidebar: function SocialSidebar_unloadSidebar() {
@ -889,6 +908,7 @@ SocialSidebar = {
if (!sbrowser.hasAttribute("origin"))
return;
sbrowser.removeEventListener("click", SocialSidebar._onclick, true);
sbrowser.stop();
sbrowser.removeAttribute("origin");
sbrowser.setAttribute("src", "about:blank");
@ -989,6 +1009,7 @@ SocialSidebar = {
else
SocialSidebar.update();
this.saveWindowState();
Services.telemetry.getHistogramById("SOCIAL_SIDEBAR_STATE").add(true);
},
hide: function() {
@ -998,6 +1019,7 @@ SocialSidebar = {
this.clearProviderMenus();
SocialSidebar.update();
this.saveWindowState();
Services.telemetry.getHistogramById("SOCIAL_SIDEBAR_STATE").add(false);
},
toggleSidebar: function SocialSidebar_toggle() {
@ -1219,13 +1241,29 @@ SocialStatus = {
}
},
_onclose: function() {
let notificationFrameId = "social-status-" + origin;
let frame = document.getElementById(notificationFrameId);
frame.removeEventListener("close", this._onclose, true);
frame.removeEventListener("click", this._onclick, true);
},
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(1);
},
showPopup: function(aToolbarButton) {
// attach our notification panel if necessary
let origin = aToolbarButton.getAttribute("origin");
let provider = Social._getProviderFromOrigin(origin);
PanelFrame.showPopup(window, PanelUI, aToolbarButton, "social", origin,
provider.statusURL, provider.getPageSize("status"));
provider.statusURL, provider.getPageSize("status"),
(frame) => {
frame.addEventListener("close", this._onclose, true);
frame.addEventListener("click", this._onclick, true);
});
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(1);
},
setPanelErrorMessage: function(aNotificationFrame) {

Просмотреть файл

@ -540,7 +540,7 @@ var gPopupBlockerObserver = {
// xxxdz this should make the option say "Show file picker" and do it (Bug 590306)
if (!blockedPopup.popupWindowURI)
continue;
var popupURIspec = blockedPopup.popupWindowURI;
var popupURIspec = blockedPopup.popupWindowURI.spec;
// Sometimes the popup URI that we get back from the blockedPopup
// isn't useful (for instance, netscape.com's popup URI ends up
@ -5133,14 +5133,14 @@ function handleLinkClick(event, href, linkNode) {
// if the mixedContentChannel is present and the referring URI passes
// a same origin check with the target URI, we can preserve the users
// decision of disabling MCB on a page for it's child tabs.
var persistDisableMCBInChildTab = false;
var persistAllowMixedContentInChildTab = false;
if (where == "tab" && gBrowser.docShell.mixedContentChannel) {
const sm = Services.scriptSecurityManager;
try {
var targetURI = makeURI(href);
sm.checkSameOriginURI(referrerURI, targetURI, false);
persistDisableMCBInChildTab = true;
persistAllowMixedContentInChildTab = true;
}
catch (e) { }
}
@ -5148,7 +5148,7 @@ function handleLinkClick(event, href, linkNode) {
urlSecurityCheck(href, doc.nodePrincipal);
openLinkIn(href, where, { referrerURI: referrerURI,
charset: doc.characterSet,
disableMCB: persistDisableMCBInChildTab});
allowMixedContent: persistAllowMixedContentInChildTab });
event.preventDefault();
return true;
}

Просмотреть файл

@ -563,8 +563,7 @@
#endif
#endif
context="toolbar-context-menu">
<toolbaritem id="menubar-items" align="center"
cui-areatype="toolbar">
<toolbaritem id="menubar-items" align="center">
# The entire main menubar is placed into browser-menubar.inc, so that it can be shared by
# hiddenWindow.xul.
#include browser-menubar.inc
@ -601,7 +600,6 @@
flex="1"
setfocus="false"
tooltip="tabbrowser-tab-tooltip"
cui-areatype="toolbar"
stopwatchid="FX_TAB_CLICK_MS">
<tab class="tabbrowser-tab" selected="true" fadein="true"/>
</tabs>
@ -682,12 +680,10 @@
<hbox id="nav-bar-customization-target" flex="1">
<toolbaritem id="urlbar-container" flex="400" persist="width"
title="&locationItem.title;" removable="false"
cui-areatype="toolbar"
class="chromeclass-location" overflows="false">
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&backCmd.label;"
command="Browser:BackOrBackDuplicate"
cui-areatype="toolbar"
onclick="checkForMiddleClick(this, event);"
tooltip="back-button-tooltip"
context="backForwardMenu"/>
@ -695,7 +691,6 @@
<toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&forwardCmd.label;"
command="Browser:ForwardOrForwardDuplicate"
cui-areatype="toolbar"
onclick="checkForMiddleClick(this, event);"
tooltip="forward-button-tooltip"
context="backForwardMenu"/>
@ -798,7 +793,6 @@
orient="horizontal"
label="&webrtcIndicatorButton.label;"
tooltiptext="&webrtcIndicatorButton.tooltip;"
cui-areatype="toolbar"
overflows="false">
<menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
onpopuphiding="WebrtcIndicator.clearPopup(this);"
@ -962,17 +956,14 @@
<toolbarbutton id="nav-bar-overflow-button"
class="toolbarbutton-1 chromeclass-toolbar-additional overflow-button"
cui-areatype="toolbar"
skipintoolbarset="true"
tooltiptext="&navbarOverflow.label;"/>
<toolbaritem id="PanelUI-button"
class="chromeclass-toolbar-additional"
cui-areatype="toolbar"
removable="false">
<toolbarbutton id="PanelUI-menu-button"
class="toolbarbutton-1"
cui-areatype="toolbar"
consumeanchor="PanelUI-button"
label="&brandShortName;"
tooltiptext="&appmenu.tooltip;"/>
@ -989,7 +980,6 @@
# Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button
# to exit fullscreen and want it to behave like other toolbar buttons.
class="toolbarbutton-1"
cui-areatype="toolbar"
#endif
tooltiptext="&fullScreenRestore.tooltip;"
oncommand="BrowserFullScreen();"/>

Просмотреть файл

@ -857,14 +857,14 @@ nsContextMenu.prototype = {
// if the mixedContentChannel is present and the referring URI passes
// a same origin check with the target URI, we can preserve the users
// decision of disabling MCB on a page for it's child tabs.
var persistDisableMCBInChildTab = false;
var persistAllowMixedContentInChildTab = false;
if (this.browser.docShell && this.browser.docShell.mixedContentChannel) {
const sm = Services.scriptSecurityManager;
try {
var targetURI = this.linkURI;
sm.checkSameOriginURI(referrerURI, targetURI, false);
persistDisableMCBInChildTab = true;
persistAllowMixedContentInChildTab = true;
}
catch (e) { }
}
@ -872,7 +872,7 @@ nsContextMenu.prototype = {
openLinkIn(this.linkURL, "tab",
{ charset: doc.characterSet,
referrerURI: referrerURI,
disableMCB: persistDisableMCBInChildTab});
allowMixedContent: persistAllowMixedContentInChildTab });
},
// open URL in current tab

Просмотреть файл

@ -235,6 +235,7 @@
setTimeout(() => {
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
}, 0);
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(2);
]]></body>
</method>
@ -330,6 +331,9 @@
this.setAttribute("image", uri.spec);
}
break;
case "click":
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(2);
break;
}
]]></body>
</method>
@ -338,6 +342,7 @@
<handlers>
<handler event="popupshowing"><![CDATA[
this._anchor.setAttribute("open", "true");
this.content.addEventListener("click", this);
]]></handler>
<handler event="popupshown"><![CDATA[
this.onShown();
@ -346,6 +351,7 @@
this.dispatchPanelEvent("socialFrameHide");
this._anchor.removeAttribute("open");
this.update();
this.content.removeEventListener("click", this);
]]></handler>
<handler event="command"><![CDATA[
this.markCurrentPage();

Просмотреть файл

@ -1024,7 +1024,7 @@
this._appendStatusPanel();
if (updateBlockedPopups)
this.mCurrentBrowser.updateBlockedPopups(false);
this.mCurrentBrowser.updateBlockedPopups();
// Update the URL bar.
var loc = this.mCurrentBrowser.currentURI;
@ -1284,7 +1284,7 @@
<![CDATA[
var aFromExternal;
var aRelatedToCurrent;
var aDisableMCB;
var aAllowMixedContent;
var aSkipAnimation;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
@ -1297,7 +1297,7 @@
aAllowThirdPartyFixup = params.allowThirdPartyFixup;
aFromExternal = params.fromExternal;
aRelatedToCurrent = params.relatedToCurrent;
aDisableMCB = params.disableMCB;
aAllowMixedContent = params.allowMixedContent;
aSkipAnimation = params.skipAnimation;
}
@ -1313,7 +1313,7 @@
fromExternal: aFromExternal,
relatedToCurrent: aRelatedToCurrent,
skipAnimation: aSkipAnimation,
disableMCB: aDisableMCB});
allowMixedContent: aAllowMixedContent });
if (!bgLoad)
this.selectedTab = tab;
@ -1472,7 +1472,7 @@
var aFromExternal;
var aRelatedToCurrent;
var aSkipAnimation;
var aDisableMCB;
var aAllowMixedContent;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
@ -1485,7 +1485,7 @@
aFromExternal = params.fromExternal;
aRelatedToCurrent = params.relatedToCurrent;
aSkipAnimation = params.skipAnimation;
aDisableMCB = params.disableMCB;
aAllowMixedContent = params.allowMixedContent;
}
// if we're adding tabs, we're past interrupt mode, ditch the owner
@ -1656,7 +1656,7 @@
}
if (aFromExternal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
if (aDisableMCB)
if (aAllowMixedContent)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
try {
b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);

Просмотреть файл

@ -8,7 +8,7 @@ add_task(function* checkIdentityOfAboutSupport() {
allowThirdPartyFixup: false,
relatedToCurrent: false,
skipAnimation: true,
disableMCB: false
allowMixedContent: false
});
yield promiseTabLoaded(tab);

Просмотреть файл

@ -13,7 +13,7 @@ let crash = function() { // this will crash when called.
};
TestHelper = {
let TestHelper = {
init: function() {
addMessageListener("social-test:crash", this);
},

Просмотреть файл

@ -214,7 +214,7 @@ function openLinkIn(url, where, params) {
var aCharset = params.charset;
var aReferrerURI = params.referrerURI;
var aRelatedToCurrent = params.relatedToCurrent;
var aDisableMCB = params.disableMCB;
var aAllowMixedContent = params.allowMixedContent;
var aInBackground = params.inBackground;
var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
var aInitiatingDoc = params.initiatingDoc;
@ -337,7 +337,7 @@ function openLinkIn(url, where, params) {
allowThirdPartyFixup: aAllowThirdPartyFixup,
relatedToCurrent: aRelatedToCurrent,
skipAnimation: aSkipTabAnimation,
disableMCB: aDisableMCB});
allowMixedContent: aAllowMixedContent });
break;
}

Просмотреть файл

@ -619,7 +619,6 @@ let CustomizableUIInternal = {
container.removeChild(node);
}
} else {
this.setLocationAttributes(currentNode, aArea);
node.setAttribute("removable", false);
LOG("Adding non-removable widget to placements of " + aArea + ": " +
node.id);

Просмотреть файл

@ -70,7 +70,6 @@ function updateCombinedWidgetStyle(aNode, aArea, aModifyCloseMenu) {
if (aModifyCloseMenu) {
attrs.closemenu = inPanel ? "none" : null;
}
attrs["cui-areatype"] = aArea ? CustomizableUI.getAreaType(aArea) : null;
for (let i = 0, l = aNode.childNodes.length; i < l; ++i) {
if (aNode.childNodes[i].localName == "separator")
continue;

Просмотреть файл

@ -113,7 +113,7 @@ loop.panel = (function(_, mozL10n) {
"privacy_notice_url": "www.mozilla.org/privacy/"
});
if (!this.state.seenToS) {
if (this.state.seenToS == "unseen") {
navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
return React.DOM.p( {className:"terms-service",
dangerouslySetInnerHTML:{__html: tosHTML}});

Просмотреть файл

@ -113,7 +113,7 @@ loop.panel = (function(_, mozL10n) {
"privacy_notice_url": "www.mozilla.org/privacy/"
});
if (!this.state.seenToS) {
if (this.state.seenToS == "unseen") {
navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
return <p className="terms-service"
dangerouslySetInnerHTML={{__html: tosHTML}}></p>;

Просмотреть файл

@ -220,10 +220,6 @@ loop.shared.views = (function(_, OT, l10n) {
},
componentDidMount: function() {
this.props.model.startSession();
},
componentWillMount: function() {
this.listenTo(this.props.model, "session:connected",
this.startPublishing);
this.listenTo(this.props.model, "session:stream-created",
@ -232,9 +228,13 @@ loop.shared.views = (function(_, OT, l10n) {
"session:network-disconnected",
"session:ended"].join(" "),
this.stopPublishing);
this.props.model.startSession();
},
componentWillUnmount: function() {
// Unregister all local event listeners
this.stopListening();
this.hangup();
},
@ -279,20 +279,19 @@ loop.shared.views = (function(_, OT, l10n) {
outgoing, this.publisherConfig);
// Suppress OT GuM custom dialog, see bug 1018875
function preventOpeningAccessDialog(event) {
event.preventDefault();
}
this.publisher.on("accessDialogOpened", preventOpeningAccessDialog);
this.publisher.on("accessDenied", preventOpeningAccessDialog);
this.listenTo(this.publisher, "accessDialogOpened accessDenied",
function(event) {
event.preventDefault();
});
this.publisher.on("streamCreated", function(event) {
this.listenTo(this.publisher, "streamCreated", function(event) {
this.setState({
audio: {enabled: event.stream.hasAudio},
video: {enabled: event.stream.hasVideo}
});
}.bind(this));
this.publisher.on("streamDestroyed", function() {
this.listenTo(this.publisher, "streamDestroyed", function() {
this.setState({
audio: {enabled: false},
video: {enabled: false}
@ -322,9 +321,8 @@ loop.shared.views = (function(_, OT, l10n) {
* Unpublishes local stream.
*/
stopPublishing: function() {
// Unregister access OT GuM custom dialog listeners, see bug 1018875
this.publisher.off("accessDialogOpened");
this.publisher.off("accessDenied");
// Unregister listeners for publisher events
this.stopListening(this.publisher);
this.props.model.session.unpublish(this.publisher);
},

Просмотреть файл

@ -220,10 +220,6 @@ loop.shared.views = (function(_, OT, l10n) {
},
componentDidMount: function() {
this.props.model.startSession();
},
componentWillMount: function() {
this.listenTo(this.props.model, "session:connected",
this.startPublishing);
this.listenTo(this.props.model, "session:stream-created",
@ -232,9 +228,13 @@ loop.shared.views = (function(_, OT, l10n) {
"session:network-disconnected",
"session:ended"].join(" "),
this.stopPublishing);
this.props.model.startSession();
},
componentWillUnmount: function() {
// Unregister all local event listeners
this.stopListening();
this.hangup();
},
@ -279,20 +279,19 @@ loop.shared.views = (function(_, OT, l10n) {
outgoing, this.publisherConfig);
// Suppress OT GuM custom dialog, see bug 1018875
function preventOpeningAccessDialog(event) {
event.preventDefault();
}
this.publisher.on("accessDialogOpened", preventOpeningAccessDialog);
this.publisher.on("accessDenied", preventOpeningAccessDialog);
this.listenTo(this.publisher, "accessDialogOpened accessDenied",
function(event) {
event.preventDefault();
});
this.publisher.on("streamCreated", function(event) {
this.listenTo(this.publisher, "streamCreated", function(event) {
this.setState({
audio: {enabled: event.stream.hasAudio},
video: {enabled: event.stream.hasVideo}
});
}.bind(this));
this.publisher.on("streamDestroyed", function() {
this.listenTo(this.publisher, "streamDestroyed", function() {
this.setState({
audio: {enabled: false},
video: {enabled: false}
@ -322,9 +321,8 @@ loop.shared.views = (function(_, OT, l10n) {
* Unpublishes local stream.
*/
stopPublishing: function() {
// Unregister access OT GuM custom dialog listeners, see bug 1018875
this.publisher.off("accessDialogOpened");
this.publisher.off("accessDenied");
// Unregister listeners for publisher events
this.stopListening(this.publisher);
this.props.model.session.unpublish(this.publisher);
},

Просмотреть файл

@ -0,0 +1,11 @@
#!/bin/sh
# Run from topsrcdir, no args
set -e
# Main tests
./mach xpcshell-test browser/components/loop/
./mach marionette-test browser/components/loop/manifest.ini
# The browser_parsable_css.js can fail if we add some css that isn't parsable.
./mach mochitest browser/components/loop/test/mochitest browser/base/content/test/general/browser_parsable_css.js

Просмотреть файл

@ -48,7 +48,7 @@ describe("loop.panel", function() {
return "en-US";
},
setLoopCharPref: sandbox.stub(),
getLoopCharPref: sandbox.stub()
getLoopCharPref: sandbox.stub().returns("unseen")
};
document.mozL10n.initialize(navigator.mozLoop);

Просмотреть файл

@ -194,12 +194,10 @@ describe("loop.shared.views", function() {
unpublish: sandbox.spy(),
subscribe: sandbox.spy()
}, Backbone.Events);
fakePublisher = {
on: sandbox.spy(),
off: sandbox.spy(),
fakePublisher = _.extend({
publishAudio: sandbox.spy(),
publishVideo: sandbox.spy()
};
}, Backbone.Events);
fakeSDK = {
initPublisher: sandbox.stub().returns(fakePublisher),
initSession: sandbox.stub().returns(fakeSession)
@ -248,6 +246,10 @@ describe("loop.shared.views", function() {
});
describe("#startPublishing", function() {
beforeEach(function() {
sandbox.stub(fakePublisher, "on");
});
it("should publish local stream", function() {
comp.startPublishing();
@ -261,13 +263,14 @@ describe("loop.shared.views", function() {
comp.startPublishing();
sinon.assert.called(fakePublisher.on);
sinon.assert.calledWith(fakePublisher.on, "accessDialogOpened");
sinon.assert.calledWith(fakePublisher.on, "accessDenied");
sinon.assert.calledWith(fakePublisher.on,
"accessDialogOpened accessDenied");
});
});
describe("#stopPublishing", function() {
beforeEach(function() {
sandbox.stub(fakePublisher, "off");
comp.startPublishing();
});
@ -277,13 +280,12 @@ describe("loop.shared.views", function() {
sinon.assert.calledOnce(fakeSession.unpublish);
});
it("should unsubscribe from accessDialogOpened and accessDenied events",
it("should unsubscribe from publisher events",
function() {
comp.stopPublishing();
sinon.assert.calledTwice(fakePublisher.off);
sinon.assert.calledWith(fakePublisher.off, "accessDialogOpened");
sinon.assert.calledWith(fakePublisher.off, "accessDenied");
// Note: Backbone.Events#stopListening calls off() on passed object.
sinon.assert.calledOnce(fakePublisher.off);
});
});
@ -367,6 +369,35 @@ describe("loop.shared.views", function() {
sinon.assert.calledOnce(fakeSession.unpublish);
});
});
describe("Publisher events", function() {
beforeEach(function() {
comp.startPublishing();
});
it("should set audio state on streamCreated", function() {
fakePublisher.trigger("streamCreated", {stream: {hasAudio: true}});
expect(comp.state.audio.enabled).eql(true);
fakePublisher.trigger("streamCreated", {stream: {hasAudio: false}});
expect(comp.state.audio.enabled).eql(false);
});
it("should set video state on streamCreated", function() {
fakePublisher.trigger("streamCreated", {stream: {hasVideo: true}});
expect(comp.state.video.enabled).eql(true);
fakePublisher.trigger("streamCreated", {stream: {hasVideo: false}});
expect(comp.state.video.enabled).eql(false);
});
it("should set media state on streamDestroyed", function() {
fakePublisher.trigger("streamDestroyed");
expect(comp.state.audio.enabled).eql(false);
expect(comp.state.video.enabled).eql(false);
});
});
});
});

Просмотреть файл

@ -65,7 +65,7 @@ add_task(function() {
add_task(function () {
const FRAME_SCRIPT = "data:," +
"docShell.QueryInterface%28Ci.nsILoadContext%29.usePrivateBrowsing%3Dtrue";
"docShell.QueryInterface%28Components.interfaces.nsILoadContext%29.usePrivateBrowsing%3Dtrue";
// Clear the list of closed windows.
while (ss.getClosedWindowCount()) {

Просмотреть файл

@ -4,6 +4,8 @@
"use strict";
let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
/**
* This frame script is only loaded for sessionstore mochitests. It contains
* a bunch of utility functions used to test form data collection and

Просмотреть файл

@ -596,8 +596,8 @@ HTMLBreadcrumbs.prototype = {
if (this.currentIndex == this.nodeHierarchy.length - 1) {
let node = this.nodeHierarchy[this.currentIndex].node;
return this.getInterestingFirstNode(node).then(child => {
// If the node has a child
if (child) {
// If the node has a child and we've not been destroyed in the meantime
if (child && !this.isDestroyed) {
// Show this child
this.expand(child);
}

Просмотреть файл

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
subsuite = devtools
support-files =
doc_markup_edit.html
@ -19,8 +18,11 @@ support-files =
[browser_markupview_copy_image_data.js]
[browser_markupview_css_completion_style_attribute.js]
[browser_markupview_highlight_hover_01.js]
skip-if = e10s # Bug 985597 - The XUL-based highlighter isn't e10s compatible
[browser_markupview_highlight_hover_02.js]
skip-if = e10s # Bug 985597 - The XUL-based highlighter isn't e10s compatible
[browser_markupview_highlight_hover_03.js]
skip-if = e10s # Bug 985597 - The XUL-based highlighter isn't e10s compatible
[browser_markupview_html_edit_01.js]
[browser_markupview_html_edit_02.js]
[browser_markupview_html_edit_03.js]
@ -32,10 +34,12 @@ support-files =
[browser_markupview_node_not_displayed_02.js]
[browser_markupview_pagesize_01.js]
[browser_markupview_pagesize_02.js]
skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
[browser_markupview_search_01.js]
[browser_markupview_tag_edit_01.js]
[browser_markupview_tag_edit_02.js]
[browser_markupview_tag_edit_03.js]
skip-if = e10s # Bug 1036421 - Tag editing isn't remote-safe
[browser_markupview_tag_edit_04.js]
[browser_markupview_tag_edit_05.js]
[browser_markupview_tag_edit_06.js]

Просмотреть файл

@ -69,15 +69,16 @@ let test = asyncTest(function*() {
yield inspector.markup.expandAll();
let node = getContainerForRawNode("#node14", inspector).editor;
let attr = node.newAttr;
let nodeFront = yield getNodeFront("#node14", inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
let attr = container.editor.newAttr;
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
let editor = inplaceEditor(attr);
for (let i = 0; i < TEST_DATA.length; i ++) {
yield enterData(i, editor, inspector);
checkData(i, editor, inspector);
yield checkData(i, editor, inspector);
}
while (inspector.markup.undo.canUndo()) {
@ -122,7 +123,7 @@ function enterData(index, editor, inspector) {
return def.promise;
}
function checkData(index, editor, inspector) {
function* checkData(index, editor, inspector) {
let [key, completion, selStart, selEnd, popupOpen] = TEST_DATA[index];
info("Test data " + index + " entered. Checking state.");
@ -137,7 +138,8 @@ function checkData(index, editor, inspector) {
"Popup is closed");
}
} else {
let editor = getContainerForRawNode("#node14", inspector).editor;
let nodeFront = yield getNodeFront("#node14", inspector);
let editor = getContainerForNodeFront(nodeFront, inspector).editor;
let attr = editor.attrs["style"].querySelector(".editable");
is(attr.textContent, completion, "Correct value is persisted after pressing Enter");
}

Просмотреть файл

@ -13,11 +13,11 @@ let test = asyncTest(function*() {
let p = getNode("p");
info("hovering over the <p> line in the markup-view");
yield hoverContainer(p, inspector);
yield hoverContainer("p", inspector);
ok(isHighlighterVisible(), "the highlighter is still visible");
info("selecting the <p> line by clicking in the markup-view");
yield clickContainer(p, inspector);
yield clickContainer("p", inspector);
p.textContent = "wait for it ....";
info("wait and see if the highlighter stays visible even after the node was selected");

Просмотреть файл

@ -29,13 +29,14 @@ let test = asyncTest(function*() {
return promise.resolve();
};
function isHighlighting(node, desc) {
is(highlightedNode, getContainerForRawNode(node, inspector).node, desc);
function* isHighlighting(selector, desc) {
let nodeFront = yield getNodeFront(selector, inspector);
is(highlightedNode, nodeFront, desc);
}
info("Hover over <p#one> line in the markup-view");
yield hoverContainer("#one", inspector);
isHighlighting(getNode("#one"), "<p#one> is highlighted");
yield isHighlighting("#one", "<p#one> is highlighted");
info("Navigate to <p#two> with the keyboard");
let onUpdated = inspector.once("inspector-updated");
@ -44,11 +45,11 @@ let test = asyncTest(function*() {
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_DOWN", {});
yield onUpdated;
isHighlighting(getNode("#two"), "<p#two> is highlighted");
yield isHighlighting("#two", "<p#two> is highlighted");
info("Navigate back to <p#one> with the keyboard");
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_UP", {});
yield onUpdated;
isHighlighting(getNode("#one"), "<p#one> is highlighted again");
yield isHighlighting("#one", "<p#one> is highlighted again");
});

Просмотреть файл

@ -13,7 +13,7 @@ const TEST_DATA = [
selector: "#one",
oldHTML: '<div id="one">First <em>Div</em></div>',
newHTML: '<div id="one">First Div</div>',
validate: function(pageNode, selectedNode) {
validate: function*(pageNode, pageNodeFront, selectedNodeFront) {
is(pageNode.textContent, "First Div", "New div has expected text content");
ok(!getNode("#one em"), "No em remaining")
}
@ -32,8 +32,8 @@ const TEST_DATA = [
selector: "#addedAttribute",
oldHTML: '<div id="addedAttribute">addedAttribute</div>',
newHTML: '<div id="addedAttribute" class="important" disabled checked>addedAttribute</div>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
is(pageNode.outerHTML, '<div id="addedAttribute" class="important" disabled="" checked="">addedAttribute</div>',
"Attributes have been added");
}
@ -49,14 +49,15 @@ const TEST_DATA = [
newHTML: '<div id="siblings-before-sibling">before sibling</div>' +
'<div id="siblings">siblings (updated)</div>' +
'<div id="siblings-after-sibling">after sibling</div>',
validate: function(pageNode, selectedNode) {
let beforeSiblingNode = getNode("#siblings-before-sibling");
let afterSiblingNode = getNode("#siblings-after-sibling");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
let beforeSibling = getNode("#siblings-before-sibling");
let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling", inspector);
let afterSibling = getNode("#siblings-after-sibling");
is(beforeSiblingNode, selectedNode, "Sibling has been selected");
is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected");
is(pageNode.textContent, "siblings (updated)", "New div has expected text content");
is(beforeSiblingNode.textContent, "before sibling", "Sibling has been inserted");
is(afterSiblingNode.textContent, "after sibling", "Sibling has been inserted");
is(beforeSibling.textContent, "before sibling", "Sibling has been inserted");
is(afterSibling.textContent, "after sibling", "Sibling has been inserted");
}
}
];

Просмотреть файл

@ -13,8 +13,8 @@ const TEST_DATA = [
selector: "#badMarkup1",
oldHTML: '<div id="badMarkup1">badMarkup1</div>',
newHTML: '<div id="badMarkup1">badMarkup1</div> hanging</div>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let textNode = pageNode.nextSibling;
@ -26,8 +26,8 @@ const TEST_DATA = [
selector: "#badMarkup2",
oldHTML: '<div id="badMarkup2">badMarkup2</div>',
newHTML: '<div id="badMarkup2">badMarkup2</div> hanging<div></div></div></div></body>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let textNode = pageNode.nextSibling;
@ -39,8 +39,8 @@ const TEST_DATA = [
selector: "#badMarkup3",
oldHTML: '<div id="badMarkup3">badMarkup3</div>',
newHTML: '<div id="badMarkup3">badMarkup3 <em>Emphasized <strong> and strong</div>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let em = getNode("#badMarkup3 em");
let strong = getNode("#badMarkup3 strong");
@ -53,8 +53,8 @@ const TEST_DATA = [
selector: "#badMarkup4",
oldHTML: '<div id="badMarkup4">badMarkup4</div>',
newHTML: '<div id="badMarkup4">badMarkup4</p>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let div = getNode("#badMarkup4");
let p = getNode("#badMarkup4 p");
@ -69,8 +69,8 @@ const TEST_DATA = [
selector: "#badMarkup5",
oldHTML: '<p id="badMarkup5">badMarkup5</p>',
newHTML: '<p id="badMarkup5">badMarkup5 <div>with a nested div</div></p>',
validate: function(pageNode, selectedNode) {
is(pageNode, selectedNode, "Original element is selected");
validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let p = getNode("#badMarkup5");
let nodiv = getNode("#badMarkup5 div");

Просмотреть файл

@ -46,7 +46,7 @@ function testEscapeCancels(inspector) {
let def = promise.defer();
let node = getNode(SELECTOR);
selectNode(node, inspector).then(() => {
selectNode(SELECTOR, inspector).then(() => {
inspector.markup.htmlEditor.on("popupshown", function onPopupShown() {
inspector.markup.htmlEditor.off("popupshown", onPopupShown);
@ -101,80 +101,82 @@ function testF2Commits(inspector) {
return def.promise;
}
function testBody(inspector) {
function* testBody(inspector) {
let body = getNode("body");
let bodyHTML = '<body id="updated"><p></p></body>';
let bodyFront = inspector.markup.walker.frontForRawNode(body);
let bodyFront = yield getNodeFront("body", inspector);
let doc = content.document;
let mutated = inspector.once("markupmutation");
inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML, body.outerHTML);
return mutated.then(mutations => {
is(getNode("body").outerHTML, bodyHTML, "<body> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
return inspector.once("inspector-updated");
});
let mutations = yield mutated;
is(getNode("body").outerHTML, bodyHTML, "<body> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
yield inspector.once("inspector-updated");
}
function testHead(inspector) {
function* testHead(inspector) {
let head = getNode("head");
let headHTML = '<head id="updated"><title>New Title</title><script>window.foo="bar";</script></head>';
let headFront = inspector.markup.walker.frontForRawNode(head);
let headFront = yield getNodeFront("head", inspector);
let doc = content.document;
let mutated = inspector.once("markupmutation");
inspector.markup.updateNodeOuterHTML(headFront, headHTML, head.outerHTML);
return mutated.then(mutations => {
is(doc.title, "New Title", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.querySelector("head").outerHTML, headHTML, "<head> HTML has been updated");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
return inspector.once("inspector-updated");
});
let mutations = yield mutated;
is(doc.title, "New Title", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.querySelector("head").outerHTML, headHTML, "<head> HTML has been updated");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
yield inspector.once("inspector-updated");
}
function testDocumentElement(inspector) {
function* testDocumentElement(inspector) {
let doc = content.document;
let docElement = doc.documentElement;
let docElementHTML = '<html id="updated" foo="bar"><head><title>Updated from document element</title><script>window.foo="bar";</script></head><body><p>Hello</p></body></html>';
let docElementFront = inspector.markup.walker.frontForRawNode(docElement);
let docElementFront = yield inspector.markup.walker.documentElement();
let mutated = inspector.once("markupmutation");
inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
return mutated.then(mutations => {
is(doc.title, "Updated from document element", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.documentElement.id, "updated", "<html> ID has been updated");
is(doc.documentElement.className, "", "<html> class has been updated");
is(doc.documentElement.getAttribute("foo"), "bar", "<html> attribute has been updated");
is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
is(doc.body.textContent, "Hello", "document.body.textContent has been updated");
});
let mutations = yield mutated;
is(doc.title, "Updated from document element", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.documentElement.id, "updated", "<html> ID has been updated");
is(doc.documentElement.className, "", "<html> class has been updated");
is(doc.documentElement.getAttribute("foo"), "bar", "<html> attribute has been updated");
is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
is(doc.body.textContent, "Hello", "document.body.textContent has been updated");
}
function testDocumentElement2(inspector) {
function* testDocumentElement2(inspector) {
let doc = content.document;
let docElement = doc.documentElement;
let docElementHTML = '<html class="updated" id="somethingelse"><head><title>Updated again from document element</title><script>window.foo="bar";</script></head><body><p>Hello again</p></body></html>';
let docElementFront = inspector.markup.walker.frontForRawNode(docElement);
let docElementFront = yield inspector.markup.walker.documentElement();
let mutated = inspector.once("markupmutation");
inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
return mutated.then(mutations => {
is(doc.title, "Updated again from document element", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.documentElement.id, "somethingelse", "<html> ID has been updated");
is(doc.documentElement.className, "updated", "<html> class has been updated");
is(doc.documentElement.getAttribute("foo"), null, "<html> attribute has been removed");
is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
is(doc.body.textContent, "Hello again", "document.body.textContent has been updated");
});
let mutations = yield mutated;
is(doc.title, "Updated again from document element", "New title has been added");
is(doc.defaultView.foo, undefined, "Script has not been executed");
is(doc.documentElement.id, "somethingelse", "<html> ID has been updated");
is(doc.documentElement.className, "updated", "<html> class has been updated");
is(doc.documentElement.getAttribute("foo"), null, "<html> attribute has been removed");
is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
is(doc.body.textContent, "Hello again", "document.body.textContent has been updated");
}

Просмотреть файл

@ -32,7 +32,7 @@ let test = asyncTest(function*() {
yield selectNode("img", inspector);
for (let testNode of TEST_NODES) {
let target = getImageTooltipTarget(testNode, inspector);
let target = yield getImageTooltipTarget(testNode, inspector);
yield assertTooltipShownOn(target, inspector);
checkImageTooltip(testNode, inspector);
}
@ -55,11 +55,11 @@ function createPage() {
context.fill();
}
function getImageTooltipTarget({selector}, inspector) {
let node = getNode(selector);
let isImg = node.tagName.toLowerCase() === "img";
function* getImageTooltipTarget({selector}, inspector) {
let nodeFront = yield getNodeFront(selector, inspector);
let isImg = nodeFront.tagName.toLowerCase() === "img";
let container = getContainerForRawNode(node, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
let target = container.editor.tag;
if (isImg) {
@ -68,12 +68,10 @@ function getImageTooltipTarget({selector}, inspector) {
return target;
}
function assertTooltipShownOn(element, {markup}) {
return Task.spawn(function*() {
info("Is the element a valid hover target");
let isValid = yield markup.tooltip.isValidHoverTarget(element);
ok(isValid, "The element is a valid hover target for the image tooltip");
});
function* assertTooltipShownOn(element, {markup}) {
info("Is the element a valid hover target");
let isValid = yield markup.tooltip.isValidHoverTarget(element);
ok(isValid, "The element is a valid hover target for the image tooltip");
}
function checkImageTooltip({selector, size}, {markup}) {

Просмотреть файл

@ -5,20 +5,25 @@
"use strict";
// Tests that various mutations to the dom update the markup view correctly.
// The test for comparing the markup view to the real dom is a bit weird:
// - Select the text in the markup view
// - Parse that as innerHTML in a document we've created for the purpose.
// - Remove extraneous whitespace in that tree
// - Compare it to the real dom with isEqualNode.
const TEST_URL = TEST_URL_ROOT + "doc_markup_mutation.html";
// All the mutation types we want to test.
// Mutation tests. Each entry in the array has the following properties:
// - desc: for logging only
// - test: a function supposed to mutate the DOM
// - check: a function supposed to test that the mutation was handled
const TEST_DATA = [
{
desc: "Adding an attribute",
test: () => {
let node1 = getNode("#node1");
node1.setAttribute("newattr", "newattrval");
},
check: function*(inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrval\"";
}), "newattr attribute found");
}
},
{
@ -26,6 +31,15 @@ const TEST_DATA = [
test: () => {
let node1 = getNode("#node1");
node1.removeAttribute("newattr");
},
check: function*(inspector) {
// The markup-view is a little weird in that it doesn't remove the
// attribute but only hides it with display:none
let {editor} = yield getContainerForSelector("#node1", inspector);
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrval\"" &&
attr.style.display === "none";
}), "newattr attribute removed");
}
},
{
@ -33,6 +47,11 @@ const TEST_DATA = [
test: () => {
let node1 = getNode("#node1");
node1.textContent = "newtext";
},
check: function*(inspector) {
let {children} = yield getContainerForSelector("#node1", inspector);
is(children.querySelector(".text").textContent.trim(), "newtext",
"The new textcontent was updated");
}
},
{
@ -40,6 +59,17 @@ const TEST_DATA = [
test: () => {
let node2 = getNode("#node2");
node2.innerHTML = "<div><span>foo</span></div>";
},
check: function*(inspector) {
let container = yield getContainerForSelector("#node2", inspector);
let openTags = container.children.querySelectorAll(".open .tag");
is(openTags.length, 2, "There are 2 tags in node2");
is(openTags[0].textContent.trim(), "div", "The first tag is a div");
is(openTags[1].textContent.trim(), "span", "The second tag is a span");
is(container.children.querySelector(".text").textContent.trim(), "foo",
"The span's textcontent is correct");
}
},
{
@ -49,14 +79,27 @@ const TEST_DATA = [
while (node4.firstChild) {
node4.removeChild(node4.firstChild);
}
},
check: function*(inspector) {
let {children} = yield getContainerForSelector("#node4", inspector);
is(children.innerHTML, "", "Children have been removed");
}
},
{
desc: "Appending a child to a different parent",
test: () => {
let node17 = getNode("#node17");
let node1 = getNode("#node2");
node1.appendChild(node17);
let node2 = getNode("#node2");
node2.appendChild(node17);
},
check: function*(inspector) {
let {children} = yield getContainerForSelector("#node16", inspector);
is(children.innerHTML, "", "Node17 has been removed from its node16 parent");
let container = yield getContainerForSelector("#node2", inspector);
let openTags = container.children.querySelectorAll(".open .tag");
is(openTags.length, 3, "There are now 3 tags in node2");
is(openTags[2].textContent.trim(), "p", "The third tag is node17");
}
},
{
@ -82,73 +125,46 @@ const TEST_DATA = [
node1.appendChild(node20);
node20.appendChild(node18);
},
check: function*(inspector) {
let {children} = yield getContainerForSelector("#node1", inspector);
is(children.childNodes.length, 2,
"Node1 now has 2 children (textnode and node20)");
let node20 = children.childNodes[1];
let node20Children = node20.querySelector(".children")
is(node20Children.childNodes.length, 2, "Node20 has 2 children (21 and 18)");
let node21 = node20Children.childNodes[0];
is(node21.querySelector(".children").textContent.trim(), "line21",
"Node21 only has a text node child");
let node18 = node20Children.childNodes[1];
is(node18.querySelector(".open .attreditor .attr-value").textContent.trim(),
"node18", "Node20's second child is indeed node18");
}
}
];
let test = asyncTest(function*() {
info("Creating the helper tab for parsing");
let parseTab = yield addTab("data:text/html,<html></html>");
let parseDoc = content.document;
info("Creating the test tab");
let contentTab = yield addTab(TEST_URL);
let doc = content.document;
// Strip whitespace in the document for easier comparison
stripWhitespace(doc.documentElement);
let {inspector} = yield openInspector();
let markup = inspector.markup;
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
info("Expanding all markup-view nodes");
yield markup.expandAll();
yield inspector.markup.expandAll();
for (let step of TEST_DATA) {
info("Starting test: " + step.desc);
for (let {desc, test, check} of TEST_DATA) {
info("Starting test: " + desc);
info("Executing the test markup mutation, listening for inspector-updated before moving on");
let updated = inspector.once("inspector-updated");
step.test();
yield updated;
info("Executing the test markup mutation");
let onUpdated = inspector.once("inspector-updated");
let onMutation = inspector.once("markupmutation");
test();
yield onUpdated.then(onMutation);
info("Expanding all markup-view nodes to make sure new nodes are imported");
yield markup.expandAll();
yield inspector.markup.expandAll();
info("Comparing the markup-view markup with the content document");
compareMarkup(parseDoc, inspector);
info("Checking the markup-view content");
yield check(inspector);
}
});
function stripWhitespace(node) {
node.normalize();
let iter = node.ownerDocument.createNodeIterator(node,
NodeFilter.SHOW_TEXT + NodeFilter.SHOW_COMMENT, null);
while ((node = iter.nextNode())) {
node.nodeValue = node.nodeValue.replace(/\s+/g, '');
if (node.nodeType == Node.TEXT_NODE &&
!/[^\s]/.exec(node.nodeValue)) {
node.parentNode.removeChild(node);
}
}
}
function compareMarkup(parseDoc, inspector) {
// Grab the text from the markup panel...
let markupContainerEl = getContainerForRawNode("body", inspector).elt;
let sel = markupContainerEl.ownerDocument.defaultView.getSelection();
sel.selectAllChildren(markupContainerEl);
// Parse it
let parseNode = parseDoc.querySelector("body");
parseNode.outerHTML = sel;
parseNode = parseDoc.querySelector("body");
// Pull whitespace out of text and comment nodes, there will
// be minor unimportant differences.
stripWhitespace(parseNode);
// console.log(contentNode.innerHTML, parseNode.innerHTML);
ok(getNode("body").isEqualNode(parseNode),
"Markup panel matches what's in the content document.");
}

Просмотреть файл

@ -8,11 +8,14 @@
// corresponding DOM nodes mutate
const TEST_URL = TEST_URL_ROOT + "doc_markup_flashing.html";
// The test data contains a list of mutations to test.
// Each item is an object:
// - desc: a description of the test step, for better logging
// - mutate: a function that should make changes to the content DOM
// - shouldFlash: a function that returns the element that should be the one flashing
// - flashedNode: [optional] the css selector of the node that is expected to
// flash in the markup-view as a result of the mutation.
// If missing, the rootNode (".list") will be expected to flash
const TEST_DATA = [{
desc: "Adding a new node should flash the new node",
mutate: (doc, rootNode) => {
@ -20,37 +23,33 @@ const TEST_DATA = [{
newLi.textContent = "new list item";
rootNode.appendChild(newLi);
},
shouldFlash: rootNode => rootNode.lastElementChild
flashedNode: ".list li:nth-child(3)"
}, {
desc: "Removing a node should flash its parent",
mutate: (doc, rootNode) => {
rootNode.removeChild(rootNode.lastElementChild);
},
shouldFlash: rootNode => rootNode
}
}, {
desc: "Re-appending an existing node should only flash this node",
mutate: (doc, rootNode) => {
rootNode.appendChild(rootNode.firstElementChild);
},
shouldFlash: rootNode => rootNode.lastElementChild
flashedNode: ".list .item:last-child"
}, {
desc: "Adding an attribute should flash the node",
mutate: (doc, rootNode) => {
rootNode.setAttribute("name-" + Date.now(), "value-" + Date.now());
},
shouldFlash: rootNode => rootNode
}
}, {
desc: "Editing an attribute should flash the node",
mutate: (doc, rootNode) => {
rootNode.setAttribute("class", "list value-" + Date.now());
},
shouldFlash: rootNode => rootNode
}
}, {
desc: "Removing an attribute should flash the node",
mutate: (doc, rootNode) => {
rootNode.removeAttribute("class");
},
shouldFlash: rootNode => rootNode
}
}];
let test = asyncTest(function*() {
@ -58,11 +57,12 @@ let test = asyncTest(function*() {
info("Getting the <ul.list> root node to test mutations on");
let rootNode = getNode(".list");
let rootNodeFront = yield getNodeFront(".list", inspector);
info("Selecting the last element of the root node before starting");
yield selectNode(rootNode.lastElementChild, inspector);
yield selectNode(".list .item:nth-child(2)", inspector);
for (let {mutate, shouldFlash, desc} of TEST_DATA) {
for (let {mutate, flashedNode, desc} of TEST_DATA) {
info("Starting test: " + desc);
info("Mutating the DOM and listening for markupmutation event");
@ -72,20 +72,20 @@ let test = asyncTest(function*() {
yield mutated;
info("Asserting that the correct markup-container is flashing");
assertNodeFlashing(shouldFlash(rootNode), inspector);
let flashingNodeFront = rootNodeFront;
if (flashedNode) {
flashingNodeFront = yield getNodeFront(flashedNode, inspector);
}
yield assertNodeFlashing(flashingNodeFront, inspector);
// Making sure the inspector has finished updating before moving on
yield updated;
}
});
function assertNodeFlashing(node, inspector) {
let container = getContainerForRawNode(node, inspector);
if (!container) {
ok(false, "Node not found");
} else {
ok(container.tagState.classList.contains("theme-bg-contrast"),
"Node is flashing");
}
function* assertNodeFlashing(nodeFront, inspector) {
let container = getContainerForNodeFront(nodeFront, inspector);
ok(container, "Markup container for node found");
ok(container.tagState.classList.contains("theme-bg-contrast"),
"Markup container for node is flashing");
}

Просмотреть файл

@ -114,7 +114,7 @@ function pressKey(key) {
}
function checkSelectedNode(key, className, inspector) {
let node = inspector.selection.node;
let node = inspector.selection.nodeFront;
if (className == "*comment*") {
is(node.nodeType, Node.COMMENT_NODE, "Found a comment after pressing " + key);

Просмотреть файл

@ -26,7 +26,8 @@ let test = asyncTest(function*() {
for (let {selector, isDisplayed} of TEST_DATA) {
info("Getting node " + selector);
let container = getContainerForRawNode(selector, inspector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
is(!container.elt.classList.contains("not-displayed"), isDisplayed,
"The container for " + selector + " is marked as displayed " + isDisplayed);
}

Просмотреть файл

@ -98,35 +98,33 @@ let test = asyncTest(function*() {
}
});
function runTestData(inspector, {selector, before, changeStyle, after}) {
let def = promise.defer();
function* runTestData(inspector, {selector, before, changeStyle, after}) {
info("Getting the " + selector + " test node");
let container = getContainerForRawNode(selector, inspector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
is(!container.elt.classList.contains("not-displayed"), before,
"The container is marked as " + (before ? "shown" : "hidden"));
info("Listening for the display-change event");
inspector.markup.walker.once("display-change", nodes => {
info("Verifying that the list of changed nodes include our container");
ok(nodes.length, "The display-change event was received with a nodes");
let foundContainer = false;
for (let node of nodes) {
if (inspector.markup.getContainer(node) === container) {
foundContainer = true;
break;
}
}
ok(foundContainer, "Container is part of the list of changed nodes");
is(!container.elt.classList.contains("not-displayed"), after,
"The container is marked as " + (after ? "shown" : "hidden"));
def.resolve();
});
let onDisplayChanged = promise.defer();
inspector.markup.walker.once("display-change", onDisplayChanged.resolve);
info("Making style changes");
changeStyle(content.document, getNode(selector));
let nodes = yield onDisplayChanged.promise;
return def.promise;
info("Verifying that the list of changed nodes include our container");
ok(nodes.length, "The display-change event was received with a nodes");
let foundContainer = false;
for (let node of nodes) {
if (getContainerForNodeFront(node, inspector) === container) {
foundContainer = true;
break;
}
}
ok(foundContainer, "Container is part of the list of changed nodes");
is(!container.elt.classList.contains("not-displayed"), after,
"The container is marked as " + (after ? "shown" : "hidden"));
}

Просмотреть файл

@ -45,23 +45,23 @@ let test = asyncTest(function*() {
info("Start test: " + step.desc);
if (step.forceReload) {
forceReload(inspector);
yield forceReload(inspector);
}
info("Selecting the node that corresponds to " + step.selector);
yield selectNode(step.selector, inspector);
info("Checking that the right nodes are shwon");
assertChildren(step.expected, inspector);
yield assertChildren(step.expected, inspector);
}
info("Checking that clicking the more button loads everything");
clickShowMoreNodes(inspector);
yield clickShowMoreNodes(inspector);
yield inspector.markup._waitForChildren();
assertChildren("abcdefghijklmnopqrstuvwxyz", inspector);
yield assertChildren("abcdefghijklmnopqrstuvwxyz", inspector);
});
function assertChildren(expected, inspector) {
let container = getContainerForRawNode("body", inspector);
function* assertChildren(expected, inspector) {
let container = yield getContainerForSelector("body", inspector);
let found = "";
for (let child of container.children.children) {
if (child.classList.contains("more-nodes")) {
@ -73,13 +73,13 @@ function assertChildren(expected, inspector) {
is(found, expected, "Got the expected children.");
}
function forceReload(inspector) {
let container = getContainerForRawNode("body", inspector);
function* forceReload(inspector) {
let container = yield getContainerForSelector("body", inspector);
container.childrenDirty = true;
}
function clickShowMoreNodes(inspector) {
let container = getContainerForRawNode("body", inspector);
function* clickShowMoreNodes(inspector) {
let container = yield getContainerForSelector("body", inspector);
let button = container.elt.querySelector("button");
let win = button.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, button, win);

Просмотреть файл

@ -25,22 +25,21 @@ let test = asyncTest(function*() {
info("Click on the 'show all nodes' button in the UL's list of children");
yield showAllNodes(inspector);
assertAllNodesAreVisible(inspector);
yield assertAllNodesAreVisible(inspector);
});
function showAllNodes(inspector) {
let container = getContainerForRawNode("ul", inspector);
function* showAllNodes(inspector) {
let container = yield getContainerForSelector("ul", inspector);
let button = container.elt.querySelector("button");
ok(button, "All nodes button is here");
let win = button.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, button, win);
return inspector.markup._waitForChildren();
yield inspector.markup._waitForChildren();
}
function assertAllNodesAreVisible(inspector) {
let ul = getNode("ul");
let container = getContainerForRawNode(ul, inspector);
function* assertAllNodesAreVisible(inspector) {
let container = yield getContainerForSelector("ul", inspector);
ok(!container.elt.querySelector("button"), "All nodes button isn't here anymore");
is(container.children.childNodes.length, ul.children.length);
is(container.children.childNodes.length, getNode("ul").children.length);
}

Просмотреть файл

@ -13,8 +13,8 @@ const TEST_URL = TEST_URL_ROOT + "doc_markup_search.html";
let test = asyncTest(function*() {
let {inspector, toolbox} = yield addTab(TEST_URL).then(openInspector);
ok(!getContainerForRawNode("em", inspector),
"The <em> tag isn't present yet in the markup-view");
let container = yield getContainerForSelector("em", inspector);
ok(!container, "The <em> tag isn't present yet in the markup-view");
// Searching for the innermost element first makes sure that the inspector
// back-end is able to attach the resulting node to the tree it knows at the
@ -25,9 +25,11 @@ let test = asyncTest(function*() {
searchUsingSelectorSearch("em", inspector);
yield updated;
ok(getContainerForRawNode("em", inspector),
"The <em> tag is now imported in the markup-view");
is(inspector.selection.node, getNode("em"),
container = yield getContainerForSelector("em", inspector);
ok(container, "The <em> tag is now imported in the markup-view");
let nodeFront = yield getNodeFront("em", inspector);
is(inspector.selection.nodeFront, nodeFront,
"The <em> tag is the currently selected node");
info("searching for other nodes too");
@ -35,7 +37,9 @@ let test = asyncTest(function*() {
let updated = inspector.once("inspector-updated");
searchUsingSelectorSearch(node, inspector);
yield updated;
is(inspector.selection.node, getNode(node),
nodeFront = yield getNodeFront(node, inspector);
is(inspector.selection.nodeFront, nodeFront,
"The <" + node + "> tag is the currently selected node");
}
});

Просмотреть файл

@ -13,16 +13,15 @@ let test = asyncTest(function*() {
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
info("Selecting the test node");
let node = content.document.getElementById("test-div");
yield selectNode(node, inspector);
yield selectNode("#test-div", inspector);
info("Verify attributes, only ID should be there for now");
assertAttributes(node, {
assertAttributes("#test-div", {
id: "test-div"
});
info("Focus the ID attribute and change its content");
let editor = getContainerForRawNode(node, inspector).editor;
let {editor} = yield getContainerForSelector("#test-div", inspector);
let attr = editor.attrs["id"].querySelector(".editable");
let mutated = inspector.once("markupmutation");
setEditableFieldValue(attr,
@ -30,7 +29,7 @@ let test = asyncTest(function*() {
yield mutated;
info("Verify attributes, should have ID, class and style");
assertAttributes(node, {
assertAttributes("#test-div", {
id: "test-div",
class: "newclass",
style: "color:green"
@ -38,7 +37,7 @@ let test = asyncTest(function*() {
info("Trying to undo the change");
yield undoChange(inspector);
assertAttributes(node, {
assertAttributes("#test-div", {
id: "test-div"
});

Просмотреть файл

@ -14,11 +14,11 @@ let test = asyncTest(function*() {
yield inspector.markup.expandAll();
info("Selecting the test node");
let node = content.document.getElementById("retag-me");
let node = content.document.querySelector("#retag-me");
let child = content.document.querySelector("#retag-me-2");
yield selectNode(node, inspector);
yield selectNode("#retag-me", inspector);
let container = getContainerForRawNode(node, inspector);
let container = yield getContainerForSelector("#retag-me", inspector);
is(node.tagName, "DIV", "We've got #retag-me element, it's a DIV");
ok(container.expanded, "It is expanded");
is(child.parentNode, node, "Child #retag-me-2 is inside #retag-me");
@ -30,8 +30,8 @@ let test = asyncTest(function*() {
yield mutated;
info("Checking that the tagname change was done");
let node = content.document.getElementById("retag-me");
let container = getContainerForRawNode(node, inspector);
let node = content.document.querySelector("#retag-me");
let container = yield getContainerForSelector("#retag-me", inspector);
is(node.tagName, "P", "We've got #retag-me, it should now be a P");
ok(container.expanded, "It is still expanded");
ok(container.selected, "It is still selected");

Просмотреть файл

@ -12,8 +12,8 @@ let test = asyncTest(function*() {
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
info("Selecting the test node by clicking on it to make sure it receives focus");
let node = content.document.getElementById("delete-me");
yield clickContainer(node, inspector);
let node = content.document.querySelector("#delete-me");
yield clickContainer("#delete-me", inspector);
info("Deleting the element with the keyboard");
let mutated = inspector.once("markupmutation");
@ -21,10 +21,10 @@ let test = asyncTest(function*() {
yield mutated;
info("Checking that it's gone, baby gone!");
ok(!content.document.getElementById("delete-me"), "The test node does not exist");
ok(!content.document.querySelector("#delete-me"), "The test node does not exist");
yield undoChange(inspector);
ok(content.document.getElementById("delete-me"), "The test node is back!");
ok(content.document.querySelector("#delete-me"), "The test node is back!");
yield inspector.once("inspector-updated");
});

Просмотреть файл

@ -36,7 +36,7 @@ function* testCollapsedLongAttribute(inspector) {
"data-long": LONG_ATTRIBUTE
});
let editor = getContainerForRawNode("#node24", inspector).editor;
let {editor} = yield getContainerForSelector("#node24", inspector);
let attr = editor.attrs["data-long"].querySelector(".editable");
// Check to make sure it has expanded after focus
@ -69,7 +69,7 @@ function* testModifyInlineStyleWithQuotes(inspector) {
});
let onMutated = inspector.once("markupmutation");
let editor = getContainerForRawNode("#node26", inspector).editor;
let {editor} = yield getContainerForSelector("#node26", inspector);
let attr = editor.attrs["style"].querySelector(".editable");
attr.focus();
@ -105,7 +105,7 @@ function* testEditingAttributeWithMixedQuotes(inspector) {
});
let onMutated = inspector.once("markupmutation");
let editor = getContainerForRawNode("#node27", inspector).editor;
let {editor} = yield getContainerForSelector("#node27", inspector);
let attr = editor.attrs["class"].querySelector(".editable");
attr.focus();

Просмотреть файл

@ -13,6 +13,7 @@ let test = asyncTest(function*() {
info("Expanding all nodes");
yield inspector.markup.expandAll();
yield waitForMultipleChildrenUpdates(inspector);
let node = getNode(".node6").firstChild;
is(node.nodeValue, "line6", "The test node's text content is correct");
@ -21,8 +22,8 @@ let test = asyncTest(function*() {
info("Listening to the markupmutation event");
let onMutated = inspector.once("markupmutation");
let editor = getContainerForRawNode(node, inspector).editor;
let field = editor.elt.querySelector("pre");
let container = yield getContainerForSelector(".node6", inspector);
let field = container.elt.querySelector("pre");
setEditableFieldValue(field, "New text", inspector);
yield onMutated;
@ -30,3 +31,15 @@ let test = asyncTest(function*() {
yield inspector.once("inspector-updated");
});
// The expand all operation of the markup-view calls itself recursively and
// there's not one event we can wait for to know when it's done
function* waitForMultipleChildrenUpdates(inspector) {
// As long as child updates are queued up while we wait for an update already
// wait again
if (inspector.markup._queuedChildUpdates &&
inspector.markup._queuedChildUpdates.size) {
yield waitForChildrenUpdated(inspector);
return yield waitForMultipleChildrenUpdates(inspector);
}
}

Просмотреть файл

@ -12,7 +12,7 @@ let test = asyncTest(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
info("Getting the container for the UL parent element");
let container = getContainerForRawNode("ul", inspector);
let container = yield getContainerForSelector("ul", inspector);
info("Clicking on the UL parent expander, and waiting for children");
let onChildren = waitForChildrenUpdated(inspector);
@ -23,9 +23,10 @@ let test = asyncTest(function*() {
yield onUpdated;
info("Checking that child LI elements have been created");
for (let li of content.document.querySelectorAll("li")) {
ok(getContainerForRawNode(li, inspector),
"A container for the child LI element was created");
for (let i = 0; i < content.document.querySelectorAll("li").length; i ++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
ok(liContainer, "A container for the child LI element was created");
}
ok(container.expanded, "Parent UL container is expanded");
@ -36,8 +37,9 @@ let test = asyncTest(function*() {
inspector.markup.doc.defaultView);
info("Checking that child LI elements have been hidden");
for (let li of content.document.querySelectorAll("li")) {
let liContainer = getContainerForRawNode(li, inspector);
for (let i = 0; i < content.document.querySelectorAll("li").length; i ++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
is(liContainer.elt.getClientRects().length, 0,
"The container for the child LI element was hidden");
}

Просмотреть файл

@ -12,7 +12,7 @@ let test = asyncTest(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
info("Getting the container for the UL parent element");
let container = getContainerForRawNode("ul", inspector);
let container = yield getContainerForSelector("ul", inspector);
info("Dbl-clicking on the UL parent expander, and waiting for children");
let onChildren = waitForChildrenUpdated(inspector);
@ -23,9 +23,10 @@ let test = asyncTest(function*() {
yield onUpdated;
info("Checking that child LI elements have been created");
for (let li of content.document.querySelectorAll("li")) {
ok(getContainerForRawNode(li, inspector),
"A container for the child LI element was created");
for (let i = 0; i < content.document.querySelectorAll("li").length; i ++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
ok(liContainer, "A container for the child LI element was created");
}
ok(container.expanded, "Parent UL container is expanded");
@ -36,8 +37,9 @@ let test = asyncTest(function*() {
inspector.markup.doc.defaultView);
info("Checking that child LI elements have been hidden");
for (let li of content.document.querySelectorAll("li")) {
let liContainer = getContainerForRawNode(li, inspector);
for (let i = 0; i < content.document.querySelectorAll("li").length; i ++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
is(liContainer.elt.getClientRects().length, 0,
"The container for the child LI element was hidden");
}

Просмотреть файл

@ -13,7 +13,7 @@ let test = asyncTest(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
info("Getting the container for the UL parent element");
let container = getContainerForRawNode("ul", inspector);
let container = yield getContainerForSelector("ul", inspector);
info("Alt-clicking on the UL parent expander, and waiting for children");
let onUpdated = inspector.once("inspector-updated");
@ -23,11 +23,14 @@ let test = asyncTest(function*() {
yield waitForMultipleChildrenUpdates(inspector);
info("Checking that all nodes exist and are expanded");
for (let node of content.document.querySelectorAll("ul, li, span, em")) {
let nodeContainer = getContainerForRawNode(node, inspector);
ok(nodeContainer, "Container for node " + node.tagName + " exists");
let nodeList = yield inspector.walker.querySelectorAll(
inspector.walker.rootNode, "ul, li, span, em");
let nodeFronts = yield nodeList.items();
for (let nodeFront of nodeFronts) {
let nodeContainer = getContainerForNodeFront(nodeFront, inspector);
ok(nodeContainer, "Container for node " + nodeFront.tagName + " exists");
ok(nodeContainer.expanded,
"Container for node " + node.tagName + " is expanded");
"Container for node " + nodeFront.tagName + " is expanded");
}
});
@ -41,4 +44,4 @@ function* waitForMultipleChildrenUpdates(inspector) {
yield waitForChildrenUpdated(inspector);
return yield waitForMultipleChildrenUpdates(inspector);
}
}
}

Просмотреть файл

@ -28,19 +28,17 @@ registerCleanupFunction(() => {
});
// Auto close the toolbox and close the test tabs when the test ends
registerCleanupFunction(() => {
try {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.closeToolbox(target);
} catch (ex) {
dump(ex);
}
registerCleanupFunction(function*() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
const TEST_URL_ROOT = "http://mochi.test:8888/browser/browser/devtools/markupview/test/";
const CHROME_BASE = "chrome://mochitests/content/browser/browser/devtools/markupview/test/";
/**
* Define an async test based on a generator function
@ -58,15 +56,19 @@ function addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
let tab = gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
// Bug 921935 should bring waitForFocus() support to e10s, which would
// probably cover the case of the test losing focus when the page is loading.
// For now, we just make sure the window is focused.
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
waitForFocus(() => {
def.resolve(tab);
}, content);
def.resolve(tab);
}, true);
content.location = url;
return def.promise;
}
@ -124,7 +126,8 @@ function openInspector() {
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
* @param {String|DOMNode} nodeOrSelector
* @return {DOMNode}
* @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
* doesn't implement *all* of the DOMNode's properties
*/
function getNode(nodeOrSelector) {
info("Getting the node for '" + nodeOrSelector + "'");
@ -133,6 +136,17 @@ function getNode(nodeOrSelector) {
nodeOrSelector;
}
/**
* Get the NodeFront for a given css selector, via the protocol
* @param {String} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {Promise} Resolves to the NodeFront instance
*/
function getNodeFront(selector, {walker}) {
return walker.querySelector(walker.rootNode, selector);
}
/**
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
@ -149,46 +163,54 @@ function selectAndHighlightNode(nodeOrSelector, inspector) {
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not to highlight the
* node upon selection
* @return a promise that resolves when the inspector is updated with the new
* node
* Set the inspector's current selection to the first match of the given css
* selector
* @param {String} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @return {Promise} Resolves when the inspector is updated with the new node
*/
function selectNode(nodeOrSelector, inspector, reason="test") {
info("Selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let selectNode = Task.async(function*(selector, inspector, reason="test") {
info("Selecting the node for '" + selector + "'");
let nodeFront = yield getNodeFront(selector, inspector);
let updated = inspector.once("inspector-updated");
inspector.selection.setNode(node, reason);
return updated;
}
inspector.selection.setNodeFront(nodeFront, reason);
yield updated;
});
/**
* Get the MarkupContainer object instance that corresponds to the given
* HTML node
* @param {DOMNode|String} nodeOrSelector The DOM node for which the
* container is required
* NodeFront
* @param {NodeFront} nodeFront
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {MarkupContainer}
*/
function getContainerForRawNode(nodeOrSelector, {markup}) {
let front = markup.walker.frontForRawNode(getNode(nodeOrSelector));
let container = markup.getContainer(front);
info("Markup-container object for " + nodeOrSelector + " " + container);
return container;
function getContainerForNodeFront(nodeFront, {markup}) {
return markup.getContainer(nodeFront);
}
/**
* Get the MarkupContainer object instance that corresponds to the given
* selector
* @param {String} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {MarkupContainer}
*/
let getContainerForSelector = Task.async(function*(selector, inspector) {
info("Getting the markup-container for node " + selector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
info("Found markup-container " + container);
return container;
});
/**
* Using the markupview's _waitForChildren function, wait for all queued
* children updates to be handled.
@ -208,38 +230,46 @@ function waitForChildrenUpdated({markup}) {
/**
* Simulate a mouse-over on the markup-container (a line in the markup-view)
* that corresponds to the node or selector passed.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the container is hovered and the higlighter
* that corresponds to the selector passed.
* @param {String} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {Promise} Resolves when the container is hovered and the higlighter
* is shown on the corresponding node
*/
function hoverContainer(nodeOrSelector, inspector) {
info("Hovering over the markup-container for node " + nodeOrSelector);
let hoverContainer = Task.async(function*(selector, inspector) {
info("Hovering over the markup-container for node " + selector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
let highlit = inspector.toolbox.once("node-highlight");
let container = getContainerForRawNode(getNode(nodeOrSelector), inspector);
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
inspector.markup.doc.defaultView);
return highlit;
}
});
/**
* Simulate a click on the markup-container (a line in the markup-view)
* that corresponds to the node or selector passed.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the node has been selected.
* that corresponds to the selector passed.
* @param {String} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {Promise} Resolves when the node has been selected.
*/
function clickContainer(nodeOrSelector, inspector) {
info("Clicking on the markup-container for node " + nodeOrSelector);
let clickContainer = Task.async(function*(selector, inspector) {
info("Clicking on the markup-container for node " + selector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
let updated = inspector.once("inspector-updated");
let container = getContainerForRawNode(getNode(nodeOrSelector), inspector);
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousedown"},
inspector.markup.doc.defaultView);
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mouseup"},
inspector.markup.doc.defaultView);
return updated;
}
});
/**
* Checks if the highlighter is visible currently
@ -288,39 +318,39 @@ function setEditableFieldValue(field, value, inspector) {
}
/**
* Focus the new-attribute inplace-editor field of the nodeOrSelector's markup
* container, and enters the given text, then wait for it to be applied and the
* for the node to mutates (when new attribute(s) is(are) created)
* @param {DOMNode|String} nodeOrSelector The node or node selector to edit.
* Focus the new-attribute inplace-editor field of a node's markup container
* and enters the given text, then wait for it to be applied and the for the
* node to mutates (when new attribute(s) is(are) created)
* @param {String} selector The selector for the node to edit.
* @param {String} text The new attribute text to be entered (e.g. "id='test'")
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return a promise that resolves when the node has mutated
*/
function addNewAttributes(nodeOrSelector, text, inspector) {
info("Entering text '" + text + "' in node '" + nodeOrSelector + "''s new attribute field");
let addNewAttributes = Task.async(function*(selector, text, inspector) {
info("Entering text '" + text + "' in node '" + selector + "''s new attribute field");
let container = getContainerForRawNode(nodeOrSelector, inspector);
ok(container, "The container for '" + nodeOrSelector + "' was found");
let container = yield getContainerForSelector(selector, inspector);
ok(container, "The container for '" + selector + "' was found");
info("Listening for the markupmutation event");
let nodeMutated = inspector.once("markupmutation");
setEditableFieldValue(container.editor.newAttr, text, inspector);
return nodeMutated;
}
yield nodeMutated;
});
/**
* Checks that a node has the given attributes
*
* @param {DOMNode|String} nodeOrSelector The node or node selector to check.
* @param {String} selector The node or node selector to check.
* @param {Object} attrs An object containing the attributes to check.
* e.g. {id: "id1", class: "someclass"}
*
* Note that node.getAttribute() returns attribute values provided by the HTML
* parser. The parser only provides unescaped entities so &amp; will return &.
*/
function assertAttributes(nodeOrSelector, attrs) {
let node = getNode(nodeOrSelector);
function assertAttributes(selector, attrs) {
let node = getNode(selector);
is(node.attributes.length, Object.keys(attrs).length,
"Node has the correct number of attributes.");

Просмотреть файл

@ -21,11 +21,10 @@ function runAddAttributesTests(tests, nodeOrSelector, inspector) {
info("Running " + tests.length + " add-attributes tests");
return Task.spawn(function*() {
info("Selecting the test node");
let div = getNode("div");
yield selectNode(div, inspector);
yield selectNode("div", inspector);
for (let test of tests) {
yield runAddAttributesTest(test, div, inspector);
yield runAddAttributesTest(test, "div", inspector);
}
yield inspector.once("inspector-updated");
@ -48,22 +47,22 @@ function runAddAttributesTests(tests, nodeOrSelector, inspector) {
* - {DOMNode} The element being tested
* - {MarkupContainer} The corresponding container in the markup-view
* - {InspectorPanel} The instance of the InspectorPanel opened
* @param {DOMNode|String} nodeOrSelector The node or node selector
* corresponding to the test element
* @param {String} selector The node selector corresponding to the test element
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* opened
*/
function* runAddAttributesTest(test, nodeOrSelector, inspector) {
let element = getNode(nodeOrSelector);
function* runAddAttributesTest(test, selector, inspector) {
let element = getNode(selector);
info("Starting add-attribute test: " + test.desc);
yield addNewAttributes(element, test.text, inspector);
yield addNewAttributes(selector, test.text, inspector);
info("Assert that the attribute(s) has/have been applied correctly");
assertAttributes(element, test.expectedAttributes);
if (test.validate) {
test.validate(element, getContainerForRawNode(element, inspector), inspector);
let container = yield getContainerForSelector(selector, inspector);
test.validate(element, container, inspector);
}
info("Undo the change");
@ -128,7 +127,7 @@ function* runEditAttributesTest(test, inspector) {
info("Editing attribute " + test.name + " with value " + test.value);
let container = getContainerForRawNode(test.node, inspector);
let container = yield getContainerForSelector(test.node, inspector);
ok(container && container.editor, "The markup-container for " + test.node +
" was found");

Просмотреть файл

@ -42,6 +42,8 @@ function* runEditOuterHTMLTest(test, inspector) {
yield selectNode(test.selector, inspector);
let oldNodeFront = inspector.selection.nodeFront;
let onUpdated = inspector.once("inspector-updated");
info("Listening for the markupmutation event");
// This event fires once the outerHTML is set, with a target as the parent node and a type of "childList".
let mutated = inspector.once("markupmutation");
@ -60,22 +62,22 @@ function* runEditOuterHTMLTest(test, inspector) {
is(mutation.target, nodeFront, "Parent node is selected immediately after setting outerHTML");
// Wait for node to be reselected after outerHTML has been set
yield inspector.selection.once("new-node");
yield inspector.selection.once("new-node-front");
// Typically selectedNode will === pageNode, but if a new element has been injected in front
// of it, this will not be the case. If this happens.
let selectedNode = inspector.selection.node;
let nodeFront = inspector.selection.nodeFront;
let selectedNodeFront = inspector.selection.nodeFront;
let pageNodeFront = yield inspector.walker.querySelector(inspector.walker.rootNode, test.selector);
let pageNode = getNode(test.selector);
if (test.validate) {
test.validate(pageNode, selectedNode);
yield test.validate(pageNode, pageNodeFront, selectedNodeFront, inspector);
} else {
is(pageNode, selectedNode, "Original node (grabbed by selector) is selected");
is(pageNodeFront, selectedNodeFront, "Original node (grabbed by selector) is selected");
is(pageNode.outerHTML, test.newHTML, "Outer HTML has been updated");
}
// Wait for the inspector to be fully updated to avoid causing errors by
// abruptly closing hanging requests when the test ends
yield inspector.once("inspector-updated");
yield onUpdated;
}

Просмотреть файл

@ -49,7 +49,7 @@ function* runTests([win, sp]) {
// Check that the information tooltips work.
sp.setText("5");
yield keyOnce("show-information", " ", { shiftKey: true });
yield keyOnce("show-information", " ", { ctrlKey: true, shiftKey: true });
// Get the information container.
const info = editorWin.document.querySelector(".CodeMirror-Tern-information");

Просмотреть файл

@ -9,6 +9,7 @@ const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const IOService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
const {Spectrum} = require("devtools/shared/widgets/Spectrum");
const {CubicBezierWidget} = require("devtools/shared/widgets/CubicBezierWidget");
const EventEmitter = require("devtools/toolkit/event-emitter");
const {colorUtils} = require("devtools/css-color");
const Heritage = require("sdk/core/heritage");
@ -33,6 +34,7 @@ const BORDERCOLOR_RE = /^border-[-a-z]*color$/ig;
const BORDER_RE = /^border(-(top|bottom|left|right))?$/ig;
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const SPECTRUM_FRAME = "chrome://browser/content/devtools/spectrum-frame.xhtml";
const CUBIC_BEZIER_FRAME = "chrome://browser/content/devtools/cubic-bezier-frame.xhtml";
const ESCAPE_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE;
const RETURN_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
const POPUP_EVENTS = ["shown", "hidden", "showing", "hiding"];
@ -740,6 +742,52 @@ Tooltip.prototype = {
return def.promise;
},
/**
* Fill the tooltip with a new instance of the cubic-bezier widget
* initialized with the given value, and return a promise that resolves to
* the instance of the widget
*/
setCubicBezierContent: function(bezier) {
let def = promise.defer();
// Create an iframe to host the cubic-bezier widget
let iframe = this.doc.createElementNS(XHTML_NS, "iframe");
iframe.setAttribute("transparent", true);
iframe.setAttribute("width", "200");
iframe.setAttribute("height", "415");
iframe.setAttribute("flex", "1");
iframe.setAttribute("class", "devtools-tooltip-iframe");
let panel = this.panel;
let xulWin = this.doc.ownerGlobal;
// Wait for the load to initialize the widget
function onLoad() {
iframe.removeEventListener("load", onLoad, true);
let win = iframe.contentWindow.wrappedJSObject;
let container = win.document.getElementById("container");
let widget = new CubicBezierWidget(container, bezier);
// Resolve to the widget instance whenever the popup becomes visible
if (panel.state == "open") {
def.resolve(widget);
} else {
panel.addEventListener("popupshown", function shown() {
panel.removeEventListener("popupshown", shown, true);
def.resolve(widget);
}, true);
}
}
iframe.addEventListener("load", onLoad, true);
iframe.setAttribute("src", CUBIC_BEZIER_FRAME);
// Put the iframe in the tooltip
this.content = iframe;
return def.promise;
},
/**
* Set the content of the tooltip to display a font family preview.
* This is based on Lea Verou's Dablet. See https://github.com/LeaVerou/dabblet
@ -1022,21 +1070,63 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
});
/**
* Internal util, checks whether a css declaration is a gradient
* The swatch cubic-bezier tooltip class is a specific class meant to be used
* along with rule-view's generated cubic-bezier swatches.
* It extends the parent SwatchBasedEditorTooltip class.
* It just wraps a standard Tooltip and sets its content with an instance of a
* CubicBezierWidget.
*
* @param {XULDocument} doc
*/
function isGradientRule(property, value) {
return (property === "background" || property === "background-image") &&
value.match(GRADIENT_RE);
function SwatchCubicBezierTooltip(doc) {
SwatchBasedEditorTooltip.call(this, doc);
// Creating a cubic-bezier instance.
// this.widget will always be a promise that resolves to the widget instance
this.widget = this.tooltip.setCubicBezierContent([0, 0, 1, 1]);
this._onUpdate = this._onUpdate.bind(this);
}
/**
* Internal util, checks whether a css declaration is a color
*/
function isColorOnly(property, value) {
return property === "background-color" ||
property === "color" ||
property.match(BORDERCOLOR_RE);
}
module.exports.SwatchCubicBezierTooltip = SwatchCubicBezierTooltip;
SwatchCubicBezierTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, {
/**
* Overriding the SwatchBasedEditorTooltip.show function to set the cubic
* bezier curve in the widget
*/
show: function() {
// Call then parent class' show function
SwatchBasedEditorTooltip.prototype.show.call(this);
// Then set the curve and listen to changes to preview them
if (this.activeSwatch) {
this.currentBezierValue = this.activeSwatch.nextSibling;
let swatch = this.swatches.get(this.activeSwatch);
this.widget.then(widget => {
widget.off("updated", this._onUpdate);
widget.cssCubicBezierValue = this.currentBezierValue.textContent;
widget.on("updated", this._onUpdate);
});
}
},
_onUpdate: function(event, bezier) {
if (!this.activeSwatch) {
return;
}
this.currentBezierValue.textContent = bezier + "";
this.preview(bezier + "");
},
destroy: function() {
SwatchBasedEditorTooltip.prototype.destroy.call(this);
this.currentBezierValue = null;
this.widget.then(widget => {
widget.off("updated", this._onUpdate);
widget.destroy();
});
}
});
/**
* L10N utility class

Просмотреть файл

@ -76,7 +76,7 @@ function initializeAutoCompletion(ctx, options = {}) {
});
};
keyMap[Editor.keyFor("showInformation", { noaccel: true })] = (cm) => {
keyMap[Editor.keyFor("showInformation2", { noaccel: true })] = (cm) => {
cm.tern.showType(cm, null, () => {
ed.emit("show-information");
});

Просмотреть файл

@ -689,6 +689,8 @@ Rule.prototype = {
* The property's priority (either "important" or an empty string).
*/
previewPropertyValue: function(aProperty, aValue, aPriority) {
aProperty.value = aValue;
let modifications = this.style.startModifyingProperties();
modifications.setProperty(aProperty.name, aValue, aPriority);
modifications.apply();
@ -1406,7 +1408,7 @@ CssRuleView.prototype = {
*/
get isEditing() {
return this.element.querySelectorAll(".styleinspector-propertyeditor").length > 0
|| this.tooltips.colorPicker.tooltip.isShown();
|| this.tooltips.isEditing;
},
_handlePrefChange: function(pref) {
@ -2168,9 +2170,7 @@ TextPropertyEditor.prototype = {
*/
get editing() {
return !!(this.nameSpan.inplaceEditor || this.valueSpan.inplaceEditor ||
this.ruleEditor.ruleView.tooltips.colorPicker.tooltip.isShown() ||
this.ruleEditor.ruleView.tooltips.colorPicker.eyedropperOpen) ||
this.popup.isOpen;
this.ruleEditor.ruleView.tooltips.isEditing) || this.popup.isOpen;
},
/**
@ -2405,11 +2405,15 @@ TextPropertyEditor.prototype = {
this.element.removeAttribute("dirty");
}
let swatchClass = "ruleview-colorswatch";
let colorSwatchClass = "ruleview-colorswatch";
let bezierSwatchClass = "ruleview-bezierswatch";
let outputParser = this.ruleEditor.ruleView._outputParser;
let frag = outputParser.parseCssProperty(name, val, {
colorSwatchClass: swatchClass,
colorSwatchClass: colorSwatchClass,
colorClass: "ruleview-color",
bezierSwatchClass: bezierSwatchClass,
bezierClass: "ruleview-bezier",
defaultColorType: !propDirty,
urlClass: "theme-link",
baseURI: this.sheetURI
@ -2418,9 +2422,9 @@ TextPropertyEditor.prototype = {
this.valueSpan.appendChild(frag);
// Attach the color picker tooltip to the color swatches
this._swatchSpans = this.valueSpan.querySelectorAll("." + swatchClass);
this._colorSwatchSpans = this.valueSpan.querySelectorAll("." + colorSwatchClass);
if (this.ruleEditor.isEditable) {
for (let span of this._swatchSpans) {
for (let span of this._colorSwatchSpans) {
// Capture the original declaration value to be able to revert later
let originalValue = this.valueSpan.textContent;
// Adding this swatch to the list of swatches our colorpicker knows about
@ -2432,6 +2436,21 @@ TextPropertyEditor.prototype = {
}
}
// Attach the cubic-bezier tooltip to the bezier swatches
this._bezierSwatchSpans = this.valueSpan.querySelectorAll("." + bezierSwatchClass);
if (this.ruleEditor.isEditable) {
for (let span of this._bezierSwatchSpans) {
// Capture the original declaration value to be able to revert later
let originalValue = this.valueSpan.textContent;
// Adding this swatch to the list of swatches our colorpicker knows about
this.ruleEditor.ruleView.tooltips.cubicBezier.addSwatch(span, {
onPreview: () => this._previewValue(this.valueSpan.textContent),
onCommit: () => this._applyNewValue(this.valueSpan.textContent),
onRevert: () => this._applyNewValue(originalValue)
});
}
}
// Populate the computed styles.
this._updateComputed();
},
@ -2563,8 +2582,8 @@ TextPropertyEditor.prototype = {
* Begin editing next available property.
*/
remove: function() {
if (this._swatchSpans && this._swatchSpans.length) {
for (let span of this._swatchSpans) {
if (this._colorSwatchSpans && this._colorSwatchSpans.length) {
for (let span of this._colorSwatchSpans) {
this.ruleEditor.ruleView.tooltips.colorPicker.removeSwatch(span);
}
}

Просмотреть файл

@ -15,7 +15,8 @@
const {Cc, Ci, Cu} = require("chrome");
const {
Tooltip,
SwatchColorPickerTooltip
SwatchColorPickerTooltip,
SwatchCubicBezierTooltip
} = require("devtools/shared/widgets/Tooltip");
const {CssLogic} = require("devtools/styleinspector/css-logic");
const {Promise:promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
@ -237,6 +238,12 @@ function TooltipsOverlay(view) {
exports.TooltipsOverlay = TooltipsOverlay;
TooltipsOverlay.prototype = {
get isEditing() {
return this.colorPicker.tooltip.isShown() ||
this.colorPicker.eyedropperOpen ||
this.cubicBezier.tooltip.isShown();
},
/**
* Add the tooltips overlay to the view. This will start tracking mouse
* movements and display tooltips when needed
@ -251,9 +258,11 @@ TooltipsOverlay.prototype = {
this.previewTooltip.startTogglingOnHover(this.view.element,
this._onPreviewTooltipTargetHover.bind(this));
// Color picker tooltip
if (this.isRuleView) {
// Color picker tooltip
this.colorPicker = new SwatchColorPickerTooltip(this.view.inspector.panelDoc);
// Cubic bezier tooltip
this.cubicBezier = new SwatchCubicBezierTooltip(this.view.inspector.panelDoc);
}
this._isStarted = true;
@ -275,6 +284,10 @@ TooltipsOverlay.prototype = {
this.colorPicker.destroy();
}
if (this.cubicBezier) {
this.cubicBezier.destroy();
}
this._isStarted = false;
},
@ -329,6 +342,11 @@ TooltipsOverlay.prototype = {
this.colorPicker.hide();
}
if (this.isRuleView && this.cubicBezier.tooltip.isShown()) {
this.cubicBezier.revert();
this.cubicBezier.hide();
}
let inspector = this.view.inspector;
if (type === TOOLTIP_IMAGE_TYPE) {
@ -353,6 +371,10 @@ TooltipsOverlay.prototype = {
if (this.colorPicker) {
this.colorPicker.hide();
}
if (this.cubicBezier) {
this.cubicBezier.hide();
}
},
/**

Просмотреть файл

@ -60,6 +60,9 @@ support-files =
[browser_ruleview_completion-new-property_02.js]
[browser_ruleview_content_01.js]
[browser_ruleview_content_02.js]
[browser_ruleview_cubicbezier-appears-on-swatch-click.js]
[browser_ruleview_cubicbezier-commit-on-ENTER.js]
[browser_ruleview_cubicbezier-revert-on-ESC.js]
[browser_ruleview_edit-property-commit.js]
[browser_ruleview_edit-property-increments.js]
[browser_ruleview_edit-property-order.js]

Просмотреть файл

@ -7,7 +7,7 @@
// Tests that the checkbox to include browser styles works properly.
let test = asyncTest(function*() {
yield addTab("data:text/html,default styles test");
yield addTab("data:text/html;charset=utf-8,default styles test");
info("Creating the test document");
content.document.body.innerHTML = '<style type="text/css"> ' +

Просмотреть файл

@ -7,7 +7,7 @@
// Test computed view key bindings
let test = asyncTest(function*() {
yield addTab("data:text/html,default styles test");
yield addTab("data:text/html;charset=utf-8,default styles test");
info("Adding content to the test page");
content.document.body.innerHTML = '<style type="text/css"> ' +

Просмотреть файл

@ -7,7 +7,7 @@
// Tests the computed-view keyboard navigation
let test = asyncTest(function*() {
yield addTab("data:text/html,computed view keyboard nav test");
yield addTab("data:text/html;charset=utf-8,computed view keyboard nav test");
content.document.body.innerHTML = '<style type="text/css"> ' +
'span { font-variant: small-caps; color: #000000; } ' +

Просмотреть файл

@ -7,7 +7,7 @@
// Test that the computed view properties can be expanded and collapsed with
// either the twisty or by dbl-clicking on the container
const TEST_URL = "data:text/html," + encodeURIComponent([
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent([
'<html>' +
'<head>' +
' <title>Computed view toggling test</title>',

Просмотреть файл

@ -7,7 +7,7 @@
// Tests for matched selector texts in the computed view
let test = asyncTest(function*() {
yield addTab("data:text/html,<div style='color:blue;'></div>");
yield addTab("data:text/html;charset=utf-8,<div style='color:blue;'></div>");
info("Opening the computed view");
let {toolbox, inspector, view} = yield openComputedView();

Просмотреть файл

@ -7,7 +7,7 @@
// Tests that the no results placeholder works properly.
let test = asyncTest(function*() {
yield addTab("data:text/html,no results placeholder test");
yield addTab("data:text/html;charset=utf-8,no results placeholder test");
info("Creating the test document");
content.document.body.innerHTML = '<style type="text/css"> ' +

Просмотреть файл

@ -7,7 +7,7 @@
// Tests that the search filter works properly.
let test = asyncTest(function*() {
yield addTab("data:text/html,default styles test");
yield addTab("data:text/html;charset=utf-8,default styles test");
info("Creating the test document");
content.document.body.innerHTML = '<style type="text/css"> ' +

Просмотреть файл

@ -11,7 +11,7 @@ XPCOMUtils.defineLazyGetter(this, "osString", function() {
});
let test = asyncTest(function*() {
yield addTab("data:text/html,computed view copy test");
yield addTab("data:text/html;charset=utf-8,computed view copy test");
info("Creating the test document");
content.document.body.innerHTML = '<style type="text/css"> ' +

Просмотреть файл

@ -11,7 +11,7 @@ const STYLESHEET_URL = "data:text/css,"+encodeURIComponent(
"color: blue",
"}"].join("\n"));
const DOCUMENT_URL = "data:text/html,"+encodeURIComponent(
const DOCUMENT_URL = "data:text/html;charset=utf-8,"+encodeURIComponent(
['<html>' +
'<head>' +
'<title>Computed view style editor link test</title>',

Просмотреть файл

@ -20,7 +20,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view user changes");
yield addTab("data:text/html;charset=utf-8,test rule view user changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -17,7 +17,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view user changes");
yield addTab("data:text/html;charset=utf-8,test rule view user changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -22,7 +22,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view user changes");
yield addTab("data:text/html;charset=utf-8,test rule view user changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -62,7 +62,7 @@ function* testCreateNew(inspector, ruleView) {
editor.input.value = "purple";
let onBlur = once(editor.input, "blur");
editor.input.blur();
EventUtils.sendKey("return", ruleView.doc.defaultView);
yield onBlur;
yield elementRuleEditor.rule._applyingModifications;

Просмотреть файл

@ -18,7 +18,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -20,7 +20,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();
yield testColorChangeIsntRevertedWhenOtherTooltipIsShown(view);

Просмотреть файл

@ -19,7 +19,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -16,7 +16,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -17,7 +17,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -19,7 +19,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -25,7 +25,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -16,7 +16,7 @@ const PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -38,7 +38,7 @@ const TESTS = [
];
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view color picker tooltip test");
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -52,7 +52,7 @@ let testData = [
["VK_ESCAPE", null, -1, 0],
];
let TEST_URL = "data:text/html,<h1 style='border: 1px solid red'>Filename" +
let TEST_URL = "data:text/html;charset=utf-8,<h1 style='border: 1px solid red'>Filename" +
": browser_bug893965_css_property_completion_existing_property.js</h1>";
let test = asyncTest(function*() {

Просмотреть файл

@ -36,7 +36,7 @@ let testData = [
["VK_RETURN", {}, null, -1, 0]
];
let TEST_URL = "data:text/html,<h1 style='color: red'>Filename: " +
let TEST_URL = "data:text/html;charset=utf-8,<h1 style='color: red'>Filename: " +
"browser_bug894376_css_value_completion_existing_property_value_pair.js</h1>";
let test = asyncTest(function*() {

Просмотреть файл

@ -37,7 +37,7 @@ let testData = [
["VK_ESCAPE", null, -1, 0],
];
let TEST_URL = "data:text/html,<h1 style='border: 1px solid red'>Filename:" +
let TEST_URL = "data:text/html;charset=utf-8,<h1 style='border: 1px solid red'>Filename:" +
"browser_bug893965_css_property_completion_new_property.js</h1>";
let test = asyncTest(function*() {

Просмотреть файл

@ -39,7 +39,7 @@ let testData = [
["VK_ESCAPE", {}, null, -1, 0]
];
let TEST_URL = "data:text/html,<style>h1{border: 1px solid red}</style>" +
let TEST_URL = "data:text/html;charset=utf-8,<style>h1{border: 1px solid red}</style>" +
"<h1>Test element</h1>";
let test = asyncTest(function*() {

Просмотреть файл

@ -0,0 +1,70 @@
/* vim: set ft=javascript 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 cubic-bezier pickers appear when clicking on cubic-bezier swatches
const PAGE_CONTENT = [
'<style type="text/css">',
' div {',
' animation: move 3s linear;',
' transition: top 4s cubic-bezier(.1, 1.45, 1, -1.2);',
' }',
' .test {',
' animation-timing-function: ease-in-out;',
' transition-timing-function: ease-out;',
' }',
'</style>',
'<div class="test">Testing the cubic-bezier tooltip!</div>'
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html;charset=utf-8,rule view cubic-bezier tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();
yield selectNode("div", inspector);
let swatches = [];
swatches.push(
getRuleViewProperty(view, "div", "animation").valueSpan
.querySelector(".ruleview-bezierswatch")
);
swatches.push(
getRuleViewProperty(view, "div", "transition").valueSpan
.querySelector(".ruleview-bezierswatch")
);
swatches.push(
getRuleViewProperty(view, ".test", "animation-timing-function").valueSpan
.querySelector(".ruleview-bezierswatch")
);
swatches.push(
getRuleViewProperty(view, ".test", "transition-timing-function").valueSpan
.querySelector(".ruleview-bezierswatch")
);
for (let swatch of swatches) {
info("Testing that the cubic-bezier appears on cubicswatch click");
yield testAppears(view, swatch);
}
});
function* testAppears(view, swatch) {
ok(swatch, "The cubic-swatch exists");
let bezier = view.tooltips.cubicBezier;
ok(bezier, "The rule-view has the expected cubicBezier property");
let bezierPanel = bezier.tooltip.panel;
ok(bezierPanel, "The XUL panel for the cubic-bezier tooltip exists");
let onShown = bezier.tooltip.once("shown");
swatch.click();
yield onShown;
ok(true, "The cubic-bezier tooltip was shown on click of the cibuc swatch");
ok(!inplaceEditor(swatch.parentNode),
"The inplace editor wasn't shown as a result of the cibuc swatch click");
bezier.hide();
}

Просмотреть файл

@ -0,0 +1,61 @@
/* vim: set ft=javascript 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 a curve change in the cubic-bezier tooltip is committed when ENTER
// is pressed
const PAGE_CONTENT = [
'<style type="text/css">',
' body {',
' transition: top 2s linear;',
' }',
'</style>'
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html;charset=utf-8,rule view cubic-bezier tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();
info("Getting the bezier swatch element");
let swatch = getRuleViewProperty(view, "body" , "transition").valueSpan
.querySelector(".ruleview-bezierswatch");
yield testPressingEnterCommitsChanges(swatch, view);
});
function* testPressingEnterCommitsChanges(swatch, ruleView) {
let bezierTooltip = ruleView.tooltips.cubicBezier;
info("Showing the tooltip");
let onShown = bezierTooltip.tooltip.once("shown");
swatch.click();
yield onShown;
let widget = yield bezierTooltip.widget;
info("Simulating a change of curve in the widget");
widget.coordinates = [0.1, 2, 0.9, -1];
let expected = "cubic-bezier(0.1, 2, 0.9, -1)";
yield waitForSuccess(() => {
return content.getComputedStyle(content.document.body).transitionTimingFunction === expected;
}, "Waiting for the change to be previewed on the element");
ok(getRuleViewProperty(ruleView, "body", "transition").valueSpan.textContent
.indexOf("cubic-bezier(") !== -1,
"The text of the timing-function was updated");
info("Sending RETURN key within the tooltip document");
let onHidden = bezierTooltip.tooltip.once("hidden");
EventUtils.sendKey("RETURN", widget.parent.ownerDocument.defaultView);
yield onHidden;
is(content.getComputedStyle(content.document.body).transitionTimingFunction,
expected, "The element's timing-function was kept after RETURN");
ok(getRuleViewProperty(ruleView, "body", "transition").valueSpan.textContent
.indexOf("cubic-bezier(") !== -1,
"The text of the timing-function was kept after RETURN");
}

Просмотреть файл

@ -0,0 +1,53 @@
/* vim: set ft=javascript 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 changes made to the cubic-bezier timing-function in the cubic-bezier
// tooltip are reverted when ESC is pressed
const PAGE_CONTENT = [
'<style type="text/css">',
' body {',
' animation-timing-function: linear;',
' }',
'</style>',
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html;charset=utf-8,rule view cubic-bezier tooltip test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();
info("Getting the bezier swatch element");
let swatch = getRuleViewProperty(view, "body", "animation-timing-function").valueSpan
.querySelector(".ruleview-bezierswatch");
yield testPressingEscapeRevertsChanges(swatch, view);
});
function* testPressingEscapeRevertsChanges(swatch, ruleView) {
let bezierTooltip = ruleView.tooltips.cubicBezier;
let onShown = bezierTooltip.tooltip.once("shown");
swatch.click();
yield onShown;
let widget = yield bezierTooltip.widget;
info("Simulating a change of curve in the widget");
widget.coordinates = [0.1, 2, 0.9, -1];
let expected = "cubic-bezier(0.1, 2, 0.9, -1)";
yield waitForSuccess(() => {
return content.getComputedStyle(content.document.body).animationTimingFunction === expected;
}, "Waiting for the change to be previewed on the element");
info("Pressing ESCAPE to close the tooltip");
let onHidden = bezierTooltip.tooltip.once("hidden");
EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
yield onHidden;
yield waitForSuccess(() => {
return content.getComputedStyle(content.document.body).animationTimingFunction === "cubic-bezier(0, 0, 1, 1)";
}, "Waiting for the change to be reverted on the element");
}

Просмотреть файл

@ -24,7 +24,7 @@ const testData = [
];
let test = asyncTest(function*() {
yield addTab("data:text/html,test escaping property change reverts back to original value");
yield addTab("data:text/html;charset=utf-8,test escaping property change reverts back to original value");
info("Creating the test document");
createDocument();

Просмотреть файл

@ -8,7 +8,7 @@
// arrow keys works correctly.
let test = asyncTest(function*() {
yield addTab("data:text/html,sample document for bug 722691");
yield addTab("data:text/html;charset=utf-8,sample document for bug 722691");
createDocument();
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -22,7 +22,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view user changes");
yield addTab("data:text/html;charset=utf-8,test rule view user changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -48,7 +48,7 @@ const TEST_DATA = [
];
let test = asyncTest(function*() {
yield addTab("data:text/html,test escaping selector change reverts back to original value");
yield addTab("data:text/html;charset=utf-8,test escaping selector change reverts back to original value");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -17,7 +17,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view selector changes");
yield addTab("data:text/html;charset=utf-8,test rule view selector changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -23,7 +23,7 @@ let PAGE_CONTENT = [
].join("\n");
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view selector changes");
yield addTab("data:text/html;charset=utf-8,test rule view selector changes");
info("Creating the test document");
content.document.body.innerHTML = PAGE_CONTENT;

Просмотреть файл

@ -26,7 +26,7 @@ const EXPECTED_COLOR = "rgb(255, 255, 85)"; // #ff5
// to close it, and clicking the page to select a color.
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view eyedropper test");
yield addTab("data:text/html;charset=utf-8,rule view eyedropper test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();

Просмотреть файл

@ -8,7 +8,7 @@
// (bug 719916)
let test = asyncTest(function*() {
yield addTab("data:text/html,<h1>Some header text</h1>");
yield addTab("data:text/html;charset=utf-8,<h1>Some header text</h1>");
let {toolbox, inspector, view} = yield openRuleView();
info("Selecting the test node");

Просмотреть файл

@ -23,7 +23,7 @@ const TEST_DATA = [
];
let test = asyncTest(function*() {
yield addTab("data:text/html,test rule view live preview on user changes");
yield addTab("data:text/html;charset=utf-8,test rule view live preview on user changes");
let style = '#testid {display:block;}';
let styleNode = addStyle(content.document, style);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше