зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c a=merge
This commit is contained in:
Коммит
a7ffe505ae
|
@ -26,8 +26,6 @@ let gDataNotificationInfoBar = {
|
|||
|
||||
init: function() {
|
||||
window.addEventListener("unload", function onUnload() {
|
||||
window.removeEventListener("unload", onUnload, false);
|
||||
|
||||
for (let o of this._OBSERVERS) {
|
||||
Services.obs.removeObserver(this, o);
|
||||
}
|
||||
|
|
|
@ -1012,8 +1012,8 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
|
|||
}
|
||||
|
||||
/* Combobox dropdown renderer */
|
||||
#ContentSelectDropdown {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
|
||||
#ContentSelectDropdown > menupopup {
|
||||
max-height: 350px;
|
||||
}
|
||||
|
||||
.contentSelectDropdown-optgroup {
|
||||
|
|
|
@ -146,8 +146,13 @@
|
|||
<!-- for url bar autocomplete -->
|
||||
<panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
|
||||
|
||||
<!-- for select dropdowns -->
|
||||
<menupopup id="ContentSelectDropdown" rolluponmousewheel="true" hidden="true"/>
|
||||
<!-- for select dropdowns. The menupopup is what shows the list of options,
|
||||
and the popuponly menulist makes things like the menuactive attributes
|
||||
work correctly on the menupopup. ContentSelectDropdown expects the
|
||||
popuponly menulist to be its immediate parent. -->
|
||||
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
|
||||
<menupopup rolluponmousewheel="true"/>
|
||||
</menulist>
|
||||
|
||||
<!-- for invalid form error message -->
|
||||
<panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
|
||||
|
@ -1169,7 +1174,7 @@
|
|||
tabcontainer="tabbrowser-tabs"
|
||||
contentcontextmenu="contentAreaContextMenu"
|
||||
autocompletepopup="PopupAutoComplete"
|
||||
selectpopup="ContentSelectDropdown"/>
|
||||
selectmenulist="ContentSelectDropdown"/>
|
||||
<chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
|
||||
</vbox>
|
||||
<splitter id="social-sidebar-splitter"
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<xul:vbox flex="1" class="browserContainer">
|
||||
<xul:stack flex="1" class="browserStack" anonid="browserStack">
|
||||
<xul:browser anonid="initialBrowser" type="content-primary" message="true" messagemanagergroup="browsers"
|
||||
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectpopup"/>
|
||||
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectmenulist"/>
|
||||
</xul:stack>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
|
@ -1600,8 +1600,8 @@
|
|||
if (!isPreloadBrowser && this.hasAttribute("autocompletepopup"))
|
||||
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
|
||||
|
||||
if (this.hasAttribute("selectpopup"))
|
||||
b.setAttribute("selectpopup", this.getAttribute("selectpopup"));
|
||||
if (this.hasAttribute("selectmenulist"))
|
||||
b.setAttribute("selectmenulist", this.getAttribute("selectmenulist"));
|
||||
|
||||
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
|
||||
|
|
|
@ -203,7 +203,6 @@ loop.shared.mixins = (function() {
|
|||
publishVideo: options.publishVideo,
|
||||
style: {
|
||||
audioLevelDisplayMode: "off",
|
||||
bugDisplayMode: "off",
|
||||
buttonDisplayMode: "off",
|
||||
nameDisplayMode: "off",
|
||||
videoDisabledDisplayMode: "off"
|
||||
|
|
|
@ -118,216 +118,88 @@
|
|||
|
||||
/* Modal dialog styles */
|
||||
|
||||
.OT_dialog-centering {
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.OT_dialog-centering-child {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.OT_dialog {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
box-sizing: border-box;
|
||||
max-width: 576px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 36px;
|
||||
text-align: center; /* centers all the inline content */
|
||||
|
||||
background-color: #363636;
|
||||
color: #fff;
|
||||
z-index: 9999;
|
||||
box-shadow: 2px 4px 6px #999;
|
||||
font-family: 'Didact Gothic', sans-serif;
|
||||
}
|
||||
|
||||
.OT_dialog-blackout {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #363636;
|
||||
}
|
||||
|
||||
.OT_dialog-blackout .OT_dialog {
|
||||
box-shadow: 0 0 0 transparent;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.OT_dialog * {
|
||||
font-family: 'Didact Gothic', sans-serif;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-prompt {
|
||||
margin-left: -350px;
|
||||
margin-top: -127px;
|
||||
width: 650px;
|
||||
height: 254px;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-reinstall {
|
||||
margin-left: -271px;
|
||||
margin-top: -107px;
|
||||
width: 542px;
|
||||
height: 214px;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-upgrading {
|
||||
margin-left: -267px;
|
||||
margin-top: -94px;
|
||||
width: 514px;
|
||||
height: 188px;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-upgraded {
|
||||
margin-left: -300px;
|
||||
margin-top: -100px;
|
||||
width: 600px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-chrome-first {
|
||||
margin-left: -227px;
|
||||
margin-top: -122px;
|
||||
width: 453px;
|
||||
height: 244px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-chrome-pre-denied {
|
||||
margin-left: -263px;
|
||||
margin-top: -135px;
|
||||
width: 526px;
|
||||
height: 270px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-chrome-now-denied {
|
||||
margin-left: -120px;
|
||||
margin-top: -85px;
|
||||
width: 256px;
|
||||
height: 170px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-firefox-denied {
|
||||
margin-left: -160px;
|
||||
margin-top: -105px;
|
||||
width: 320px;
|
||||
height: 190px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-firefox-maybe-denied {
|
||||
margin-left: -281px;
|
||||
margin-top: -126px;
|
||||
width: 562px;
|
||||
height: 252px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-highlight-chrome {
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
width: 227px;
|
||||
height: 94px;
|
||||
background-image: url(../images/rtc/access-prompt-chrome.png);
|
||||
font-family: inherit;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
.OT_closeButton {
|
||||
color: #999999;
|
||||
cursor: pointer;
|
||||
font-size: 32px;
|
||||
line-height: 30px;
|
||||
line-height: 36px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
right: 18px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.OT_dialog-messages {
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
left: 32px;
|
||||
right: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages {
|
||||
top: 45px;
|
||||
}
|
||||
|
||||
|
||||
.OT_dialog-messages-main {
|
||||
margin-bottom: 36px;
|
||||
line-height: 36px;
|
||||
|
||||
font-weight: 300;
|
||||
font-size: 18pt;
|
||||
line-height: 24px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.OT_dialog-messages-minor {
|
||||
font-weight: 300;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 18px;
|
||||
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
color: #A4A4A4;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages-minor {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.OT_dialog-messages-minor strong {
|
||||
font-weight: 300;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.OT_dialog-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.OT_dialog-single-button {
|
||||
position: absolute;
|
||||
bottom: 41px;
|
||||
left: 50%;
|
||||
margin-left: -97px;
|
||||
height: 47px;
|
||||
width: 193px;
|
||||
}
|
||||
|
||||
|
||||
.OT_dialog-single-button-wide {
|
||||
bottom: 35px;
|
||||
height: 140px;
|
||||
left: 5px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
.OT_dialog-single-button-with-title {
|
||||
margin: 0 auto;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
width: 270px;
|
||||
}
|
||||
|
||||
|
||||
.OT_dialog-button-pair {
|
||||
position: absolute;
|
||||
bottom: 45px;
|
||||
left: 5px;
|
||||
right: 0;
|
||||
height: 94px;
|
||||
}
|
||||
|
||||
.OT_dialog-button-with-title {
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
width: 260px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.OT_dialog-button-pair-seperator {
|
||||
border-right: 1px solid #555555;
|
||||
height: 112px;
|
||||
width: 1px;
|
||||
float: left;
|
||||
.OT_dialog-actions-card {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.OT_dialog-button-title {
|
||||
margin-bottom: 18px;
|
||||
line-height: 18px;
|
||||
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 14px;
|
||||
line-height: 150%;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.OT_dialog-button-title label {
|
||||
color: #999999;
|
||||
}
|
||||
|
@ -345,13 +217,13 @@
|
|||
}
|
||||
|
||||
.OT_dialog-button {
|
||||
font-weight: 100;
|
||||
display: block;
|
||||
line-height: 50px;
|
||||
height: 47px;
|
||||
display: inline-block;
|
||||
|
||||
margin-bottom: 18px;
|
||||
padding: 0 1em;
|
||||
|
||||
background-color: #1CA3DC;
|
||||
text-align: center;
|
||||
font-size: 16pt;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -364,138 +236,67 @@
|
|||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.OT_dialog-button.OT_dialog-button-large {
|
||||
line-height: 60px;
|
||||
height: 58px;
|
||||
.OT_dialog-button-large {
|
||||
line-height: 36px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
|
||||
font-weight: 100;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.OT_dialog-button.OT_dialog-button-small {
|
||||
.OT_dialog-button-small {
|
||||
line-height: 18px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
|
||||
background-color: #444444;
|
||||
color: #999999;
|
||||
font-size: 12pt;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
margin: 20px auto 0 auto;
|
||||
width: 86px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.OT_dialog-progress-bar {
|
||||
display: inline-block; /* prevents margin collapse */
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 41px;
|
||||
|
||||
border: 1px solid #4E4E4E;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.OT_dialog-progress-bar-fill {
|
||||
height: 100%;
|
||||
|
||||
background-color: #29A4DA;
|
||||
height: 10px;
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-upgrading .OT_dialog-plugin-upgrade-percentage {
|
||||
font-size: 36pt;
|
||||
line-height: 54px;
|
||||
|
||||
font-size: 48px;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
.OT_dialog-plugin-upgrading .OT_dialog-progress-bar {
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.OT_dialog-3steps {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-3steps {
|
||||
margin-top: 21px;
|
||||
}
|
||||
|
||||
.OT_dialog-3steps-step {
|
||||
float: left;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 33%;
|
||||
height: 140px;
|
||||
padding: 0 10px;
|
||||
color: #A4A4A4;
|
||||
}
|
||||
|
||||
.OT_dialog-3steps-seperator {
|
||||
float: left;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin-top: 10px;
|
||||
width: 1px;
|
||||
height: 68px;
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-seperator {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.OT_dialog-3steps-step-num {
|
||||
font-size: 20px;
|
||||
background-color: #2AA3D8;
|
||||
border-radius: 20px;
|
||||
line-height: 33px;
|
||||
height: 33px;
|
||||
width: 33px;
|
||||
margin: 0 auto 17px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-step-num {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.OT_dialog-allow-camera-icon {
|
||||
background-color: #000;
|
||||
width: 113px;
|
||||
height: 48px;
|
||||
margin: 10px auto 0;
|
||||
background-image: url(../images/rtc/access-predenied-chrome.png);
|
||||
}
|
||||
|
||||
/* Publisher Deny Helpers */
|
||||
|
||||
.OT_publisher-denied-firefox {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.OT_publisher-denied-firefox p {
|
||||
width: 232px;
|
||||
height: 103px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin-top: -52px;
|
||||
margin-left: -116px;
|
||||
background-image: url(../images/rtc/access-denied-firefox.png);
|
||||
background-position: 50% 0;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.OT_publisher-denied-firefox span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
width: 232px;
|
||||
height: 31px;
|
||||
background-image: url(../images/rtc/access-denied-copy-firefox.png);
|
||||
text-indent: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* Helpers */
|
||||
|
||||
.OT_centered {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.OT_dialog-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.OT_dialog-button-block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.OT_dialog-no-natural-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Publisher and Subscriber styles */
|
||||
|
@ -803,21 +604,14 @@
|
|||
|
||||
.OT_publisher .OT_name,
|
||||
.OT_subscriber .OT_name {
|
||||
left: 24px;
|
||||
left: 10px;
|
||||
right: 37px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_name-no-bug,
|
||||
.OT_subscriber .OT_name-no-bug {
|
||||
left: 10px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_mute,
|
||||
.OT_subscriber .OT_mute,
|
||||
.OT_publisher .OT_opentok,
|
||||
.OT_subscriber .OT_opentok {
|
||||
.OT_subscriber .OT_mute {
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
|
@ -828,21 +622,6 @@
|
|||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_opentok,
|
||||
.OT_subscriber .OT_opentok {
|
||||
background: url(../images/rtc/buttons.png) 0 -32px no-repeat;
|
||||
cursor: default;
|
||||
height: 18px;
|
||||
left: 8px;
|
||||
line-height: 18px;
|
||||
top: 8px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.OT_micro .OT_opentok {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_mute,
|
||||
.OT_subscriber .OT_mute {
|
||||
right: 0;
|
||||
|
@ -883,21 +662,6 @@
|
|||
background-position: 7px 7px;
|
||||
}
|
||||
|
||||
/* Disabling this for now - see https://jira.tokbox.com/browse/OPENTOK-8870
|
||||
.OT_publisher .OT_opentok:hover:after,
|
||||
.OT_subscriber .OT_opentok:hover:after {
|
||||
content: 'tokbox';
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
letter-spacing: -1px;
|
||||
top: 20px;
|
||||
opacity: 0.5;
|
||||
position: absolute;
|
||||
text-indent: 0;
|
||||
top: 0;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Styles for display modes
|
||||
*
|
||||
|
@ -975,23 +739,6 @@
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_opentok.OT_mode-off,
|
||||
.OT_publisher .OT_opentok.OT_mode-auto,
|
||||
.OT_subscriber .OT_opentok.OT_mode-off,
|
||||
.OT_subscriber .OT_opentok.OT_mode-auto {
|
||||
top: -17px;
|
||||
}
|
||||
|
||||
.OT_publisher .OT_opentok.OT_mode-on,
|
||||
.OT_publisher .OT_opentok.OT_mode-auto.OT_mode-on-hold,
|
||||
.OT_publisher:hover .OT_opentok.OT_mode-auto,
|
||||
.OT_subscriber .OT_opentok.OT_mode-on,
|
||||
.OT_subscriber .OT_opentok.OT_mode-auto.OT_mode-on-hold,
|
||||
.OT_subscriber:hover .OT_opentok.OT_mode-auto {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
|
||||
/* Contains the video element, used to fix video letter-boxing */
|
||||
.OT_video-container {
|
||||
position: absolute;
|
||||
|
@ -1095,7 +842,7 @@
|
|||
background-image: radial-gradient(circle, rgba(151,206,0,1) 0%, rgba(151,206,0,0) 100%);
|
||||
}
|
||||
|
||||
.OT_audio-level-meter {
|
||||
.OT_audio-level-meter.OT_mode-off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -701,7 +701,7 @@ let CallsListView = Heritage.extend(WidgetMethods, {
|
|||
let dimensionsNode = $("#screenshot-dimensions");
|
||||
let actualWidth = (width / scaling) | 0;
|
||||
let actualHeight = (height / scaling) | 0;
|
||||
dimensionsNode.setAttribute("value", actualWidth + " x " + actualHeight);
|
||||
dimensionsNode.setAttribute("value", actualWidth + " \u00D7 " + actualHeight);
|
||||
|
||||
window.emit(EVENTS.CALL_SCREENSHOT_DISPLAYED);
|
||||
},
|
||||
|
|
|
@ -20,7 +20,7 @@ function ifTestingSupported() {
|
|||
is($("#screenshot-container").hidden, false,
|
||||
"The screenshot container should now be visible.");
|
||||
|
||||
is($("#screenshot-dimensions").getAttribute("value"), "128 x 128",
|
||||
is($("#screenshot-dimensions").getAttribute("value"), "128" + " \u00D7 " + "128",
|
||||
"The screenshot dimensions label has the expected value.");
|
||||
|
||||
is($("#screenshot-image").getAttribute("flipped"), "false",
|
||||
|
|
|
@ -20,7 +20,7 @@ add_task(function*() {
|
|||
tag: "DIV",
|
||||
id: "top",
|
||||
classes: ".class1.class2",
|
||||
dims: "500 x 100"
|
||||
dims: "500" + " \u00D7 " + "100"
|
||||
},
|
||||
{
|
||||
selector: "#vertical",
|
||||
|
@ -36,7 +36,7 @@ add_task(function*() {
|
|||
tag: "DIV",
|
||||
id: "bottom",
|
||||
classes: "",
|
||||
dims: "500 x 100"
|
||||
dims: "500" + " \u00D7 " + "100"
|
||||
},
|
||||
{
|
||||
selector: "body",
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
// Expected values:
|
||||
let res1 = [
|
||||
{selector: "#element-size", value: "160x160"},
|
||||
{selector: ".size > span", value: "100x100"},
|
||||
{selector: "#element-size", value: "160" + "\u00D7" + "160"},
|
||||
{selector: ".size > span", value: "100" + "\u00D7" + "100"},
|
||||
{selector: ".margin.top > span", value: 30},
|
||||
{selector: ".margin.left > span", value: "auto"},
|
||||
{selector: ".margin.bottom > span", value: 30},
|
||||
|
@ -26,8 +26,8 @@ let res1 = [
|
|||
];
|
||||
|
||||
let res2 = [
|
||||
{selector: "#element-size", value: "190x210"},
|
||||
{selector: ".size > span", value: "100x150"},
|
||||
{selector: "#element-size", value: "190" + "\u00D7" + "210"},
|
||||
{selector: ".size > span", value: "100" + "\u00D7" + "150"},
|
||||
{selector: ".margin.top > span", value: 30},
|
||||
{selector: ".margin.left > span", value: "auto"},
|
||||
{selector: ".margin.bottom > span", value: 30},
|
||||
|
|
|
@ -45,7 +45,7 @@ function*(inspector, view) {
|
|||
|
||||
info("Checking that the layout-view shows the right value");
|
||||
let sizeElt = view.doc.querySelector(".size > span");
|
||||
is(sizeElt.textContent, "100x100");
|
||||
is(sizeElt.textContent, "100" + "\u00D7" + "100");
|
||||
|
||||
info("Listening for layout-view changes and modifying the size");
|
||||
let onUpdated = waitForUpdate(inspector);
|
||||
|
@ -54,7 +54,7 @@ function*(inspector, view) {
|
|||
ok(true, "Layout-view got updated");
|
||||
|
||||
info("Checking that the layout-view shows the right value after update");
|
||||
is(sizeElt.textContent, "200x100");
|
||||
is(sizeElt.textContent, "200" + "\u00D7" + "100");
|
||||
});
|
||||
|
||||
addTest("Go back to the first page",
|
||||
|
|
|
@ -401,7 +401,7 @@ LayoutView.prototype = {
|
|||
this._lastRequest = null;
|
||||
let width = layout.width;
|
||||
let height = layout.height;
|
||||
let newLabel = width + "x" + height;
|
||||
let newLabel = width + "\u00D7" + height;
|
||||
if (this.sizeHeadingLabel.textContent != newLabel) {
|
||||
this.sizeHeadingLabel.textContent = newLabel;
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ LayoutView.prototype = {
|
|||
height -= this.map.borderTop.value + this.map.borderBottom.value +
|
||||
this.map.paddingTop.value + this.map.paddingBottom.value;
|
||||
|
||||
let newValue = width + "x" + height;
|
||||
let newValue = width + "\u00D7" + height;
|
||||
if (this.sizeLabel.textContent != newValue) {
|
||||
this.sizeLabel.textContent = newValue;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@ const PAGE_CONTENT = [
|
|||
].join("\n");
|
||||
|
||||
const TEST_NODES = [
|
||||
{selector: "img.local", size: "192 x 192"},
|
||||
{selector: "img.data", size: "64 x 64"},
|
||||
{selector: "img.remote", size: "22 x 23"},
|
||||
{selector: ".canvas", size: "600 x 600"}
|
||||
{selector: "img.local", size: "192" + " \u00D7 " + "192"},
|
||||
{selector: "img.data", size: "64" + " \u00D7 " + "64"},
|
||||
{selector: "img.remote", size: "22" + " \u00D7 " + "23"},
|
||||
{selector: ".canvas", size: "600" + " \u00D7 " + "600"}
|
||||
];
|
||||
|
||||
add_task(function*() {
|
||||
|
|
|
@ -1683,7 +1683,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
*/
|
||||
_onSecurityIconClick: function(e) {
|
||||
let state = this.selectedItem.attachment.securityState;
|
||||
if (state === "broken" || state === "secure") {
|
||||
if (state !== "insecure") {
|
||||
// Choose the security tab.
|
||||
NetMonitorView.NetworkDetails.widget.selectedIndex = 5;
|
||||
}
|
||||
|
@ -2605,7 +2605,7 @@ NetworkDetailsView.prototype = {
|
|||
// in width and height attributes like the rest of the folk. Hack around
|
||||
// this by getting the bounding client rect and subtracting the margins.
|
||||
let { width, height } = e.target.getBoundingClientRect();
|
||||
let dimensions = (width - 2) + " x " + (height - 2);
|
||||
let dimensions = (width - 2) + " \u00D7 " + (height - 2);
|
||||
$("#response-content-image-dimensions-value").setAttribute("value", dimensions);
|
||||
};
|
||||
}
|
||||
|
@ -2765,10 +2765,22 @@ NetworkDetailsView.prototype = {
|
|||
let errorbox = $("#security-error");
|
||||
let infobox = $("#security-information");
|
||||
|
||||
if (securityInfo.state === "secure") {
|
||||
if (securityInfo.state === "secure" || securityInfo.state === "weak") {
|
||||
infobox.hidden = false;
|
||||
errorbox.hidden = true;
|
||||
|
||||
// Warning icons
|
||||
let cipher = $("#security-warning-cipher");
|
||||
let sslv3 = $("#security-warning-sslv3");
|
||||
|
||||
if (securityInfo.state === "weak") {
|
||||
cipher.hidden = securityInfo.weaknessReasons.indexOf("cipher") === -1;
|
||||
sslv3.hidden = securityInfo.weaknessReasons.indexOf("sslv3") === -1;
|
||||
} else {
|
||||
cipher.hidden = true;
|
||||
sslv3.hidden = true;
|
||||
}
|
||||
|
||||
let enabledLabel = L10N.getStr("netmonitor.security.enabled");
|
||||
let disabledLabel = L10N.getStr("netmonitor.security.disabled");
|
||||
|
||||
|
|
|
@ -506,6 +506,9 @@
|
|||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
<image class="security-warning-icon"
|
||||
id="security-warning-sslv3"
|
||||
tooltiptext="&netmonitorUI.security.warning.sslv3;" />
|
||||
</hbox>
|
||||
<hbox id="security-ciphersuite"
|
||||
class="tabpanel-summary-container"
|
||||
|
@ -516,6 +519,9 @@
|
|||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
<image class="security-warning-icon"
|
||||
id="security-warning-cipher"
|
||||
tooltiptext="&netmonitorUI.security.warning.cipher;" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
|
|
@ -92,6 +92,7 @@ skip-if = e10s # Bug 1091612
|
|||
[browser_net_security-state.js]
|
||||
[browser_net_security-tab-deselect.js]
|
||||
[browser_net_security-tab-visibility.js]
|
||||
[browser_net_security-warnings.js]
|
||||
[browser_net_simple-init.js]
|
||||
[browser_net_simple-request-data.js]
|
||||
[browser_net_simple-request-details.js]
|
||||
|
|
|
@ -208,7 +208,7 @@ function test() {
|
|||
.getAttribute("value"), "base64",
|
||||
"The image encoding info isn't correct.");
|
||||
is(tabpanel.querySelector("#response-content-image-dimensions-value")
|
||||
.getAttribute("value"), "16 x 16",
|
||||
.getAttribute("value"), "16" + " \u00D7 " + "16",
|
||||
"The image dimensions info isn't correct.");
|
||||
|
||||
deferred.resolve();
|
||||
|
|
|
@ -13,6 +13,7 @@ add_task(function* () {
|
|||
"test1.example.com": "security-state-insecure",
|
||||
"example.com": "security-state-secure",
|
||||
"nocert.example.com": "security-state-broken",
|
||||
"rc4.example.com": "security-state-weak",
|
||||
};
|
||||
|
||||
let [tab, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
|
@ -70,7 +71,12 @@ add_task(function* () {
|
|||
debuggee.performRequests(1, "https://example.com" + CORS_SJS_PATH);
|
||||
yield done;
|
||||
|
||||
is(RequestsMenu.itemCount, 3, "Three events logged.");
|
||||
done = waitForNetworkEvents(monitor, 1);
|
||||
info("Requesting a resource over HTTPS with RC4.");
|
||||
debuggee.performRequests(1, "https://rc4.example.com" + CORS_SJS_PATH);
|
||||
yield done;
|
||||
|
||||
is(RequestsMenu.itemCount, 4, "Four events logged.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* 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 warning indicators are shown when appropriate.
|
||||
*/
|
||||
|
||||
const TEST_CASES = [
|
||||
{
|
||||
desc: "no warnings",
|
||||
uri: "https://example.com" + CORS_SJS_PATH,
|
||||
warnCipher: false,
|
||||
warnSSLv3: false,
|
||||
},
|
||||
{
|
||||
desc: "sslv3 warning",
|
||||
uri: "https://ssl3.example.com" + CORS_SJS_PATH,
|
||||
warnCipher: false,
|
||||
warnSSLv3: true,
|
||||
},
|
||||
{
|
||||
desc: "cipher warning",
|
||||
uri: "https://rc4.example.com" + CORS_SJS_PATH,
|
||||
warnCipher: true,
|
||||
warnSSLv3: false,
|
||||
},
|
||||
{
|
||||
desc: "cipher and sslv3 warning",
|
||||
uri: "https://ssl3rc4.example.com" + CORS_SJS_PATH,
|
||||
warnCipher: true,
|
||||
warnSSLv3: true,
|
||||
},
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
let [tab, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
let { $, EVENTS, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu, NetworkDetails } = NetMonitorView;
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
info("Enabling SSLv3 for the test.");
|
||||
yield new promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.tls.version.min", 0]]}, resolve);
|
||||
});
|
||||
|
||||
let cipher = $("#security-warning-cipher");
|
||||
let sslv3 = $("#security-warning-sslv3");
|
||||
|
||||
for (let test of TEST_CASES) {
|
||||
info("Testing site with " + test.desc);
|
||||
|
||||
info("Performing request to " + test.uri);
|
||||
debuggee.performRequests(1, test.uri);
|
||||
yield waitForNetworkEvents(monitor, 1);
|
||||
|
||||
info("Selecting the request.");
|
||||
RequestsMenu.selectedIndex = 0;
|
||||
|
||||
info("Waiting for details pane to be updated.");
|
||||
yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
|
||||
|
||||
if (NetworkDetails.widget.selectedIndex !== 5) {
|
||||
info("Selecting security tab.");
|
||||
NetworkDetails.widget.selectedIndex = 5;
|
||||
|
||||
info("Waiting for details pane to be updated.");
|
||||
yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
|
||||
}
|
||||
|
||||
is(cipher.hidden, !test.warnCipher, "Cipher suite warning is hidden.");
|
||||
is(sslv3.hidden, !test.warnSSLv3, "SSLv3 warning is hidden.");
|
||||
|
||||
RequestsMenu.clear();
|
||||
|
||||
}
|
||||
|
||||
yield teardown(monitor);
|
||||
|
||||
});
|
|
@ -604,7 +604,7 @@ ResponsiveUI.prototype = {
|
|||
* @param aPreset associated preset.
|
||||
*/
|
||||
setMenuLabel: function RUI_setMenuLabel(aMenuitem, aPreset) {
|
||||
let size = Math.round(aPreset.width) + "x" + Math.round(aPreset.height);
|
||||
let size = Math.round(aPreset.width) + "\u00D7" + Math.round(aPreset.height);
|
||||
|
||||
// .inputField might be not reachable yet (async XBL loading)
|
||||
if (this.menulist.inputField) {
|
||||
|
|
|
@ -210,7 +210,7 @@ function test() {
|
|||
initialWidth = content.innerWidth;
|
||||
initialHeight = content.innerHeight;
|
||||
index = instance.menulist.selectedIndex;
|
||||
let expectedValue = initialWidth + "x" + initialHeight;
|
||||
let expectedValue = initialWidth + "\u00D7" + initialHeight;
|
||||
let expectedLabel = instance.menulist.firstChild.firstChild.getAttribute("label");
|
||||
|
||||
userInput = "I'm wrong";
|
||||
|
|
|
@ -115,7 +115,7 @@ function test() {
|
|||
|
||||
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
|
||||
|
||||
let customPresetIndex = getPresetIndex("456x123 (Testing preset)");
|
||||
let customPresetIndex = getPresetIndex("456" + "\u00D7" + "123 (Testing preset)");
|
||||
info(customPresetIndex);
|
||||
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
|
||||
|
||||
|
|
|
@ -726,7 +726,7 @@ Tooltip.prototype = {
|
|||
this.content = vbox;
|
||||
},
|
||||
|
||||
_getImageDimensionLabel: (w, h) => w + " x " + h,
|
||||
_getImageDimensionLabel: (w, h) => w + " \u00D7 " + h,
|
||||
|
||||
/**
|
||||
* Fill the tooltip with a new instance of the spectrum color picker widget
|
||||
|
|
|
@ -202,6 +202,14 @@
|
|||
- in a "receive" state. -->
|
||||
<!ENTITY netmonitorUI.timings.receive "Receiving:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.security.warning.protocol): A tooltip
|
||||
- for warning icon that indicates a connection uses insecure protocol. -->
|
||||
<!ENTITY netmonitorUI.security.warning.sslv3 "The protocol SSL 3.0 is deprecated and insecure.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.security.warning.cipher): A tooltip
|
||||
- for warning icon that indicates a connection uses insecure cipher suite. -->
|
||||
<!ENTITY netmonitorUI.security.warning.cipher "The cipher used for encryption is deprecated and insecure.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.security.error): This is the label displayed
|
||||
- in the security tab if a security error prevented the connection. -->
|
||||
<!ENTITY netmonitorUI.security.error "An error occured:">
|
||||
|
|
|
@ -44,6 +44,10 @@ netmonitor.security.state.insecure=The connection used to fetch this resource wa
|
|||
# issues.
|
||||
netmonitor.security.state.broken=A security error prevented the resource from being loaded.
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.state.weak)
|
||||
# This string is used as an tooltip for request that had minor security issues
|
||||
netmonitor.security.state.weak=This resource was transferred over a connection that used weak encryption.
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.enabled):
|
||||
# This string is used to indicate that a specific security feature is used by
|
||||
# a connection in the security details tab.
|
||||
|
|
|
@ -178,6 +178,11 @@
|
|||
list-style-image: url(chrome://browser/skin/identity-icons-https.png);
|
||||
}
|
||||
|
||||
.security-state-weak {
|
||||
cursor: pointer;
|
||||
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-display.png);
|
||||
}
|
||||
|
||||
.security-state-broken {
|
||||
cursor: pointer;
|
||||
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-active.png);
|
||||
|
@ -578,6 +583,21 @@ label.requests-menu-status-code {
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.security-warning-icon {
|
||||
background-image: url(alerticon-warning.png);
|
||||
background-size: 13px 12px;
|
||||
-moz-margin-start: 5px;
|
||||
vertical-align: top;
|
||||
width: 13px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.security-warning-icon {
|
||||
background-image: url(alerticon-warning@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom request form */
|
||||
|
||||
#custom-pane {
|
||||
|
|
|
@ -25,6 +25,14 @@ treecol {
|
|||
|
||||
/* Category List */
|
||||
|
||||
#categories {
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
#categories > scrollbox {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.png");
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://testing-common/services/common/utils.js");
|
||||
Cu.import("resource://testing-common/PlacesTestUtils.jsm");
|
||||
|
||||
let provider = {
|
||||
getFile: function(prop, persistent) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines/history.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
|
@ -13,13 +12,16 @@ Cu.import("resource://testing-common/services/sync/utils.js");
|
|||
|
||||
Service.engineManager.clear();
|
||||
|
||||
add_test(function test_setup() {
|
||||
PlacesTestUtils.clearHistory().then(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_processIncoming_mobile_history_batched() {
|
||||
_("SyncEngine._processIncoming works on history engine.");
|
||||
|
||||
let FAKE_DOWNLOAD_LIMIT = 100;
|
||||
|
||||
Svc.Prefs.set("client.type", "mobile");
|
||||
PlacesUtils.history.removeAllPages();
|
||||
Service.engineManager.register(HistoryEngine);
|
||||
|
||||
// A collection that logs each GET
|
||||
|
@ -130,10 +132,11 @@ add_test(function test_processIncoming_mobile_history_batched() {
|
|||
}
|
||||
|
||||
} finally {
|
||||
PlacesUtils.history.removeAllPages();
|
||||
server.stop(do_test_finished);
|
||||
Svc.Prefs.resetBranch("");
|
||||
Service.recordManager.clearCache();
|
||||
PlacesTestUtils.clearHistory().then(() => {
|
||||
server.stop(do_test_finished);
|
||||
Svc.Prefs.resetBranch("");
|
||||
Service.recordManager.clearCache();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ function ensureThrows(func) {
|
|||
try {
|
||||
func.apply(this, arguments);
|
||||
} catch (ex) {
|
||||
PlacesUtils.history.removeAllPages();
|
||||
PlacesTestUtils.clearHistory();
|
||||
do_throw(ex);
|
||||
}
|
||||
};
|
||||
|
@ -300,6 +300,5 @@ add_test(function test_remove() {
|
|||
|
||||
add_test(function cleanup() {
|
||||
_("Clean up.");
|
||||
PlacesUtils.history.removeAllPages();
|
||||
run_next_test();
|
||||
PlacesTestUtils.clearHistory().then(run_next_test);
|
||||
});
|
||||
|
|
|
@ -199,6 +199,5 @@ add_test(function test_stop_tracking_twice() {
|
|||
|
||||
add_test(function cleanup() {
|
||||
_("Clean up.");
|
||||
PlacesUtils.history.removeAllPages();
|
||||
run_next_test();
|
||||
PlacesTestUtils.clearHistory().then(run_next_test);
|
||||
});
|
||||
|
|
|
@ -912,14 +912,19 @@ public:
|
|||
mozStorageTransaction transaction(mDBConn, false,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE);
|
||||
|
||||
VisitData* lastPlace = nullptr;
|
||||
VisitData* lastFetchedPlace = nullptr;
|
||||
for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
|
||||
VisitData& place = mPlaces.ElementAt(i);
|
||||
VisitData& referrer = mReferrers.ElementAt(i);
|
||||
|
||||
// Fetching from the database can overwrite this information, so save it
|
||||
// apart.
|
||||
bool typed = place.typed;
|
||||
bool hidden = place.hidden;
|
||||
|
||||
// We can avoid a database lookup if it's the same place as the last
|
||||
// visit we added.
|
||||
bool known = lastPlace && lastPlace->IsSamePlaceAs(place);
|
||||
bool known = lastFetchedPlace && lastFetchedPlace->IsSamePlaceAs(place);
|
||||
if (!known) {
|
||||
nsresult rv = mHistory->FetchPageInfo(place, &known);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -930,6 +935,17 @@ public:
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
lastFetchedPlace = &mPlaces.ElementAt(i);
|
||||
}
|
||||
|
||||
// If any transition is typed, ensure the page is marked as typed.
|
||||
if (typed != lastFetchedPlace->typed) {
|
||||
place.typed = true;
|
||||
}
|
||||
|
||||
// If any transition is visible, ensure the page is marked as visible.
|
||||
if (hidden != lastFetchedPlace->hidden) {
|
||||
place.hidden = false;
|
||||
}
|
||||
|
||||
FetchReferrerInfo(referrer, place);
|
||||
|
@ -953,8 +969,6 @@ public:
|
|||
rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
lastPlace = &mPlaces.ElementAt(i);
|
||||
}
|
||||
|
||||
nsresult rv = transaction.Commit();
|
||||
|
@ -2291,24 +2305,15 @@ History::FetchPageInfo(VisitData& _place, bool* _exists)
|
|||
(_place.title.IsEmpty() && title.IsVoid()));
|
||||
}
|
||||
|
||||
if (_place.hidden) {
|
||||
// If this transition was hidden, it is possible that others were not.
|
||||
// Any one visible transition makes this location visible. If database
|
||||
// has location as visible, reflect that in our data structure.
|
||||
int32_t hidden;
|
||||
rv = stmt->GetInt32(3, &hidden);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.hidden = !!hidden;
|
||||
}
|
||||
int32_t hidden;
|
||||
rv = stmt->GetInt32(3, &hidden);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.hidden = !!hidden;
|
||||
|
||||
if (!_place.typed) {
|
||||
// If this transition wasn't typed, others might have been. If database
|
||||
// has location as typed, reflect that in our data structure.
|
||||
int32_t typed;
|
||||
rv = stmt->GetInt32(4, &typed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.typed = !!typed;
|
||||
}
|
||||
int32_t typed;
|
||||
rv = stmt->GetInt32(4, &typed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.typed = !!typed;
|
||||
|
||||
rv = stmt->GetInt32(5, &_place.frecency);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -24,30 +24,28 @@ const RECENT_EVENT_THRESHOLD = 15 * 60 * 1000000;
|
|||
* The time of the visit. Defaults to now if not provided.
|
||||
*/
|
||||
function VisitInfo(aTransitionType,
|
||||
aVisitTime)
|
||||
{
|
||||
aVisitTime) {
|
||||
this.transitionType =
|
||||
aTransitionType === undefined ? TRANSITION_LINK : aTransitionType;
|
||||
this.visitDate = aVisitTime || Date.now() * 1000;
|
||||
}
|
||||
|
||||
function promiseUpdatePlaces(aPlaces) {
|
||||
let deferred = Promise.defer();
|
||||
PlacesUtils.asyncHistory.updatePlaces(aPlaces, {
|
||||
_errors: [],
|
||||
_results: [],
|
||||
handleError: function handleError(aResultCode, aPlace) {
|
||||
this._errors.push({ resultCode: aResultCode, info: aPlace});
|
||||
},
|
||||
handleResult: function handleResult(aPlace) {
|
||||
this._results.push(aPlace);
|
||||
},
|
||||
handleCompletion: function handleCompletion() {
|
||||
deferred.resolve({ errors: this._errors, results: this._results });
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
PlacesUtils.asyncHistory.updatePlaces(aPlaces, {
|
||||
_errors: [],
|
||||
_results: [],
|
||||
handleError(aResultCode, aPlace) {
|
||||
this._errors.push({ resultCode: aResultCode, info: aPlace});
|
||||
},
|
||||
handleResult(aPlace) {
|
||||
this._results.push(aPlace);
|
||||
},
|
||||
handleCompletion() {
|
||||
resolve({ errors: this._errors, results: this._results });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,18 +61,14 @@ function promiseUpdatePlaces(aPlaces) {
|
|||
*/
|
||||
function TitleChangedObserver(aURI,
|
||||
aExpectedTitle,
|
||||
aCallback)
|
||||
{
|
||||
aCallback) {
|
||||
this.uri = aURI;
|
||||
this.expectedTitle = aExpectedTitle;
|
||||
this.callback = aCallback;
|
||||
}
|
||||
TitleChangedObserver.prototype = {
|
||||
__proto__: NavHistoryObserver.prototype,
|
||||
onTitleChanged: function(aURI,
|
||||
aTitle,
|
||||
aGUID)
|
||||
{
|
||||
onTitleChanged(aURI, aTitle, aGUID) {
|
||||
do_log_info("onTitleChanged(" + aURI.spec + ", " + aTitle + ", " + aGUID + ")");
|
||||
if (!this.uri.equals(aURI)) {
|
||||
return;
|
||||
|
@ -148,14 +142,12 @@ function do_check_title_for_uri(aURI,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Test Functions
|
||||
|
||||
function test_interface_exists()
|
||||
{
|
||||
add_task(function* test_interface_exists() {
|
||||
let history = Cc["@mozilla.org/browser/history;1"].getService(Ci.nsISupports);
|
||||
do_check_true(history instanceof Ci.mozIAsyncHistory);
|
||||
}
|
||||
});
|
||||
|
||||
function test_invalid_uri_throws()
|
||||
{
|
||||
add_task(function* test_invalid_uri_throws() {
|
||||
// First, test passing in nothing.
|
||||
let place = {
|
||||
visits: [
|
||||
|
@ -188,10 +180,9 @@ function test_invalid_uri_throws()
|
|||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_invalid_places_throws()
|
||||
{
|
||||
add_task(function* test_invalid_places_throws() {
|
||||
// First, test passing in nothing.
|
||||
try {
|
||||
PlacesUtils.asyncHistory.updatePlaces();
|
||||
|
@ -219,10 +210,9 @@ function test_invalid_places_throws()
|
|||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_invalid_guid_throws()
|
||||
{
|
||||
add_task(function* test_invalid_guid_throws() {
|
||||
// First check invalid length guid.
|
||||
let place = {
|
||||
guid: "BAD_GUID",
|
||||
|
@ -249,10 +239,9 @@ function test_invalid_guid_throws()
|
|||
catch (e) {
|
||||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_no_visits_throws()
|
||||
{
|
||||
add_task(function* test_no_visits_throws() {
|
||||
const TEST_URI =
|
||||
NetUtil.newURI(TEST_DOMAIN + "test_no_id_or_guid_no_visits_throws");
|
||||
const TEST_GUID = "_RANDOMGUID_";
|
||||
|
@ -290,10 +279,9 @@ function test_no_visits_throws()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_add_visit_no_date_throws()
|
||||
{
|
||||
add_task(function* test_add_visit_no_date_throws() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_add_visit_no_date_throws"),
|
||||
visits: [
|
||||
|
@ -308,10 +296,9 @@ function test_add_visit_no_date_throws()
|
|||
catch (e) {
|
||||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_add_visit_no_transitionType_throws()
|
||||
{
|
||||
add_task(function* test_add_visit_no_transitionType_throws() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_add_visit_no_transitionType_throws"),
|
||||
visits: [
|
||||
|
@ -326,10 +313,9 @@ function test_add_visit_no_transitionType_throws()
|
|||
catch (e) {
|
||||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_add_visit_invalid_transitionType_throws()
|
||||
{
|
||||
add_task(function* test_add_visit_invalid_transitionType_throws() {
|
||||
// First, test something that has a transition type lower than the first one.
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN +
|
||||
|
@ -355,10 +341,9 @@ function test_add_visit_invalid_transitionType_throws()
|
|||
catch (e) {
|
||||
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_non_addable_uri_errors()
|
||||
{
|
||||
add_task(function* test_non_addable_uri_errors() {
|
||||
// Array of protocols that nsINavHistoryService::canAddURI returns false for.
|
||||
const URLS = [
|
||||
"about:config",
|
||||
|
@ -404,10 +389,9 @@ function test_non_addable_uri_errors()
|
|||
do_check_false(yield promiseIsURIVisited(place.info.uri));
|
||||
}
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_duplicate_guid_errors()
|
||||
{
|
||||
add_task(function* test_duplicate_guid_errors() {
|
||||
// This test ensures that trying to add a visit, with a guid already found in
|
||||
// another visit, fails.
|
||||
let place = {
|
||||
|
@ -443,10 +427,9 @@ function test_duplicate_guid_errors()
|
|||
do_check_false(yield promiseIsURIVisited(badPlaceInfo.info.uri));
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_invalid_referrerURI_ignored()
|
||||
{
|
||||
add_task(function* test_invalid_referrerURI_ignored() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN +
|
||||
"test_invalid_referrerURI_ignored"),
|
||||
|
@ -480,10 +463,9 @@ function test_invalid_referrerURI_ignored()
|
|||
stmt.finalize();
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_nonnsIURI_referrerURI_ignored()
|
||||
{
|
||||
add_task(function* test_nonnsIURI_referrerURI_ignored() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN +
|
||||
"test_nonnsIURI_referrerURI_ignored"),
|
||||
|
@ -513,10 +495,9 @@ function test_nonnsIURI_referrerURI_ignored()
|
|||
stmt.finalize();
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_old_referrer_ignored()
|
||||
{
|
||||
add_task(function* test_old_referrer_ignored() {
|
||||
// This tests that a referrer for a visit which is not recent (specifically,
|
||||
// older than 15 minutes as per RECENT_EVENT_THRESHOLD) is not saved by
|
||||
// updatePlaces.
|
||||
|
@ -573,10 +554,9 @@ function test_old_referrer_ignored()
|
|||
stmt.finalize();
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_place_id_ignored()
|
||||
{
|
||||
add_task(function* test_place_id_ignored() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_place_id_ignored_first"),
|
||||
visits: [
|
||||
|
@ -614,10 +594,9 @@ function test_place_id_ignored()
|
|||
do_check_true(yield promiseIsURIVisited(badPlace.uri));
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_handleCompletion_called_when_complete()
|
||||
{
|
||||
add_task(function* test_handleCompletion_called_when_complete() {
|
||||
// We test a normal visit, and embeded visit, and a uri that would fail
|
||||
// the canAddURI test to make sure that the notification happens after *all*
|
||||
// of them have had a callback.
|
||||
|
@ -656,10 +635,9 @@ function test_handleCompletion_called_when_complete()
|
|||
do_check_eq(callbackCountSuccess, EXPECTED_COUNT_SUCCESS);
|
||||
do_check_eq(callbackCountFailure, EXPECTED_COUNT_FAILURE);
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_add_visit()
|
||||
{
|
||||
add_task(function* test_add_visit() {
|
||||
const VISIT_TIME = Date.now() * 1000;
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_add_visit"),
|
||||
|
@ -720,10 +698,9 @@ function test_add_visit()
|
|||
yield promiseAsyncUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_properties_saved()
|
||||
{
|
||||
add_task(function* test_properties_saved() {
|
||||
// Check each transition type to make sure it is saved properly.
|
||||
let places = [];
|
||||
for (let transitionType = TRANSITION_LINK;
|
||||
|
@ -804,10 +781,9 @@ function test_properties_saved()
|
|||
yield promiseAsyncUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_guid_saved()
|
||||
{
|
||||
add_task(function* test_guid_saved() {
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_guid_saved"),
|
||||
guid: "__TESTGUID__",
|
||||
|
@ -828,10 +804,9 @@ function test_guid_saved()
|
|||
do_check_eq(placeInfo.guid, place.guid);
|
||||
do_check_guid_for_uri(uri, place.guid);
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_referrer_saved()
|
||||
{
|
||||
add_task(function* test_referrer_saved() {
|
||||
let places = [
|
||||
{ uri: NetUtil.newURI(TEST_DOMAIN + "test_referrer_saved/referrer"),
|
||||
visits: [
|
||||
|
@ -881,10 +856,9 @@ function test_referrer_saved()
|
|||
yield promiseAsyncUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function test_guid_change_saved()
|
||||
{
|
||||
add_task(function* test_guid_change_saved() {
|
||||
// First, add a visit for it.
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_guid_change_saved"),
|
||||
|
@ -908,10 +882,9 @@ function test_guid_change_saved()
|
|||
do_check_guid_for_uri(place.uri, place.guid);
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_title_change_saved()
|
||||
{
|
||||
add_task(function* test_title_change_saved() {
|
||||
// First, add a visit for it.
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_title_change_saved"),
|
||||
|
@ -955,10 +928,9 @@ function test_title_change_saved()
|
|||
do_check_title_for_uri(place.uri, place.title);
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_no_title_does_not_clear_title()
|
||||
{
|
||||
add_task(function* test_no_title_does_not_clear_title() {
|
||||
const TITLE = "test title";
|
||||
// First, add a visit for it.
|
||||
let place = {
|
||||
|
@ -984,10 +956,9 @@ function test_no_title_does_not_clear_title()
|
|||
do_check_title_for_uri(place.uri, TITLE);
|
||||
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_title_change_notifies()
|
||||
{
|
||||
add_task(function* test_title_change_notifies() {
|
||||
// There are three cases to test. The first case is to make sure we do not
|
||||
// get notified if we do not specify a title.
|
||||
let place = {
|
||||
|
@ -1015,36 +986,35 @@ function test_title_change_notifies()
|
|||
place.uri = NetUtil.newURI(place.uri.spec + "/new-visit-with-title");
|
||||
place.title = "title 1";
|
||||
function promiseTitleChangedObserver(aPlace) {
|
||||
let deferred = Promise.defer();
|
||||
let callbackCount = 0;
|
||||
let observer = new TitleChangedObserver(aPlace.uri, aPlace.title, function() {
|
||||
switch (++callbackCount) {
|
||||
case 1:
|
||||
// The third case to test is to make sure we get a notification when
|
||||
// we change an existing place.
|
||||
observer.expectedTitle = place.title = "title 2";
|
||||
place.visits = [new VisitInfo()];
|
||||
PlacesUtils.asyncHistory.updatePlaces(place);
|
||||
break;
|
||||
case 2:
|
||||
PlacesUtils.history.removeObserver(silentObserver);
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
deferred.resolve();
|
||||
break;
|
||||
};
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
let callbackCount = 0;
|
||||
let observer = new TitleChangedObserver(aPlace.uri, aPlace.title, function() {
|
||||
switch (++callbackCount) {
|
||||
case 1:
|
||||
// The third case to test is to make sure we get a notification when
|
||||
// we change an existing place.
|
||||
observer.expectedTitle = place.title = "title 2";
|
||||
place.visits = [new VisitInfo()];
|
||||
PlacesUtils.asyncHistory.updatePlaces(place);
|
||||
break;
|
||||
case 2:
|
||||
PlacesUtils.history.removeObserver(silentObserver);
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
resolve();
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
PlacesUtils.asyncHistory.updatePlaces(aPlace);
|
||||
return deferred.promise;
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
PlacesUtils.asyncHistory.updatePlaces(aPlace);
|
||||
});
|
||||
}
|
||||
|
||||
yield promiseTitleChangedObserver(place);
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
function test_visit_notifies()
|
||||
{
|
||||
add_task(function* test_visit_notifies() {
|
||||
// There are two observers we need to see for each visit. One is an
|
||||
// nsINavHistoryObserver and the other is the uri-visit-saved observer topic.
|
||||
let place = {
|
||||
|
@ -1057,44 +1027,43 @@ function test_visit_notifies()
|
|||
do_check_false(yield promiseIsURIVisited(place.uri));
|
||||
|
||||
function promiseVisitObserver(aPlace) {
|
||||
let deferred = Promise.defer();
|
||||
let callbackCount = 0;
|
||||
let finisher = function() {
|
||||
if (++callbackCount == 2) {
|
||||
deferred.resolve();
|
||||
return new Promise((resolve, reject) => {
|
||||
let callbackCount = 0;
|
||||
let finisher = function() {
|
||||
if (++callbackCount == 2) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
let visitObserver = new VisitObserver(place.uri, place.guid,
|
||||
function(aVisitDate,
|
||||
aTransitionType) {
|
||||
let visit = place.visits[0];
|
||||
do_check_eq(visit.visitDate, aVisitDate);
|
||||
do_check_eq(visit.transitionType, aTransitionType);
|
||||
let visitObserver = new VisitObserver(place.uri, place.guid,
|
||||
function(aVisitDate,
|
||||
aTransitionType) {
|
||||
let visit = place.visits[0];
|
||||
do_check_eq(visit.visitDate, aVisitDate);
|
||||
do_check_eq(visit.transitionType, aTransitionType);
|
||||
|
||||
PlacesUtils.history.removeObserver(visitObserver);
|
||||
finisher();
|
||||
PlacesUtils.history.removeObserver(visitObserver);
|
||||
finisher();
|
||||
});
|
||||
PlacesUtils.history.addObserver(visitObserver, false);
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
do_log_info("observe(" + aSubject + ", " + aTopic + ", " + aData + ")");
|
||||
do_check_true(aSubject instanceof Ci.nsIURI);
|
||||
do_check_true(aSubject.equals(place.uri));
|
||||
|
||||
Services.obs.removeObserver(observer, URI_VISIT_SAVED);
|
||||
finisher();
|
||||
};
|
||||
Services.obs.addObserver(observer, URI_VISIT_SAVED, false);
|
||||
PlacesUtils.asyncHistory.updatePlaces(place);
|
||||
});
|
||||
PlacesUtils.history.addObserver(visitObserver, false);
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
do_log_info("observe(" + aSubject + ", " + aTopic + ", " + aData + ")");
|
||||
do_check_true(aSubject instanceof Ci.nsIURI);
|
||||
do_check_true(aSubject.equals(place.uri));
|
||||
|
||||
Services.obs.removeObserver(observer, URI_VISIT_SAVED);
|
||||
finisher();
|
||||
};
|
||||
Services.obs.addObserver(observer, URI_VISIT_SAVED, false);
|
||||
PlacesUtils.asyncHistory.updatePlaces(place);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
yield promiseVisitObserver(place);
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
// test with empty mozIVisitInfoCallback object
|
||||
function test_callbacks_not_supplied()
|
||||
{
|
||||
add_task(function* test_callbacks_not_supplied() {
|
||||
const URLS = [
|
||||
"imap://cyrus.andrew.cmu.edu/archive.imap", // bad URI
|
||||
"http://mozilla.org/" // valid URI
|
||||
|
@ -1121,40 +1090,36 @@ function test_callbacks_not_supplied()
|
|||
|
||||
PlacesUtils.asyncHistory.updatePlaces(places, {});
|
||||
yield promiseAsyncUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Test Runner
|
||||
// Test that we don't wrongly overwrite typed and hidden when adding new visits.
|
||||
add_task(function* test_typed_hidden_not_overwritten() {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
let places = [
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/"),
|
||||
title: "test",
|
||||
visits: [
|
||||
new VisitInfo(TRANSITION_TYPED),
|
||||
new VisitInfo(TRANSITION_LINK)
|
||||
]
|
||||
},
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/"),
|
||||
title: "test",
|
||||
visits: [
|
||||
new VisitInfo(TRANSITION_FRAMED_LINK)
|
||||
]
|
||||
},
|
||||
];
|
||||
yield promiseUpdatePlaces(places);
|
||||
|
||||
[
|
||||
test_interface_exists,
|
||||
test_invalid_uri_throws,
|
||||
test_invalid_places_throws,
|
||||
test_invalid_guid_throws,
|
||||
test_no_visits_throws,
|
||||
test_add_visit_no_date_throws,
|
||||
test_add_visit_no_transitionType_throws,
|
||||
test_add_visit_invalid_transitionType_throws,
|
||||
// Note: all asynchronous tests (every test below this point) should wait for
|
||||
// async updates before calling run_next_test.
|
||||
test_non_addable_uri_errors,
|
||||
test_duplicate_guid_errors,
|
||||
test_invalid_referrerURI_ignored,
|
||||
test_nonnsIURI_referrerURI_ignored,
|
||||
test_old_referrer_ignored,
|
||||
test_place_id_ignored,
|
||||
test_handleCompletion_called_when_complete,
|
||||
test_add_visit,
|
||||
test_properties_saved,
|
||||
test_guid_saved,
|
||||
test_referrer_saved,
|
||||
test_guid_change_saved,
|
||||
test_title_change_saved,
|
||||
test_no_title_does_not_clear_title,
|
||||
test_title_change_notifies,
|
||||
test_visit_notifies,
|
||||
test_callbacks_not_supplied,
|
||||
].forEach(add_task);
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute("SELECT hidden, typed FROM moz_places WHERE url = :url",
|
||||
{ url: "http://mozilla.org/" });
|
||||
Assert.equal(rows[0].getResultByName("typed"), 1,
|
||||
"The page should be marked as typed");
|
||||
Assert.equal(rows[0].getResultByName("hidden"), 0,
|
||||
"The page should be marked as not hidden");
|
||||
});
|
||||
|
||||
function run_test()
|
||||
{
|
||||
|
|
|
@ -605,4 +605,11 @@
|
|||
<children includes="menupopup"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="menulist-popuponly" display="xul:menu"
|
||||
extends="chrome://global/content/bindings/menulist.xml#menulist">
|
||||
<content>
|
||||
<children includes="menupopup"/>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
|
|
@ -248,7 +248,7 @@
|
|||
this.messageManager.addMessageListener("DOMFullscreen:RequestRollback", this);
|
||||
this.messageManager.loadFrameScript("chrome://global/content/browser-child.js", true);
|
||||
|
||||
if (this.hasAttribute("selectpopup")) {
|
||||
if (this.hasAttribute("selectmenulist")) {
|
||||
this.messageManager.addMessageListener("Forms:ShowDropDown", this);
|
||||
this.messageManager.addMessageListener("Forms:HideDropDown", this);
|
||||
this.messageManager.loadFrameScript("chrome://global/content/select-child.js", true);
|
||||
|
@ -310,9 +310,9 @@
|
|||
|
||||
case "Forms:ShowDropDown": {
|
||||
Cu.import("resource://gre/modules/SelectParentHelper.jsm");
|
||||
let dropdown = document.getElementById(this.getAttribute("selectpopup"));
|
||||
SelectParentHelper.populate(dropdown, data.options, data.selectedIndex);
|
||||
SelectParentHelper.open(this, dropdown, data.rect);
|
||||
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
|
||||
SelectParentHelper.populate(menulist, data.options, data.selectedIndex);
|
||||
SelectParentHelper.open(this, menulist, data.rect);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -345,8 +345,8 @@
|
|||
|
||||
case "Forms:HideDropDown": {
|
||||
Cu.import("resource://gre/modules/SelectParentHelper.jsm");
|
||||
let dropdown = document.getElementById(this.getAttribute("selectpopup"));
|
||||
SelectParentHelper.hide(dropdown);
|
||||
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
|
||||
SelectParentHelper.hide(menulist);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -930,6 +930,14 @@ menulist {
|
|||
-moz-binding: url("chrome://global/content/bindings/menulist.xml#menulist");
|
||||
}
|
||||
|
||||
menulist[popuponly="true"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/menulist.xml#menulist-popuponly");
|
||||
-moz-appearance: none !important;
|
||||
margin: 0 !important;
|
||||
height: 0 !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
menulist[editable="true"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/menulist.xml#menulist-editable");
|
||||
}
|
||||
|
|
|
@ -1263,7 +1263,7 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
|||
}
|
||||
|
||||
let rect = this.currentQuads.border.bounds;
|
||||
let dim = Math.ceil(rect.width) + " x " + Math.ceil(rect.height);
|
||||
let dim = Math.ceil(rect.width) + " \u00D7 " + Math.ceil(rect.height);
|
||||
|
||||
let elementId = this.ID_CLASS_PREFIX + "nodeinfobar-";
|
||||
this.markup.setTextContentForElement(elementId + "tagname", tagName);
|
||||
|
|
|
@ -136,7 +136,7 @@ let MemoryActor = protocol.ActorClass({
|
|||
if (this.state == "attached") {
|
||||
if (isTopLevel && this.dbg.memory.trackingAllocationSites) {
|
||||
this._clearDebuggees();
|
||||
nthis._frameCache.initFrames();
|
||||
this._frameCache.initFrames();
|
||||
}
|
||||
this.dbg.addDebuggees();
|
||||
}
|
||||
|
|
|
@ -500,6 +500,7 @@ let NetworkHelper = {
|
|||
* - state: The security of the connection used to fetch this
|
||||
* request. Has one of following string values:
|
||||
* * "insecure": the connection was not secure (only http)
|
||||
* * "weak": the connection has minor security issues
|
||||
* * "broken": secure connection failed (e.g. expired cert)
|
||||
* * "secure": the connection was properly secured.
|
||||
* If state == broken:
|
||||
|
@ -511,6 +512,9 @@ let NetworkHelper = {
|
|||
* See parseCertificateInfo for the contents.
|
||||
* - hsts: true if host uses Strict Transport Security, false otherwise
|
||||
* - hpkp: true if host uses Public Key Pinning, false otherwise
|
||||
* If state == weak: Same as state == secure and
|
||||
* - weaknessReasons: list of reasons that cause the request to be
|
||||
* considered weak. See getReasonsForWeakness.
|
||||
*/
|
||||
parseSecurityInfo: function NH_parseSecurityInfo(securityInfo, httpActivity) {
|
||||
const info = {
|
||||
|
@ -551,7 +555,7 @@ let NetworkHelper = {
|
|||
* => .securityState has STATE_IS_BROKEN flag
|
||||
* => .errorCode is NOT an NSS error code
|
||||
* => .errorMessage is not available
|
||||
* => state === "insecure"
|
||||
* => state === "weak"
|
||||
*/
|
||||
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
|
@ -561,10 +565,26 @@ let NetworkHelper = {
|
|||
const NSSErrorsService = Cc['@mozilla.org/nss_errors_service;1']
|
||||
.getService(Ci.nsINSSErrorsService);
|
||||
const SSLStatus = securityInfo.SSLStatus;
|
||||
if (!NSSErrorsService.isNSSErrorCode(securityInfo.errorCode)) {
|
||||
const state = securityInfo.securityState;
|
||||
|
||||
if (securityInfo.securityState & wpl.STATE_IS_SECURE) {
|
||||
// The connection is secure.
|
||||
info.state = "secure";
|
||||
if (state & wpl.STATE_IS_SECURE) {
|
||||
// The connection is secure.
|
||||
info.state = "secure";
|
||||
} else if (state & wpl.STATE_IS_BROKEN) {
|
||||
// The connection is not secure, there was no error but there's some
|
||||
// minor security issues.
|
||||
info.state = "weak";
|
||||
info.weaknessReasons = this.getReasonsForWeakness(state);
|
||||
} else if (state & wpl.STATE_IS_INSECURE) {
|
||||
// This was most likely an https request that was aborted before
|
||||
// validation. Return info as info.state = insecure.
|
||||
return info;
|
||||
} else {
|
||||
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
|
||||
"Security state " + state + " has no known STATE_IS_* flags.");
|
||||
return info;
|
||||
}
|
||||
|
||||
// Cipher suite.
|
||||
info.cipherSuite = SSLStatus.cipherName;
|
||||
|
@ -598,14 +618,10 @@ let NetworkHelper = {
|
|||
info.hpkp = false;
|
||||
}
|
||||
|
||||
} else if (NSSErrorsService.isNSSErrorCode(securityInfo.errorCode)) {
|
||||
} else {
|
||||
// The connection failed.
|
||||
info.state = "broken";
|
||||
info.errorMessage = securityInfo.errorMessage;
|
||||
} else {
|
||||
// Connection has securityInfo, it is not secure and there's no problems
|
||||
// to report. Mark the request as insecure.
|
||||
return info;
|
||||
}
|
||||
|
||||
return info;
|
||||
|
@ -683,6 +699,46 @@ let NetworkHelper = {
|
|||
return "Unknown";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes the securityState bitfield and returns reasons for weak connection
|
||||
* as an array of strings.
|
||||
*
|
||||
* @param Number state
|
||||
* nsITransportSecurityInfo.securityState.
|
||||
*
|
||||
* @return Array[String]
|
||||
* List of weakness reasons. A subset of { cipher, sslv3 } where
|
||||
* * cipher: The cipher suite is consireded to be weak (RC4).
|
||||
* * sslv3: The protocol, SSLv3, is weak.
|
||||
*/
|
||||
getReasonsForWeakness: function NH_getReasonsForWeakness(state) {
|
||||
const wpl = Ci.nsIWebProgressListener;
|
||||
|
||||
// If there's non-fatal security issues the request has STATE_IS_BROKEN
|
||||
// flag set. See http://hg.mozilla.org/mozilla-central/file/44344099d119
|
||||
// /security/manager/ssl/src/nsNSSCallbacks.cpp#l1233
|
||||
let reasons = [];
|
||||
|
||||
if (state & wpl.STATE_IS_BROKEN) {
|
||||
let isSSLV3 = state & wpl.STATE_USES_SSL_3;
|
||||
let isCipher = state & wpl.STATE_USES_WEAK_CRYPTO;
|
||||
if (isSSLV3) {
|
||||
reasons.push("sslv3");
|
||||
}
|
||||
|
||||
if (isCipher) {
|
||||
reasons.push("cipher");
|
||||
}
|
||||
|
||||
if (!isCipher && !isSSLV3) {
|
||||
DevToolsUtils.reportException("NetworkHelper.getReasonsForWeakness",
|
||||
"STATE_IS_BROKEN without a known reason. Full state was: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
return reasons;
|
||||
},
|
||||
};
|
||||
|
||||
for (let prop of Object.getOwnPropertyNames(NetworkHelper)) {
|
||||
|
|
|
@ -89,12 +89,12 @@ function test_secureSecurityInfo() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test that STATE_IS_BROKEN returns "insecure"
|
||||
* Test that STATE_IS_BROKEN returns "weak"
|
||||
*/
|
||||
function test_brokenSecurityInfo() {
|
||||
MockSecurityInfo.securityState = wpl.STATE_IS_BROKEN;
|
||||
|
||||
let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {});
|
||||
equal(result.state, "insecure",
|
||||
"state == 'insecure' if securityState contains STATE_IS_BROKEN flag");
|
||||
equal(result.state, "weak",
|
||||
"state == 'weak' if securityState contains STATE_IS_BROKEN flag");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/* 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";
|
||||
|
||||
// Tests that NetworkHelper.getReasonsForWeakness returns correct reasons for
|
||||
// weak requests.
|
||||
|
||||
const { devtools } = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
|
||||
Object.defineProperty(this, "NetworkHelper", {
|
||||
get: function() {
|
||||
return devtools.require("devtools/toolkit/webconsole/network-helper");
|
||||
},
|
||||
configurable: true,
|
||||
writeable: false,
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const wpl = Ci.nsIWebProgressListener;
|
||||
const TEST_CASES = [
|
||||
{
|
||||
description: "weak cipher",
|
||||
input: wpl.STATE_IS_BROKEN | wpl.STATE_USES_WEAK_CRYPTO,
|
||||
expected: ["cipher"]
|
||||
}, {
|
||||
description: "weak sslv3 protocol",
|
||||
input: wpl.STATE_IS_BROKEN | wpl.STATE_USES_SSL_3,
|
||||
expected: ["sslv3"]
|
||||
}, {
|
||||
description: "weak cipher + sslv3",
|
||||
input: wpl.STATE_IS_BROKEN | wpl.STATE_USES_WEAK_CRYPTO | wpl.STATE_USES_SSL_3,
|
||||
expected: ["sslv3", "cipher"] // order matters for deepEqual
|
||||
}, {
|
||||
description: "only STATE_IS_BROKEN flag",
|
||||
input: wpl.STATE_IS_BROKEN,
|
||||
expected: []
|
||||
}, {
|
||||
description: "only STATE_IS_SECURE flag",
|
||||
input: wpl.STATE_IS_SECURE,
|
||||
expected: []
|
||||
},
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
do_print("Testing NetworkHelper.getReasonsForWeakness.");
|
||||
|
||||
for (let {description, input, expected} of TEST_CASES) {
|
||||
do_print("Testing " + description);
|
||||
|
||||
deepEqual(NetworkHelper.getReasonsForWeakness(input), expected,
|
||||
"Got the expected reasons for weakness.");
|
||||
}
|
||||
}
|
|
@ -11,3 +11,4 @@ support-files =
|
|||
[test_security-info-protocol-version.js]
|
||||
[test_security-info-state.js]
|
||||
[test_security-info-static-hpkp.js]
|
||||
[test_security-info-weakness-reasons.js]
|
||||
|
|
|
@ -11,27 +11,35 @@ this.EXPORTED_SYMBOLS = [
|
|||
let currentBrowser = null;
|
||||
|
||||
this.SelectParentHelper = {
|
||||
populate: function(popup, items, selectedIndex) {
|
||||
populate: function(menulist, items, selectedIndex) {
|
||||
// Clear the current contents of the popup
|
||||
popup.textContent = "";
|
||||
populateChildren(popup, items, selectedIndex);
|
||||
menulist.menupopup.textContent = "";
|
||||
populateChildren(menulist.menupopup, items, selectedIndex);
|
||||
// We expect the parent element of the popup to be a <xul:menulist> that
|
||||
// has the popuponly attribute set to "true". This is necessary in order
|
||||
// for a <xul:menupopup> to act like a proper <html:select> dropdown, as
|
||||
// the <xul:menulist> does things like remember state and set the
|
||||
// _moz-menuactive attribute on the selected <xul:menuitem>.
|
||||
menulist.selectedIndex = selectedIndex;
|
||||
},
|
||||
|
||||
open: function(browser, popup, rect) {
|
||||
open: function(browser, menulist, rect) {
|
||||
menulist.hidden = false;
|
||||
currentBrowser = browser;
|
||||
this._registerListeners(popup);
|
||||
popup.hidden = false;
|
||||
this._registerListeners(menulist.menupopup);
|
||||
|
||||
let {x, y} = browser.mapScreenCoordinatesFromContent(rect.left, rect.top + rect.height);
|
||||
popup.openPopupAtScreen(x, y);
|
||||
menulist.menupopup.openPopupAtScreen(x, y);
|
||||
menulist.selectedItem.scrollIntoView();
|
||||
},
|
||||
|
||||
hide: function(popup) {
|
||||
popup.hidePopup();
|
||||
hide: function(menulist) {
|
||||
menulist.menupopup.hidePopup();
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
let popup = event.currentTarget;
|
||||
let menulist = popup.parentNode;
|
||||
|
||||
switch (event.type) {
|
||||
case "command":
|
||||
|
@ -47,6 +55,7 @@ this.SelectParentHelper = {
|
|||
currentBrowser.messageManager.sendAsyncMessage("Forms:DismissedDropDown", {});
|
||||
currentBrowser = null;
|
||||
this._unregisterListeners(popup);
|
||||
menulist.hidden = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -69,11 +78,6 @@ function populateChildren(element, options, selectedIndex, startIndex = 0, isGro
|
|||
for (let option of options) {
|
||||
let item = element.ownerDocument.createElement("menuitem");
|
||||
item.setAttribute("label", option.textContent);
|
||||
item.setAttribute("type", "radio");
|
||||
|
||||
if (index == selectedIndex) {
|
||||
item.setAttribute("checked", "true");
|
||||
}
|
||||
|
||||
element.appendChild(item);
|
||||
|
||||
|
|
|
@ -8,11 +8,14 @@
|
|||
menulist {
|
||||
-moz-appearance: menulist;
|
||||
margin: 5px 2px 3px;
|
||||
min-height: 20px !important;
|
||||
color: -moz-DialogText;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
menulist:not([popuponly="true"]) {
|
||||
min-height: 20px !important;
|
||||
}
|
||||
|
||||
.menulist-label-box {
|
||||
-moz-appearance: menulist-text;
|
||||
-moz-box-align: center;
|
||||
|
|
Загрузка…
Ссылка в новой задаче