merge m-c to fx-team
@ -15,16 +15,14 @@ function Cell(aGrid, aNode) {
|
||||
this._node._newtabCell = this;
|
||||
|
||||
// Register drag-and-drop event handlers.
|
||||
["DragEnter", "DragOver", "DragExit", "Drop"].forEach(function (aType) {
|
||||
let method = "on" + aType;
|
||||
this[method] = this[method].bind(this);
|
||||
this._node.addEventListener(aType.toLowerCase(), this[method], false);
|
||||
["dragenter", "dragover", "dragexit", "drop"].forEach(function (aType) {
|
||||
this._node.addEventListener(aType, this, false);
|
||||
}, this);
|
||||
}
|
||||
|
||||
Cell.prototype = {
|
||||
/**
|
||||
*
|
||||
* The grid.
|
||||
*/
|
||||
_grid: null,
|
||||
|
||||
@ -97,41 +95,27 @@ Cell.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'dragenter' event.
|
||||
* @param aEvent The dragenter event.
|
||||
* Handles all cell events.
|
||||
*/
|
||||
onDragEnter: function Cell_onDragEnter(aEvent) {
|
||||
if (gDrag.isValid(aEvent)) {
|
||||
aEvent.preventDefault();
|
||||
gDrop.enter(this, aEvent);
|
||||
}
|
||||
},
|
||||
handleEvent: function Cell_handleEvent(aEvent) {
|
||||
if (aEvent.type != "dragexit" && !gDrag.isValid(aEvent))
|
||||
return;
|
||||
|
||||
/**
|
||||
* Event handler for the 'dragover' event.
|
||||
* @param aEvent The dragover event.
|
||||
*/
|
||||
onDragOver: function Cell_onDragOver(aEvent) {
|
||||
if (gDrag.isValid(aEvent))
|
||||
aEvent.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'dragexit' event.
|
||||
* @param aEvent The dragexit event.
|
||||
*/
|
||||
onDragExit: function Cell_onDragExit(aEvent) {
|
||||
gDrop.exit(this, aEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'drop' event.
|
||||
* @param aEvent The drop event.
|
||||
*/
|
||||
onDrop: function Cell_onDrop(aEvent) {
|
||||
if (gDrag.isValid(aEvent)) {
|
||||
aEvent.preventDefault();
|
||||
gDrop.drop(this, aEvent);
|
||||
switch (aEvent.type) {
|
||||
case "dragenter":
|
||||
aEvent.preventDefault();
|
||||
gDrop.enter(this, aEvent);
|
||||
break;
|
||||
case "dragover":
|
||||
aEvent.preventDefault();
|
||||
break;
|
||||
case "dragexit":
|
||||
gDrop.exit(this, aEvent);
|
||||
break;
|
||||
case "drop":
|
||||
aEvent.preventDefault();
|
||||
gDrop.drop(this, aEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -36,11 +36,11 @@ let gDrag = {
|
||||
start: function Drag_start(aSite, aEvent) {
|
||||
this._draggedSite = aSite;
|
||||
|
||||
// Prevent moz-transform for left, top.
|
||||
aSite.node.setAttribute("dragged", "true");
|
||||
|
||||
// Make sure the dragged site is floating above the grid.
|
||||
aSite.node.setAttribute("ontop", "true");
|
||||
// Mark nodes as being dragged.
|
||||
let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
|
||||
let nodes = aSite.node.parentNode.querySelectorAll(selector);
|
||||
for (let i = 0; i < nodes.length; i++)
|
||||
nodes[i].setAttribute("dragged", "true");
|
||||
|
||||
this._setDragData(aSite, aEvent);
|
||||
|
||||
@ -88,13 +88,12 @@ let gDrag = {
|
||||
* @param aEvent The 'dragend' event.
|
||||
*/
|
||||
end: function Drag_end(aSite, aEvent) {
|
||||
aSite.node.removeAttribute("dragged");
|
||||
let nodes = aSite.node.parentNode.querySelectorAll("[dragged]");
|
||||
for (let i = 0; i < nodes.length; i++)
|
||||
nodes[i].removeAttribute("dragged");
|
||||
|
||||
// Slide the dragged site back into its cell (may be the old or the new cell).
|
||||
gTransformation.slideSiteTo(aSite, aSite.cell, {
|
||||
unfreeze: true,
|
||||
callback: function () aSite.node.removeAttribute("ontop")
|
||||
});
|
||||
gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true});
|
||||
|
||||
this._draggedSite = null;
|
||||
},
|
||||
@ -106,7 +105,11 @@ let gDrag = {
|
||||
*/
|
||||
isValid: function Drag_isValid(aEvent) {
|
||||
let dt = aEvent.dataTransfer;
|
||||
return dt && dt.types.contains("text/x-moz-url");
|
||||
let mimeType = "text/x-moz-url";
|
||||
|
||||
// Check that the drag data is non-empty.
|
||||
// Can happen when dragging places folders.
|
||||
return dt && dt.types.contains(mimeType) && dt.getData(mimeType);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -128,13 +131,13 @@ let gDrag = {
|
||||
// Create and use an empty drag element. We don't want to use the default
|
||||
// drag image with its default opacity.
|
||||
let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
|
||||
dragElement.classList.add("drag-element");
|
||||
let body = document.getElementById("body");
|
||||
body.appendChild(dragElement);
|
||||
dragElement.classList.add("newtab-drag");
|
||||
let scrollbox = document.getElementById("newtab-scrollbox");
|
||||
scrollbox.appendChild(dragElement);
|
||||
dt.setDragImage(dragElement, 0, 0);
|
||||
|
||||
// After the 'dragstart' event has been processed we can remove the
|
||||
// temporary drag element from the DOM.
|
||||
setTimeout(function () body.removeChild(dragElement), 0);
|
||||
setTimeout(function () scrollbox.removeChild(dragElement), 0);
|
||||
}
|
||||
};
|
||||
|
@ -26,13 +26,26 @@ let gDropTargetShim = {
|
||||
init: function DropTargetShim_init() {
|
||||
let node = gGrid.node;
|
||||
|
||||
this._dragover = this._dragover.bind(this);
|
||||
|
||||
// Add drag event handlers.
|
||||
node.addEventListener("dragstart", this._start.bind(this), true);
|
||||
// XXX bug 505521 - Don't listen for drag, it's useless at the moment.
|
||||
//node.addEventListener("drag", this._drag.bind(this), false);
|
||||
node.addEventListener("dragend", this._end.bind(this), true);
|
||||
node.addEventListener("dragstart", this, true);
|
||||
node.addEventListener("dragend", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles all shim events.
|
||||
*/
|
||||
handleEvent: function DropTargetShim_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "dragstart":
|
||||
this._start(aEvent);
|
||||
break;
|
||||
case "dragover":
|
||||
this._dragover(aEvent);
|
||||
break;
|
||||
case "dragend":
|
||||
this._end(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -40,11 +53,11 @@ let gDropTargetShim = {
|
||||
* @param aEvent The 'dragstart' event.
|
||||
*/
|
||||
_start: function DropTargetShim_start(aEvent) {
|
||||
if (aEvent.target.classList.contains("site")) {
|
||||
if (aEvent.target.classList.contains("newtab-link")) {
|
||||
gGrid.lock();
|
||||
|
||||
// XXX bug 505521 - Listen for dragover on the document.
|
||||
document.documentElement.addEventListener("dragover", this._dragover, false);
|
||||
document.documentElement.addEventListener("dragover", this, false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -56,12 +69,7 @@ let gDropTargetShim = {
|
||||
// Let's see if we find a drop target.
|
||||
let target = this._findDropTarget(aEvent);
|
||||
|
||||
if (target == this._lastDropTarget) {
|
||||
// XXX bug 505521 - Don't fire dragover for now (causes recursion).
|
||||
/*if (target)
|
||||
// The last drop target is valid and didn't change.
|
||||
this._dispatchEvent(aEvent, "dragover", target);*/
|
||||
} else {
|
||||
if (target != this._lastDropTarget) {
|
||||
if (this._lastDropTarget)
|
||||
// We left the last drop target.
|
||||
this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
|
||||
@ -84,7 +92,7 @@ let gDropTargetShim = {
|
||||
* @param aEvent The 'dragover' event.
|
||||
*/
|
||||
_dragover: function DropTargetShim_dragover(aEvent) {
|
||||
let sourceNode = aEvent.dataTransfer.mozSourceNode;
|
||||
let sourceNode = aEvent.dataTransfer.mozSourceNode.parentNode;
|
||||
gDrag.drag(sourceNode._newtabSite, aEvent);
|
||||
|
||||
this._drag(aEvent);
|
||||
@ -117,7 +125,7 @@ let gDropTargetShim = {
|
||||
gGrid.unlock();
|
||||
|
||||
// XXX bug 505521 - Remove the document's dragover listener.
|
||||
document.documentElement.removeEventListener("dragover", this._dragover, false);
|
||||
document.documentElement.removeEventListener("dragover", this, false);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ let gGrid = {
|
||||
*/
|
||||
get cells() {
|
||||
let cells = [];
|
||||
let children = this.node.querySelectorAll("li");
|
||||
let children = this.node.querySelectorAll(".newtab-cell");
|
||||
for (let i = 0; i < children.length; i++)
|
||||
cells.push(new Cell(this, children[i]));
|
||||
|
||||
@ -43,8 +43,8 @@ let gGrid = {
|
||||
* Initializes the grid.
|
||||
* @param aSelector The query selector of the grid.
|
||||
*/
|
||||
init: function Grid_init(aSelector) {
|
||||
this._node = document.querySelector(aSelector);
|
||||
init: function Grid_init() {
|
||||
this._node = document.getElementById("newtab-grid");
|
||||
this._createSiteFragment();
|
||||
this._draw();
|
||||
},
|
||||
@ -96,21 +96,20 @@ let gGrid = {
|
||||
* Creates the DOM fragment that is re-used when creating sites.
|
||||
*/
|
||||
_createSiteFragment: function Grid_createSiteFragment() {
|
||||
let site = document.createElementNS(HTML_NAMESPACE, "a");
|
||||
site.classList.add("site");
|
||||
let site = document.createElementNS(HTML_NAMESPACE, "div");
|
||||
site.classList.add("newtab-site");
|
||||
site.setAttribute("draggable", "true");
|
||||
|
||||
// Create the site's inner HTML code.
|
||||
site.innerHTML =
|
||||
'<img class="site-img" width="' + THUMB_WIDTH +'" ' +
|
||||
' height="' + THUMB_HEIGHT + '" alt=""/>' +
|
||||
'<span class="site-title"/>' +
|
||||
'<span class="site-strip">' +
|
||||
' <input class="button strip-button strip-button-pin" type="button"' +
|
||||
' tabindex="-1" title="' + newTabString("pin") + '"/>' +
|
||||
' <input class="button strip-button strip-button-block" type="button"' +
|
||||
' tabindex="-1" title="' + newTabString("block") + '"/>' +
|
||||
'</span>';
|
||||
'<a class="newtab-link">' +
|
||||
' <span class="newtab-thumbnail"/>' +
|
||||
' <span class="newtab-title"/>' +
|
||||
'</a>' +
|
||||
'<input type="button" title="' + newTabString("pin") + '"' +
|
||||
' class="newtab-control newtab-control-pin"/>' +
|
||||
'<input type="button" title="' + newTabString("block") + '"' +
|
||||
' class="newtab-control newtab-control-block"/>';
|
||||
|
||||
this._siteFragment = document.createDocumentFragment();
|
||||
this._siteFragment.appendChild(site);
|
||||
|
@ -1,161 +1,174 @@
|
||||
:root {
|
||||
-moz-appearance: none;
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
#scrollbox:not([page-disabled]) {
|
||||
input[type=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* SCROLLBOX */
|
||||
#newtab-scrollbox {
|
||||
display: -moz-box;
|
||||
position: relative;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#newtab-scrollbox:not([page-disabled]) {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#body {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
min-width: 675px;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* TOOLBAR */
|
||||
#toolbar {
|
||||
/* TOGGLE */
|
||||
#newtab-toggle {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
#toolbar[page-disabled] {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#toolbar:-moz-locale-dir(rtl) {
|
||||
left: 8px;
|
||||
#newtab-toggle:-moz-locale-dir(rtl) {
|
||||
left: 12px;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
-moz-transition: opacity 200ms ease-out;
|
||||
/* MARGINS */
|
||||
#newtab-vertical-margin {
|
||||
display: -moz-box;
|
||||
position: relative;
|
||||
-moz-box-flex: 1;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
#toolbar-button-show,
|
||||
#toolbar-button-reset {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
#newtab-margin-top {
|
||||
min-height: 50px;
|
||||
max-height: 80px;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#toolbar-button-reset[modified],
|
||||
#toolbar-button-show[page-disabled] {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
#newtab-margin-bottom {
|
||||
min-height: 40px;
|
||||
max-height: 100px;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#toolbar-button-hide[page-disabled],
|
||||
#toolbar-button-reset[page-disabled] {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
#newtab-horizontal-margin {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 5;
|
||||
}
|
||||
|
||||
.newtab-side-margin {
|
||||
min-width: 40px;
|
||||
max-width: 300px;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
/* GRID */
|
||||
#grid {
|
||||
width: 637px;
|
||||
height: 411px;
|
||||
overflow: hidden;
|
||||
list-style-type: none;
|
||||
-moz-transition: opacity 200ms ease-out;
|
||||
#newtab-grid {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 5;
|
||||
-moz-box-orient: vertical;
|
||||
min-width: 600px;
|
||||
min-height: 400px;
|
||||
-moz-transition: 100ms ease-out;
|
||||
-moz-transition-property: opacity;
|
||||
}
|
||||
|
||||
#grid[page-disabled] {
|
||||
#newtab-grid[page-disabled] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#grid[page-disabled],
|
||||
#grid[locked] {
|
||||
#newtab-grid[locked],
|
||||
#newtab-grid[page-disabled] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ROWS */
|
||||
.newtab-row {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-direction: normal;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
float: left;
|
||||
width: 201px;
|
||||
height: 127px;
|
||||
margin-bottom: 15px;
|
||||
-moz-margin-end: 16px;
|
||||
}
|
||||
|
||||
.cell:-moz-locale-dir(rtl) {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.cell:nth-child(3n+3) {
|
||||
-moz-margin-end: 0;
|
||||
.newtab-cell {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
display: block;
|
||||
.newtab-site {
|
||||
position: relative;
|
||||
width: 201px;
|
||||
height: 127px;
|
||||
-moz-box-flex: 1;
|
||||
-moz-transition: 100ms ease-out;
|
||||
-moz-transition-property: top, left, opacity;
|
||||
}
|
||||
|
||||
.site[frozen] {
|
||||
.newtab-site[frozen] {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.site[ontop] {
|
||||
.newtab-site[dragged] {
|
||||
-moz-transition-property: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* SITE IMAGE */
|
||||
.site-img {
|
||||
display: block;
|
||||
opacity: 0.75;
|
||||
-moz-transition: opacity 200ms ease-out;
|
||||
}
|
||||
|
||||
.site:hover > .site-img,
|
||||
.site[ontop] > .site-img,
|
||||
.site:-moz-focusring > .site-img {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.site-img[loading] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* SITE TITLE */
|
||||
.site-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* SITE STRIP */
|
||||
.site-strip {
|
||||
/* LINK + THUMBNAILS */
|
||||
.newtab-link,
|
||||
.newtab-thumbnail {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 195px;
|
||||
height: 17px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
-moz-transition: opacity 200ms ease-out;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.site:hover:not([frozen]) > .site-strip {
|
||||
.newtab-thumbnail {
|
||||
opacity: .8;
|
||||
-moz-transition: opacity 100ms ease-out;
|
||||
}
|
||||
|
||||
.newtab-thumbnail[dragged],
|
||||
.newtab-link:-moz-focusring > .newtab-thumbnail,
|
||||
.newtab-site:hover > .newtab-link > .newtab-thumbnail {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.strip-button-pin,
|
||||
.strip-button-block:-moz-locale-dir(rtl) {
|
||||
float: left;
|
||||
/* TITLES */
|
||||
.newtab-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.strip-button-block,
|
||||
.strip-button-pin:-moz-locale-dir(rtl) {
|
||||
float: right;
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
opacity: 0;
|
||||
-moz-transition: opacity 100ms ease-out;
|
||||
}
|
||||
|
||||
.newtab-control:-moz-focusring,
|
||||
.newtab-site:hover > .newtab-control {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.newtab-control[dragged] {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.newtab-control-pin:-moz-locale-dir(ltr),
|
||||
.newtab-control-block:-moz-locale-dir(rtl) {
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
.newtab-control-block:-moz-locale-dir(ltr),
|
||||
.newtab-control-pin:-moz-locale-dir(rtl) {
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
/* DRAG & DROP */
|
||||
@ -165,7 +178,7 @@
|
||||
* so that we can use custom drag images and elements. It needs an opacity of
|
||||
* 0.01 so that the core code detects that it's in fact a visible element.
|
||||
*/
|
||||
.drag-element {
|
||||
.newtab-drag {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
background-color: #fff;
|
||||
|
@ -30,13 +30,10 @@ XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
|
||||
function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
|
||||
|
||||
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
const THUMB_WIDTH = 201;
|
||||
const THUMB_HEIGHT = 127;
|
||||
|
||||
#include batch.js
|
||||
#include transformations.js
|
||||
#include page.js
|
||||
#include toolbar.js
|
||||
#include grid.js
|
||||
#include cells.js
|
||||
#include sites.js
|
||||
@ -47,4 +44,4 @@ const THUMB_HEIGHT = 127;
|
||||
#include updater.js
|
||||
|
||||
// Everything is loaded. Initialize the New Tab Page.
|
||||
gPage.init("#toolbar", "#grid");
|
||||
gPage.init();
|
||||
|
@ -4,7 +4,7 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/newtab/newTab.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/newtab/newTab.css" type="text/css"?>
|
||||
|
||||
@ -13,28 +13,44 @@
|
||||
%newTabDTD;
|
||||
]>
|
||||
|
||||
<xul:window xmlns="http://www.w3.org/1999/xhtml"
|
||||
<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
disablefastfind="true" title="&newtab.pageTitle;">
|
||||
<xul:vbox id="scrollbox" flex="1" title=" ">
|
||||
<body id="body">
|
||||
<div id="toolbar">
|
||||
<input class="button toolbar-button" id="toolbar-button-show"
|
||||
type="button" title="&newtab.show;"/>
|
||||
<input class="button toolbar-button" id="toolbar-button-hide"
|
||||
type="button" title="&newtab.hide;"/>
|
||||
<input class="button toolbar-button" id="toolbar-button-reset"
|
||||
type="button" title="&newtab.reset;"/>
|
||||
xul:disablefastfind="true" xul:title="&newtab.pageTitle;">
|
||||
|
||||
<div id="newtab-scrollbox">
|
||||
|
||||
<div id="newtab-vertical-margin">
|
||||
<div id="newtab-margin-top"/>
|
||||
|
||||
<div id="newtab-horizontal-margin">
|
||||
<div class="newtab-side-margin"/>
|
||||
|
||||
<div id="newtab-grid">
|
||||
<div class="newtab-row">
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
</div>
|
||||
<div class="newtab-row">
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
</div>
|
||||
<div class="newtab-row">
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
<div class="newtab-cell"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="newtab-side-margin"/>
|
||||
</div>
|
||||
|
||||
<ul id="grid">
|
||||
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||
<li class="cell"/><li class="cell"/><li class="cell"/>
|
||||
</ul>
|
||||
<div id="newtab-margin-bottom"/>
|
||||
</div>
|
||||
<input id="newtab-toggle" type="button"/>
|
||||
</div>
|
||||
|
||||
<xul:script type="text/javascript;version=1.8"
|
||||
src="chrome://browser/content/newtab/newTab.js"/>
|
||||
</body>
|
||||
</xul:vbox>
|
||||
<xul:script type="text/javascript;version=1.8"
|
||||
src="chrome://browser/content/newtab/newTab.js"/>
|
||||
</xul:window>
|
||||
|
@ -11,25 +11,24 @@
|
||||
let gPage = {
|
||||
/**
|
||||
* Initializes the page.
|
||||
* @param aToolbarSelector The query selector for the page toolbar.
|
||||
* @param aGridSelector The query selector for the grid.
|
||||
*/
|
||||
init: function Page_init(aToolbarSelector, aGridSelector) {
|
||||
gToolbar.init(aToolbarSelector);
|
||||
this._gridSelector = aGridSelector;
|
||||
|
||||
init: function Page_init() {
|
||||
// Add ourselves to the list of pages to receive notifications.
|
||||
gAllPages.register(this);
|
||||
|
||||
// Listen for 'unload' to unregister this page.
|
||||
function unload() { gAllPages.unregister(this); }
|
||||
addEventListener("unload", unload.bind(this), false);
|
||||
addEventListener("unload", this, false);
|
||||
|
||||
// Listen for toggle button clicks.
|
||||
let button = document.getElementById("newtab-toggle");
|
||||
button.addEventListener("click", this, false);
|
||||
|
||||
// Check if the new tab feature is enabled.
|
||||
if (gAllPages.enabled)
|
||||
let enabled = gAllPages.enabled;
|
||||
if (enabled)
|
||||
this._init();
|
||||
else
|
||||
this._updateAttributes(false);
|
||||
|
||||
this._updateAttributes(enabled);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -48,25 +47,9 @@ let gPage = {
|
||||
* Updates the whole page and the grid when the storage has changed.
|
||||
*/
|
||||
update: function Page_update() {
|
||||
this.updateModifiedFlag();
|
||||
gGrid.refresh();
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the page is modified and sets the CSS class accordingly
|
||||
*/
|
||||
updateModifiedFlag: function Page_updateModifiedFlag() {
|
||||
let node = document.getElementById("toolbar-button-reset");
|
||||
let modified = this._isModified();
|
||||
|
||||
if (modified)
|
||||
node.setAttribute("modified", "true");
|
||||
else
|
||||
node.removeAttribute("modified");
|
||||
|
||||
this._updateTabIndices(gAllPages.enabled, modified);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally initializes the page. This runs only when/if the feature
|
||||
* is/gets enabled.
|
||||
@ -78,29 +61,27 @@ let gPage = {
|
||||
this._initialized = true;
|
||||
|
||||
gLinks.populateCache(function () {
|
||||
// Check if the grid is modified.
|
||||
this.updateModifiedFlag();
|
||||
|
||||
// Initialize and render the grid.
|
||||
gGrid.init(this._gridSelector);
|
||||
gGrid.init();
|
||||
|
||||
// Initialize the drop target shim.
|
||||
gDropTargetShim.init();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Workaround to prevent a delay on MacOSX due to a slow drop animation.
|
||||
document.addEventListener("dragover", this.onDragOver, false);
|
||||
document.addEventListener("drop", this.onDrop, false);
|
||||
document.addEventListener("dragover", this, false);
|
||||
document.addEventListener("drop", this, false);
|
||||
#endif
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the 'page-disabled' attributes of the respective DOM nodes.
|
||||
* @param aValue Whether to set or remove attributes.
|
||||
* @param aValue Whether the New Tab Page is enabled or not.
|
||||
*/
|
||||
_updateAttributes: function Page_updateAttributes(aValue) {
|
||||
let nodes = document.querySelectorAll("#grid, #scrollbox, #toolbar, .toolbar-button");
|
||||
let selector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid";
|
||||
let nodes = document.querySelectorAll(selector);
|
||||
|
||||
// Set the nodes' states.
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
@ -111,64 +92,32 @@ let gPage = {
|
||||
node.setAttribute("page-disabled", "true");
|
||||
}
|
||||
|
||||
this._updateTabIndices(aValue, this._isModified());
|
||||
// Update the toggle button's title.
|
||||
let toggle = document.getElementById("newtab-toggle");
|
||||
toggle.setAttribute("title", newTabString(aValue ? "hide" : "show"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the page is modified.
|
||||
* @return Whether the page is modified or not.
|
||||
* Handles all page events.
|
||||
*/
|
||||
_isModified: function Page_isModified() {
|
||||
// The page is considered modified only if sites have been removed.
|
||||
return !gBlockedLinks.isEmpty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the tab indices of focusable elements.
|
||||
* @param aEnabled Whether the page is currently enabled.
|
||||
* @param aModified Whether the page is currently modified.
|
||||
*/
|
||||
_updateTabIndices: function Page_updateTabIndices(aEnabled, aModified) {
|
||||
function setFocusable(aNode, aFocusable) {
|
||||
if (aFocusable)
|
||||
aNode.removeAttribute("tabindex");
|
||||
else
|
||||
aNode.setAttribute("tabindex", "-1");
|
||||
}
|
||||
|
||||
// Sites and the 'hide' button are always focusable when the grid is shown.
|
||||
let nodes = document.querySelectorAll(".site, #toolbar-button-hide");
|
||||
for (let i = 0; i < nodes.length; i++)
|
||||
setFocusable(nodes[i], aEnabled);
|
||||
|
||||
// The 'show' button is focusable when the grid is hidden.
|
||||
let btnShow = document.getElementById("toolbar-button-show");
|
||||
setFocusable(btnShow, !aEnabled);
|
||||
|
||||
// The 'reset' button is focusable when the grid is shown and modified.
|
||||
let btnReset = document.getElementById("toolbar-button-reset");
|
||||
setFocusable(btnReset, aEnabled && aModified);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the 'dragover' event. Workaround to prevent a delay on MacOSX
|
||||
* due to a slow drop animation.
|
||||
* @param aEvent The 'dragover' event.
|
||||
*/
|
||||
onDragOver: function Page_onDragOver(aEvent) {
|
||||
if (gDrag.isValid(aEvent) && gDrag.draggedSite)
|
||||
aEvent.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the 'drop' event. Workaround to prevent a delay on MacOSX due to
|
||||
* a slow drop animation.
|
||||
* @param aEvent The 'drop' event.
|
||||
*/
|
||||
onDrop: function Page_onDrop(aEvent) {
|
||||
if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopPropagation();
|
||||
handleEvent: function Page_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "unload":
|
||||
gAllPages.unregister(this);
|
||||
break;
|
||||
case "click":
|
||||
gAllPages.enabled = !gAllPages.enabled;
|
||||
break;
|
||||
case "dragover":
|
||||
if (gDrag.isValid(aEvent) && gDrag.draggedSite)
|
||||
aEvent.preventDefault();
|
||||
break;
|
||||
case "drop":
|
||||
if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopPropagation();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -91,7 +91,6 @@ Site.prototype = {
|
||||
} else {
|
||||
gBlockedLinks.block(this._link);
|
||||
gUpdater.updateGrid(aCallback);
|
||||
gPage.updateModifiedFlag();
|
||||
}
|
||||
},
|
||||
|
||||
@ -110,14 +109,14 @@ Site.prototype = {
|
||||
* @param aPinned Whether this site is now pinned or unpinned.
|
||||
*/
|
||||
_updateAttributes: function (aPinned) {
|
||||
let buttonPin = this._querySelector(".strip-button-pin");
|
||||
let control = this._querySelector(".newtab-control-pin");
|
||||
|
||||
if (aPinned) {
|
||||
this.node.setAttribute("pinned", true);
|
||||
buttonPin.setAttribute("title", newTabString("unpin"));
|
||||
control.setAttribute("pinned", true);
|
||||
control.setAttribute("title", newTabString("unpin"));
|
||||
} else {
|
||||
this.node.removeAttribute("pinned");
|
||||
buttonPin.setAttribute("title", newTabString("pin"));
|
||||
control.removeAttribute("pinned");
|
||||
control.setAttribute("title", newTabString("pin"));
|
||||
}
|
||||
},
|
||||
|
||||
@ -126,32 +125,17 @@ Site.prototype = {
|
||||
*/
|
||||
_render: function Site_render() {
|
||||
let title = this.title || this.url;
|
||||
this.node.setAttribute("title", title);
|
||||
this.node.setAttribute("href", this.url);
|
||||
this._querySelector(".site-title").textContent = title;
|
||||
let link = this._querySelector(".newtab-link");
|
||||
link.setAttribute("title", title);
|
||||
link.setAttribute("href", this.url);
|
||||
this._querySelector(".newtab-title").textContent = title;
|
||||
|
||||
if (this.isPinned())
|
||||
this._updateAttributes(true);
|
||||
|
||||
this._renderThumbnail();
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the site's thumbnail.
|
||||
*/
|
||||
_renderThumbnail: function Site_renderThumbnail() {
|
||||
let img = this._querySelector(".site-img")
|
||||
img.setAttribute("alt", this.title || this.url);
|
||||
img.setAttribute("loading", "true");
|
||||
|
||||
// Wait until the image has loaded.
|
||||
img.addEventListener("load", function onLoad() {
|
||||
img.removeEventListener("load", onLoad, false);
|
||||
img.removeAttribute("loading");
|
||||
}, false);
|
||||
|
||||
// Set the thumbnail url.
|
||||
img.setAttribute("src", PageThumbs.getThumbnailURL(this.url));
|
||||
let thumbnailURL = PageThumbs.getThumbnailURL(this.url);
|
||||
let thumbnail = this._querySelector(".newtab-thumbnail");
|
||||
thumbnail.style.backgroundImage = "url(" + thumbnailURL + ")";
|
||||
},
|
||||
|
||||
/**
|
||||
@ -159,56 +143,37 @@ Site.prototype = {
|
||||
*/
|
||||
_addEventHandlers: function Site_addEventHandlers() {
|
||||
// Register drag-and-drop event handlers.
|
||||
["DragStart", /*"Drag",*/ "DragEnd"].forEach(function (aType) {
|
||||
let method = "_on" + aType;
|
||||
this[method] = this[method].bind(this);
|
||||
this._node.addEventListener(aType.toLowerCase(), this[method], false);
|
||||
}, this);
|
||||
this._node.addEventListener("dragstart", this, false);
|
||||
this._node.addEventListener("dragend", this, false);
|
||||
|
||||
let self = this;
|
||||
|
||||
function pin(aEvent) {
|
||||
if (aEvent)
|
||||
aEvent.preventDefault();
|
||||
|
||||
if (self.isPinned())
|
||||
self.unpin();
|
||||
else
|
||||
self.pin();
|
||||
}
|
||||
|
||||
function block(aEvent) {
|
||||
if (aEvent)
|
||||
aEvent.preventDefault();
|
||||
|
||||
self.block();
|
||||
}
|
||||
|
||||
this._querySelector(".strip-button-pin").addEventListener("click", pin, false);
|
||||
this._querySelector(".strip-button-block").addEventListener("click", block, false);
|
||||
let controls = this.node.querySelectorAll(".newtab-control");
|
||||
for (let i = 0; i < controls.length; i++)
|
||||
controls[i].addEventListener("click", this, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'dragstart' event.
|
||||
* @param aEvent The drag event.
|
||||
* Handles all site events.
|
||||
*/
|
||||
_onDragStart: function Site_onDragStart(aEvent) {
|
||||
gDrag.start(this, aEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'drag' event.
|
||||
* @param aEvent The drag event.
|
||||
*/
|
||||
_onDrag: function Site_onDrag(aEvent) {
|
||||
gDrag.drag(this, aEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for the 'dragend' event.
|
||||
* @param aEvent The drag event.
|
||||
*/
|
||||
_onDragEnd: function Site_onDragEnd(aEvent) {
|
||||
gDrag.end(this, aEvent);
|
||||
handleEvent: function Site_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "click":
|
||||
aEvent.preventDefault();
|
||||
if (aEvent.target.classList.contains("newtab-control-block"))
|
||||
this.block();
|
||||
else if (this.isPinned())
|
||||
this.unpin();
|
||||
else
|
||||
this.pin();
|
||||
break;
|
||||
case "dragstart":
|
||||
gDrag.start(this, aEvent);
|
||||
break;
|
||||
case "drag":
|
||||
gDrag.drag(this, aEvent);
|
||||
break;
|
||||
case "dragend":
|
||||
gDrag.end(this, aEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,87 +0,0 @@
|
||||
#ifdef 0
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This singleton represents the page's toolbar that allows to enable/disable
|
||||
* the 'New Tab Page' feature and to reset the whole page.
|
||||
*/
|
||||
let gToolbar = {
|
||||
/**
|
||||
* Initializes the toolbar.
|
||||
* @param aSelector The query selector of the toolbar.
|
||||
*/
|
||||
init: function Toolbar_init(aSelector) {
|
||||
this._node = document.querySelector(aSelector);
|
||||
let buttons = this._node.querySelectorAll("input");
|
||||
|
||||
// Listen for 'click' events on the toolbar buttons.
|
||||
["show", "hide", "reset"].forEach(function (aType, aIndex) {
|
||||
let self = this;
|
||||
let button = buttons[aIndex];
|
||||
let handler = function () self[aType]();
|
||||
|
||||
button.addEventListener("click", handler, false);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Per default buttons lose focus after being clicked on Mac OS X.
|
||||
// So when the URL bar has focus and a toolbar button is clicked the
|
||||
// URL bar regains focus and the history pops up. We need to prevent
|
||||
// that by explicitly removing its focus.
|
||||
button.addEventListener("mousedown", function () {
|
||||
window.focus();
|
||||
}, false);
|
||||
#endif
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the 'New Tab Page' feature.
|
||||
*/
|
||||
show: function Toolbar_show() {
|
||||
this._passButtonFocus("show", "hide");
|
||||
gAllPages.enabled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables the 'New Tab Page' feature.
|
||||
*/
|
||||
hide: function Toolbar_hide() {
|
||||
this._passButtonFocus("hide", "show");
|
||||
gAllPages.enabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the whole page and forces it to re-render its content.
|
||||
* @param aCallback The callback to call when the page has been reset.
|
||||
*/
|
||||
reset: function Toolbar_reset(aCallback) {
|
||||
this._passButtonFocus("reset", "hide");
|
||||
let node = gGrid.node;
|
||||
|
||||
// animate the page reset
|
||||
gTransformation.fadeNodeOut(node, function () {
|
||||
NewTabUtils.reset();
|
||||
|
||||
gLinks.populateCache(function () {
|
||||
gAllPages.update();
|
||||
|
||||
// Without the setTimeout() we have a strange flicker.
|
||||
setTimeout(function () gTransformation.fadeNodeIn(node, aCallback));
|
||||
}, true);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Passes the focus from the current button to the next.
|
||||
* @param aCurrent The button that currently has focus.
|
||||
* @param aNext The button that is focused next.
|
||||
*/
|
||||
_passButtonFocus: function Toolbar_passButtonFocus(aCurrent, aNext) {
|
||||
if (document.querySelector("#toolbar-button-" + aCurrent + ":-moz-focusring"))
|
||||
document.getElementById("toolbar-button-" + aNext).focus();
|
||||
}
|
||||
};
|
||||
|
@ -10,6 +10,24 @@
|
||||
* convenience methods to work with a site's DOM node.
|
||||
*/
|
||||
let gTransformation = {
|
||||
/**
|
||||
* Returns the width of the left and top border of a cell. We need to take it
|
||||
* into account when measuring and comparing site and cell positions.
|
||||
*/
|
||||
get _cellBorderWidths() {
|
||||
let cstyle = window.getComputedStyle(gGrid.cells[0].node, null);
|
||||
let widths = {
|
||||
left: parseInt(cstyle.getPropertyValue("border-left-width")),
|
||||
top: parseInt(cstyle.getPropertyValue("border-top-width"))
|
||||
};
|
||||
|
||||
// Cache this value, overwrite the getter.
|
||||
Object.defineProperty(this, "_cellBorderWidths",
|
||||
{value: widths, enumerable: true});
|
||||
|
||||
return widths;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a DOM node's position.
|
||||
* @param aNode The DOM node.
|
||||
@ -80,6 +98,14 @@ let gTransformation = {
|
||||
* @param aSite The site to freeze.
|
||||
*/
|
||||
freezeSitePosition: function Transformation_freezeSitePosition(aSite) {
|
||||
if (this._isFrozen(aSite))
|
||||
return;
|
||||
|
||||
let style = aSite.node.style;
|
||||
let comp = getComputedStyle(aSite.node, null);
|
||||
style.width = comp.getPropertyValue("width")
|
||||
style.height = comp.getPropertyValue("height");
|
||||
|
||||
aSite.node.setAttribute("frozen", "true");
|
||||
this.setSitePosition(aSite, this.getNodePosition(aSite.node));
|
||||
},
|
||||
@ -89,8 +115,11 @@ let gTransformation = {
|
||||
* @param aSite The site to unfreeze.
|
||||
*/
|
||||
unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) {
|
||||
if (!this._isFrozen(aSite))
|
||||
return;
|
||||
|
||||
let style = aSite.node.style;
|
||||
style.left = style.top = "";
|
||||
style.left = style.top = style.width = style.height = "";
|
||||
aSite.node.removeAttribute("frozen");
|
||||
},
|
||||
|
||||
@ -117,8 +146,13 @@ let gTransformation = {
|
||||
callback();
|
||||
}
|
||||
|
||||
// We need to take the width of a cell's border into account.
|
||||
targetPosition.left += this._cellBorderWidths.left;
|
||||
targetPosition.top += this._cellBorderWidths.top;
|
||||
|
||||
// Nothing to do here if the positions already match.
|
||||
if (currentPosition.equals(targetPosition)) {
|
||||
if (currentPosition.left == targetPosition.left &&
|
||||
currentPosition.top == targetPosition.top) {
|
||||
finish();
|
||||
} else {
|
||||
this.setSitePosition(aSite, targetPosition);
|
||||
@ -222,5 +256,14 @@ let gTransformation = {
|
||||
_moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) {
|
||||
this.freezeSitePosition(aSite);
|
||||
this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether a site is currently frozen.
|
||||
* @param aSite The site to check.
|
||||
* @return Whether the given site is frozen.
|
||||
*/
|
||||
_isFrozen: function Transformation_isFrozen(aSite) {
|
||||
return aSite.node.hasAttribute("frozen");
|
||||
}
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ _BROWSER_FILES = \
|
||||
browser_newtab_bug722273.js \
|
||||
browser_newtab_bug723102.js \
|
||||
browser_newtab_bug723121.js \
|
||||
browser_newtab_bug725996.js \
|
||||
browser_newtab_bug734043.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
@ -12,6 +12,7 @@ function runTests() {
|
||||
yield addNewTabPageTab();
|
||||
gBrowser.removeTab(firstTab);
|
||||
|
||||
cw.gToolbar.hide();
|
||||
ok(NewTabUtils.allPages.enabled, true, "page is enabled");
|
||||
NewTabUtils.allPages.enabled = false;
|
||||
ok(cw.gGrid.node.hasAttribute("page-disabled"), "page is disabled");
|
||||
}
|
||||
|
@ -10,15 +10,19 @@ function runTests() {
|
||||
|
||||
let cell = cells[0].node;
|
||||
let site = cells[0].site.node;
|
||||
let link = site.querySelector(".newtab-link");
|
||||
|
||||
sendDragEvent(site, "dragstart");
|
||||
sendDragEvent(link, "dragstart");
|
||||
checkGridLocked(true, "grid is now locked");
|
||||
|
||||
sendDragEvent(site, "dragend");
|
||||
sendDragEvent(link, "dragend");
|
||||
checkGridLocked(false, "grid isn't locked anymore");
|
||||
|
||||
sendDragEvent(cell, "dragstart");
|
||||
checkGridLocked(false, "grid isn't locked - dragstart was ignored");
|
||||
|
||||
sendDragEvent(site, "dragstart");
|
||||
checkGridLocked(false, "grid isn't locked - dragstart was ignored");
|
||||
}
|
||||
|
||||
function checkGridLocked(aLocked, aMessage) {
|
||||
|
52
browser/base/content/test/newtab/browser_newtab_bug725996.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function runTests() {
|
||||
setLinks("0,1,2,3,4,5,6,7,8");
|
||||
setPinnedLinks("");
|
||||
|
||||
yield addNewTabPageTab();
|
||||
checkGrid("0,1,2,3,4,5,6,7,8");
|
||||
|
||||
let cell = cells[0].node;
|
||||
|
||||
sendDropEvent(cell, "about:blank#99\nblank");
|
||||
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
|
||||
"first cell is pinned and contains the dropped site");
|
||||
|
||||
yield whenPagesUpdated();
|
||||
checkGrid("99p,0,1,2,3,4,5,6,7");
|
||||
|
||||
sendDropEvent(cell, "");
|
||||
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
|
||||
"first cell is still pinned with the site we dropped before");
|
||||
}
|
||||
|
||||
function sendDropEvent(aNode, aData) {
|
||||
let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
let dataTransfer = {
|
||||
mozUserCancelled: false,
|
||||
setData: function () null,
|
||||
setDragImage: function () null,
|
||||
getData: function () aData,
|
||||
|
||||
types: {
|
||||
contains: function (aType) aType == "text/x-moz-url"
|
||||
},
|
||||
|
||||
mozGetDataAt: function (aType, aIndex) {
|
||||
if (aIndex || aType != "text/x-moz-url")
|
||||
return null;
|
||||
|
||||
return aData;
|
||||
},
|
||||
};
|
||||
|
||||
let event = cw.document.createEvent("DragEvents");
|
||||
event.initDragEvent("drop", true, true, cw, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 0, null, dataTransfer);
|
||||
|
||||
windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
|
||||
}
|
@ -2,13 +2,16 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function runTests() {
|
||||
// TODO Bug 735166 - Intermittent timeout in browser_newtab_bug734043.js
|
||||
return;
|
||||
|
||||
setLinks("0,1,2,3,4,5,6,7,8");
|
||||
setPinnedLinks("");
|
||||
|
||||
yield addNewTabPageTab();
|
||||
|
||||
let receivedError = false;
|
||||
let block = cw.document.querySelector(".strip-button-block");
|
||||
let block = cw.document.querySelector(".newtab-control-block");
|
||||
|
||||
function onError() {
|
||||
receivedError = true;
|
||||
|
@ -15,7 +15,7 @@ function runTests() {
|
||||
|
||||
ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
|
||||
|
||||
cw.gToolbar.hide();
|
||||
NewTabUtils.allPages.enabled = false;
|
||||
ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
|
||||
|
||||
let oldGridNode = cw.gGrid.node;
|
||||
@ -28,7 +28,7 @@ function runTests() {
|
||||
// check that no sites have been rendered
|
||||
is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
|
||||
|
||||
cw.gToolbar.show();
|
||||
NewTabUtils.allPages.enabled = true;
|
||||
ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
|
||||
ok(!oldGridNode.hasAttribute("page-disabled"), "old page is not disabled");
|
||||
}
|
||||
|
@ -5,6 +5,9 @@
|
||||
* These tests make sure that resetting the 'New Tage Page' works as expected.
|
||||
*/
|
||||
function runTests() {
|
||||
// Disabled until bug 716543 is fixed.
|
||||
return;
|
||||
|
||||
// create a new tab page and check its modified state after blocking a site
|
||||
setLinks("0,1,2,3,4,5,6,7,8");
|
||||
setPinnedLinks("");
|
||||
|
@ -8,6 +8,9 @@
|
||||
* state.
|
||||
*/
|
||||
function runTests() {
|
||||
// Disabled until bug 716543 is fixed.
|
||||
return;
|
||||
|
||||
setLinks("0,1,2,3,4,5,6,7,8,9");
|
||||
setPinnedLinks(",1");
|
||||
|
||||
|
@ -188,7 +188,7 @@ function checkGrid(aSitesPattern, aSites) {
|
||||
|
||||
let shouldBePinned = /p$/.test(id);
|
||||
let cellContainsPinned = site.isPinned();
|
||||
let cssClassPinned = site.node && site.node.hasAttribute("pinned");
|
||||
let cssClassPinned = site.node && site.node.querySelector(".newtab-control-pin").hasAttribute("pinned");
|
||||
|
||||
// Check if the site should be and is pinned.
|
||||
if (shouldBePinned) {
|
||||
@ -270,10 +270,15 @@ function simulateDrop(aDropTarget, aDragSource) {
|
||||
* Resumes testing when all pages have been updated.
|
||||
*/
|
||||
function whenPagesUpdated() {
|
||||
NewTabUtils.allPages.register({
|
||||
let page = {
|
||||
update: function () {
|
||||
NewTabUtils.allPages.unregister(this);
|
||||
executeSoon(TestRunner.next);
|
||||
}
|
||||
};
|
||||
|
||||
NewTabUtils.allPages.register(page);
|
||||
registerCleanupFunction(function () {
|
||||
NewTabUtils.allPages.unregister(page);
|
||||
});
|
||||
}
|
||||
|
@ -44,7 +44,23 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
|
||||
return Services.prefs.getCharPref("browser.newtab.url") || "about:blank";
|
||||
const PREF = "browser.newtab.url";
|
||||
|
||||
function getNewTabPageURL() {
|
||||
return Services.prefs.getCharPref(PREF) || "about:blank";
|
||||
}
|
||||
|
||||
function update() {
|
||||
BROWSER_NEW_TAB_URL = getNewTabPageURL();
|
||||
}
|
||||
|
||||
Services.prefs.addObserver(PREF, update, false);
|
||||
addEventListener("unload", function onUnload() {
|
||||
removeEventListener("unload", onUnload);
|
||||
Services.prefs.removeObserver(PREF, update);
|
||||
});
|
||||
|
||||
return getNewTabPageURL();
|
||||
});
|
||||
|
||||
var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
|
||||
|
@ -18,7 +18,7 @@ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
* Hint: This is the default value because the 'New Tab Page' is the only
|
||||
* client for now.
|
||||
*/
|
||||
const THUMBNAIL_WIDTH = 201;
|
||||
const THUMBNAIL_WIDTH = 400;
|
||||
|
||||
/**
|
||||
* The default height for page thumbnails.
|
||||
@ -26,7 +26,7 @@ const THUMBNAIL_WIDTH = 201;
|
||||
* Hint: This is the default value because the 'New Tab Page' is the only
|
||||
* client for now.
|
||||
*/
|
||||
const THUMBNAIL_HEIGHT = 127;
|
||||
const THUMBNAIL_HEIGHT = 225;
|
||||
|
||||
/**
|
||||
* The default background color for page thumbnails.
|
||||
|
@ -1,6 +1,2 @@
|
||||
<!-- These strings are used in the about:newtab page -->
|
||||
<!ENTITY newtab.pageTitle "New Tab">
|
||||
|
||||
<!ENTITY newtab.show "Show the New Tab Page">
|
||||
<!ENTITY newtab.hide "Hide the New Tab Page">
|
||||
<!ENTITY newtab.reset "Reset the New Tab Page">
|
||||
|
@ -1,3 +1,5 @@
|
||||
newtab.pin=Pin this site at its current position
|
||||
newtab.unpin=Unpin this site
|
||||
newtab.block=Remove this site
|
||||
newtab.show=Show the new tab page
|
||||
newtab.hide=Hide the new tab page
|
||||
|
@ -44,8 +44,8 @@ browser.jar:
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/strip.png (newtab/strip.png)
|
||||
skin/classic/browser/newtab/toolbar.png (newtab/toolbar.png)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/newtab/noise.png (newtab/noise.png)
|
||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||
skin/classic/browser/places/calendar.png (places/calendar.png)
|
||||
|
BIN
browser/themes/gnomestripe/newtab/controls.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
@ -1,148 +1,131 @@
|
||||
#scrollbox {
|
||||
padding-bottom: 18px;
|
||||
background-color: #fff;
|
||||
:root {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#body {
|
||||
padding-top: 106px;
|
||||
font-family: sans-serif;
|
||||
/* SCROLLBOX */
|
||||
#newtab-scrollbox:not([page-disabled]) {
|
||||
background-color: rgb(229,229,229);
|
||||
background-image: url(chrome://browser/skin/newtab/noise.png),
|
||||
-moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.button {
|
||||
/* TOGGLE */
|
||||
#newtab-toggle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
border: 0 none;
|
||||
border: none;
|
||||
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
/* TOOLBAR */
|
||||
#toolbar {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 13px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
#newtab-toggle[page-disabled] {
|
||||
background-position: -232px 0;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
background: transparent url(chrome://browser/skin/newtab/toolbar.png);
|
||||
/* ROWS */
|
||||
.newtab-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#toolbar-button-show {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background-position: -10px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-show:hover {
|
||||
background-position: -10px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-show:active {
|
||||
background-position: -10px -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:hover {
|
||||
background-position: 0 -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:active {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
top: 17px;
|
||||
width: 11px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
background-position: -21px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:hover {
|
||||
background-position: -21px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:active {
|
||||
background-position: -21px -24px;
|
||||
}
|
||||
|
||||
/* GRID */
|
||||
#grid {
|
||||
padding: 1px;
|
||||
margin: 0 auto;
|
||||
.newtab-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
.newtab-cell {
|
||||
-moz-margin-end: 20px;
|
||||
background-color: rgba(255,255,255,.2);
|
||||
border: 1px solid;
|
||||
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
|
||||
border-radius: 1px;
|
||||
-moz-transition: border-color 100ms ease-out;
|
||||
}
|
||||
|
||||
.newtab-cell:empty {
|
||||
border: 1px dashed;
|
||||
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
|
||||
}
|
||||
|
||||
.newtab-cell:last-child {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.newtab-cell:hover:not(:empty) {
|
||||
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
-moz-transition: 200ms ease-out;
|
||||
-moz-transition-property: top, left, box-shadow, opacity;
|
||||
}
|
||||
|
||||
.site[dragged] {
|
||||
-moz-transition-property: box-shadow;
|
||||
}
|
||||
|
||||
.site[ontop] {
|
||||
box-shadow: 0 1px 4px #000;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* SITE TITLE */
|
||||
.site-title {
|
||||
height: 2.4em;
|
||||
width: 189px;
|
||||
padding: 0 6px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
border: solid transparent;
|
||||
border-width: 6px 0;
|
||||
color: #fff;
|
||||
.newtab-site {
|
||||
text-decoration: none;
|
||||
line-height: 1.2em;
|
||||
font-weight: 700;
|
||||
-moz-transition-property: top, left, opacity, box-shadow, background-color;
|
||||
}
|
||||
|
||||
/* SITE STRIP */
|
||||
.site-strip {
|
||||
padding: 4px 3px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
.newtab-site:hover,
|
||||
.newtab-site[dragged] {
|
||||
box-shadow: 0 0 10px rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
.strip-button {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: transparent url(chrome://browser/skin/newtab/strip.png);
|
||||
.newtab-site[dragged] {
|
||||
-moz-transition-property: box-shadow, background-color;
|
||||
background-color: rgb(242,242,242);
|
||||
}
|
||||
|
||||
.strip-button-pin:hover {
|
||||
background-position: 0 -17px;
|
||||
/* THUMBNAILS */
|
||||
.newtab-thumbnail {
|
||||
background-origin: padding-box;
|
||||
background-clip: padding-box;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.strip-button-pin:active,
|
||||
.site[pinned] .strip-button-pin {
|
||||
background-position: 0 -34px;
|
||||
/* TITLES */
|
||||
.newtab-title {
|
||||
padding: 0 8px;
|
||||
background-color: rgba(248,249,251,.95);
|
||||
color: #1f364c;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.strip-button-block {
|
||||
background-position: -17px 0;
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 1px 2px 3px;
|
||||
border: none;
|
||||
background: transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
.strip-button-block:hover {
|
||||
background-position: -17px -17px;
|
||||
.newtab-control-pin:hover {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
.strip-button-block:active {
|
||||
background-position: -17px -34px;
|
||||
.newtab-control-pin:active {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned] {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:hover {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:active {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:hover {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:active {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
BIN
browser/themes/gnomestripe/newtab/noise.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -54,8 +54,8 @@ browser.jar:
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/strip.png (newtab/strip.png)
|
||||
skin/classic/browser/newtab/toolbar.png (newtab/toolbar.png)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/newtab/noise.png (newtab/noise.png)
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/monitor.png
|
||||
skin/classic/browser/monitor_16-10.png
|
||||
|
BIN
browser/themes/pinstripe/newtab/controls.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
@ -1,147 +1,131 @@
|
||||
#scrollbox {
|
||||
padding-bottom: 18px;
|
||||
background-color: #fff;
|
||||
:root {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#body {
|
||||
padding-top: 106px;
|
||||
font-family: sans-serif;
|
||||
/* SCROLLBOX */
|
||||
#newtab-scrollbox:not([page-disabled]) {
|
||||
background-color: rgb(229,229,229);
|
||||
background-image: url(chrome://browser/skin/newtab/noise.png),
|
||||
-moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.button {
|
||||
/* TOGGLE */
|
||||
#newtab-toggle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
border: 0 none;
|
||||
border: none;
|
||||
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
/* TOOLBAR */
|
||||
#toolbar {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 13px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
#newtab-toggle[page-disabled] {
|
||||
background-position: -232px 0;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
background: transparent url(chrome://browser/skin/newtab/toolbar.png);
|
||||
/* ROWS */
|
||||
.newtab-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#toolbar-button-show {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background-position: -10px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-show:hover {
|
||||
background-position: -10px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-show:active {
|
||||
background-position: -10px -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:hover {
|
||||
background-position: 0 -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:active {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
top: 17px;
|
||||
width: 11px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
background-position: -21px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:hover {
|
||||
background-position: -21px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:active {
|
||||
background-position: -21px -24px;
|
||||
}
|
||||
|
||||
/* GRID */
|
||||
#grid {
|
||||
padding: 1px;
|
||||
margin: 0 auto;
|
||||
.newtab-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
.newtab-cell {
|
||||
-moz-margin-end: 20px;
|
||||
background-color: rgba(255,255,255,.2);
|
||||
border: 1px solid;
|
||||
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
|
||||
border-radius: 1px;
|
||||
-moz-transition: border-color 100ms ease-out;
|
||||
}
|
||||
|
||||
.newtab-cell:empty {
|
||||
border: 1px dashed;
|
||||
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
|
||||
}
|
||||
|
||||
.newtab-cell:last-child {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.newtab-cell:hover:not(:empty) {
|
||||
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
-moz-transition: 200ms ease-out;
|
||||
-moz-transition-property: top, left, box-shadow, opacity;
|
||||
}
|
||||
|
||||
.site[dragged] {
|
||||
-moz-transition-property: box-shadow;
|
||||
}
|
||||
|
||||
.site[ontop] {
|
||||
box-shadow: 0 1px 4px #000;
|
||||
}
|
||||
|
||||
/* SITE TITLE */
|
||||
.site-title {
|
||||
height: 2.4em;
|
||||
width: 189px;
|
||||
padding: 0 6px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
border: solid transparent;
|
||||
border-width: 6px 0;
|
||||
color: #fff;
|
||||
.newtab-site {
|
||||
text-decoration: none;
|
||||
line-height: 1.2em;
|
||||
font-weight: 700;
|
||||
-moz-transition-property: top, left, opacity, box-shadow, background-color;
|
||||
}
|
||||
|
||||
/* SITE STRIP */
|
||||
.site-strip {
|
||||
padding: 4px 3px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
.newtab-site:hover,
|
||||
.newtab-site[dragged] {
|
||||
box-shadow: 0 0 10px rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
.strip-button {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: transparent url(chrome://browser/skin/newtab/strip.png);
|
||||
.newtab-site[dragged] {
|
||||
-moz-transition-property: box-shadow, background-color;
|
||||
background-color: rgb(242,242,242);
|
||||
}
|
||||
|
||||
.strip-button-pin:hover {
|
||||
background-position: 0 -17px;
|
||||
/* THUMBNAILS */
|
||||
.newtab-thumbnail {
|
||||
background-origin: padding-box;
|
||||
background-clip: padding-box;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.strip-button-pin:active,
|
||||
.site[pinned] .strip-button-pin {
|
||||
background-position: 0 -34px;
|
||||
/* TITLES */
|
||||
.newtab-title {
|
||||
padding: 0 8px;
|
||||
background-color: rgba(248,249,251,.95);
|
||||
color: #1f364c;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.strip-button-block {
|
||||
background-position: -17px 0;
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 1px 2px 3px;
|
||||
border: none;
|
||||
background: transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
.strip-button-block:hover {
|
||||
background-position: -17px -17px;
|
||||
.newtab-control-pin:hover {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
.strip-button-block:active {
|
||||
background-position: -17px -34px;
|
||||
.newtab-control-pin:active {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned] {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:hover {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:active {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:hover {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:active {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
BIN
browser/themes/pinstripe/newtab/noise.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -59,8 +59,8 @@ browser.jar:
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/strip.png (newtab/strip.png)
|
||||
skin/classic/browser/newtab/toolbar.png (newtab/toolbar.png)
|
||||
skin/classic/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/browser/newtab/noise.png (newtab/noise.png)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
skin/classic/browser/places/bookmark.png (places/bookmark.png)
|
||||
@ -231,8 +231,8 @@ browser.jar:
|
||||
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/aero/browser/newtab/strip.png (newtab/strip.png)
|
||||
skin/classic/aero/browser/newtab/toolbar.png (newtab/toolbar.png)
|
||||
skin/classic/aero/browser/newtab/controls.png (newtab/controls.png)
|
||||
skin/classic/aero/browser/newtab/noise.png (newtab/noise.png)
|
||||
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
|
||||
* skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css)
|
||||
skin/classic/aero/browser/places/bookmark.png (places/bookmark.png)
|
||||
|
BIN
browser/themes/winstripe/newtab/controls.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
@ -1,148 +1,131 @@
|
||||
#scrollbox {
|
||||
padding-bottom: 18px;
|
||||
background-color: #fff;
|
||||
:root {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#body {
|
||||
padding-top: 106px;
|
||||
font-family: sans-serif;
|
||||
/* SCROLLBOX */
|
||||
#newtab-scrollbox:not([page-disabled]) {
|
||||
background-color: rgb(229,229,229);
|
||||
background-image: url(chrome://browser/skin/newtab/noise.png),
|
||||
-moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.button {
|
||||
/* TOGGLE */
|
||||
#newtab-toggle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
border: 0 none;
|
||||
border: none;
|
||||
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
/* TOOLBAR */
|
||||
#toolbar {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 13px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
#newtab-toggle[page-disabled] {
|
||||
background-position: -232px 0;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
background: transparent url(chrome://browser/skin/newtab/toolbar.png);
|
||||
/* ROWS */
|
||||
.newtab-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#toolbar-button-show {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background-position: -10px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-show:hover {
|
||||
background-position: -10px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-show:active {
|
||||
background-position: -10px -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:hover {
|
||||
background-position: 0 -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-hide:active {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
top: 17px;
|
||||
width: 11px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset {
|
||||
background-position: -21px 0;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:hover {
|
||||
background-position: -21px -12px;
|
||||
}
|
||||
|
||||
#toolbar-button-reset:active {
|
||||
background-position: -21px -24px;
|
||||
}
|
||||
|
||||
/* GRID */
|
||||
#grid {
|
||||
padding: 1px;
|
||||
margin: 0 auto;
|
||||
.newtab-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
.newtab-cell {
|
||||
-moz-margin-end: 20px;
|
||||
background-color: rgba(255,255,255,.2);
|
||||
border: 1px solid;
|
||||
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
|
||||
border-radius: 1px;
|
||||
-moz-transition: border-color 100ms ease-out;
|
||||
}
|
||||
|
||||
.newtab-cell:empty {
|
||||
border: 1px dashed;
|
||||
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
|
||||
}
|
||||
|
||||
.newtab-cell:last-child {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.newtab-cell:hover:not(:empty) {
|
||||
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
-moz-transition: 200ms ease-out;
|
||||
-moz-transition-property: top, left, box-shadow, opacity;
|
||||
}
|
||||
|
||||
.site[dragged] {
|
||||
-moz-transition-property: box-shadow;
|
||||
}
|
||||
|
||||
.site[ontop] {
|
||||
box-shadow: 0 1px 4px #000;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* SITE TITLE */
|
||||
.site-title {
|
||||
height: 2.4em;
|
||||
width: 189px;
|
||||
padding: 0 6px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
border: solid transparent;
|
||||
border-width: 6px 0;
|
||||
color: #fff;
|
||||
.newtab-site {
|
||||
text-decoration: none;
|
||||
line-height: 1.2em;
|
||||
font-weight: 700;
|
||||
-moz-transition-property: top, left, opacity, box-shadow, background-color;
|
||||
}
|
||||
|
||||
/* SITE STRIP */
|
||||
.site-strip {
|
||||
padding: 4px 3px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
.newtab-site:hover,
|
||||
.newtab-site[dragged] {
|
||||
box-shadow: 0 0 10px rgba(8,22,37,.3);
|
||||
}
|
||||
|
||||
.strip-button {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: transparent url(chrome://browser/skin/newtab/strip.png);
|
||||
.newtab-site[dragged] {
|
||||
-moz-transition-property: box-shadow, background-color;
|
||||
background-color: rgb(242,242,242);
|
||||
}
|
||||
|
||||
.strip-button-pin:hover {
|
||||
background-position: 0 -17px;
|
||||
/* THUMBNAILS */
|
||||
.newtab-thumbnail {
|
||||
background-origin: padding-box;
|
||||
background-clip: padding-box;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.strip-button-pin:active,
|
||||
.site[pinned] .strip-button-pin {
|
||||
background-position: 0 -34px;
|
||||
/* TITLES */
|
||||
.newtab-title {
|
||||
padding: 0 8px;
|
||||
background-color: rgba(248,249,251,.95);
|
||||
color: #1f364c;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.strip-button-block {
|
||||
background-position: -17px 0;
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 1px 2px 3px;
|
||||
border: none;
|
||||
background: transparent url(chrome://browser/skin/newtab/controls.png);
|
||||
}
|
||||
|
||||
.strip-button-block:hover {
|
||||
background-position: -17px -17px;
|
||||
.newtab-control-pin:hover {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
.strip-button-block:active {
|
||||
background-position: -17px -34px;
|
||||
.newtab-control-pin:active {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned] {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:hover {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
.newtab-control-pin[pinned]:active {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:hover {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
.newtab-control-block:active {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
BIN
browser/themes/winstripe/newtab/noise.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.7 KiB |
@ -1261,8 +1261,11 @@
|
||||
let videoHeight = this.video.clientHeight;
|
||||
let videoWidth = this.video.clientWidth;
|
||||
|
||||
if (this._overlayPlayButtonHeight > videoHeight || this._overlayPlayButtonWidth > videoWidth)
|
||||
if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight ||
|
||||
this._overlayPlayButtonWidth > videoWidth)
|
||||
this.clickToPlay.hidden = true;
|
||||
else if (this.clickToPlay.hidden)
|
||||
this.clickToPlay.hidden = false;
|
||||
|
||||
// The scrubber has |flex=1|, therefore |minScrubberWidth|
|
||||
// was generated by empirical testing.
|
||||
|
@ -205,17 +205,20 @@ ThreadActor.prototype = {
|
||||
|
||||
onClientEvaluate: function TA_onClientEvaluate(aRequest) {
|
||||
if (this.state !== "paused") {
|
||||
return { type: "wrongState",
|
||||
return { error: "wrongState",
|
||||
message: "Debuggee must be paused to evaluate code." };
|
||||
};
|
||||
|
||||
let frame = this._requestFrame(aRequest.frame);
|
||||
if (!frame) {
|
||||
// XXXspec
|
||||
return { type: "unknownFrame",
|
||||
return { error: "unknownFrame",
|
||||
message: "Evaluation frame not found" };
|
||||
}
|
||||
|
||||
if (!frame.environment) {
|
||||
return { error: "notDebuggee",
|
||||
message: "cannot access the environment of this frame." };
|
||||
};
|
||||
|
||||
// We'll clobber the youngest frame if the eval causes a pause, so
|
||||
// save our frame now to be restored after eval returns.
|
||||
@ -233,18 +236,10 @@ ThreadActor.prototype = {
|
||||
|
||||
// Put ourselves back in the pause state.
|
||||
let packet = this._paused(youngest);
|
||||
packet.why = { type: "clientEvaluated" };
|
||||
if ("return" in completion) {
|
||||
packet.why.value = this.createValueGrip(completion["return"]);
|
||||
} else if ("throw" in completion) {
|
||||
packet.why.exception = this.createValueGrip(completion["throw"]);
|
||||
} else {
|
||||
// XXXspec
|
||||
packet.why.terminated = true;
|
||||
}
|
||||
packet.why = { type: "clientEvaluated",
|
||||
frameFinished: this.createProtocolCompletionValue(completion) };
|
||||
|
||||
// Return back to our previous pause's event loop.
|
||||
|
||||
return packet;
|
||||
},
|
||||
|
||||
@ -269,9 +264,9 @@ ThreadActor.prototype = {
|
||||
// frames if count is not defined.
|
||||
let frames = [];
|
||||
for (; frame && (!count || i < (start + count)); i++) {
|
||||
let grip = this._createFrameActor(frame).grip();
|
||||
grip.depth = i;
|
||||
frames.push(grip);
|
||||
let form = this._createFrameActor(frame).form();
|
||||
form.depth = i;
|
||||
frames.push(form);
|
||||
frame = frame.older;
|
||||
}
|
||||
|
||||
@ -279,6 +274,11 @@ ThreadActor.prototype = {
|
||||
},
|
||||
|
||||
onReleaseMany: function TA_onReleaseMany(aRequest) {
|
||||
if (!aRequest.actors) {
|
||||
return { error: "missingParameter",
|
||||
message: "no actors were specified" };
|
||||
}
|
||||
|
||||
for each (let actorID in aRequest.actors) {
|
||||
let actor = this.threadLifetimePool.get(actorID);
|
||||
this.threadLifetimePool.objectActors.delete(actor.obj);
|
||||
@ -449,8 +449,6 @@ ThreadActor.prototype = {
|
||||
* Return the Debug.Frame for a frame mentioned by the protocol.
|
||||
*/
|
||||
_requestFrame: function TA_requestFrame(aFrameID) {
|
||||
// XXXspec: doesn't actually specify how frames are named. By
|
||||
// depth? By actor? Both?
|
||||
if (!aFrameID) {
|
||||
return this._youngestFrame;
|
||||
}
|
||||
@ -463,10 +461,9 @@ ThreadActor.prototype = {
|
||||
},
|
||||
|
||||
_paused: function TA_paused(aFrame) {
|
||||
// XXX: We don't handle nested pauses correctly. Don't try - if we're
|
||||
// We don't handle nested pauses correctly. Don't try - if we're
|
||||
// paused, just continue running whatever code triggered the pause.
|
||||
|
||||
// We don't want to actually have nested pauses (although we will
|
||||
// We don't want to actually have nested pauses (although we
|
||||
// have nested event loops). If code runs in the debuggee during
|
||||
// a pause, it should cause the actor to resume (dropping
|
||||
// pause-lifetime actors etc) and then repause when complete.
|
||||
@ -504,7 +501,7 @@ ThreadActor.prototype = {
|
||||
type: "paused",
|
||||
actor: this._pauseActor.actorID };
|
||||
if (aFrame) {
|
||||
packet.frame = this._createFrameActor(aFrame).grip();
|
||||
packet.frame = this._createFrameActor(aFrame).form();
|
||||
}
|
||||
|
||||
if (poppedFrames) {
|
||||
@ -598,13 +595,11 @@ ThreadActor.prototype = {
|
||||
* The object whose lexical environment we want to extract.
|
||||
* @param object aPool
|
||||
* The pool where the newly-created actor will be placed.
|
||||
* @return The EnvironmentActor for aObject.
|
||||
* @return The EnvironmentActor for aObject or undefined for host functions or
|
||||
* functions scoped to a non-debuggee global.
|
||||
*/
|
||||
createEnvironmentActor: function TA_createEnvironmentActor(aObject, aPool) {
|
||||
let environment = aObject.environment;
|
||||
// XXX: need to spec this: when the object is a function proxy or not a
|
||||
// function implemented in JavaScript, we don't return a scope property at
|
||||
// all.
|
||||
if (!environment) {
|
||||
return undefined;
|
||||
}
|
||||
@ -647,6 +642,25 @@ ThreadActor.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a protocol completion value representing the given
|
||||
* Debugger-provided completion value.
|
||||
*/
|
||||
createProtocolCompletionValue:
|
||||
function TA_createProtocolCompletionValue(aCompletion) {
|
||||
let protoValue = {};
|
||||
if ("return" in aCompletion) {
|
||||
protoValue.return = this.createValueGrip(aCompletion.return);
|
||||
} else if ("yield" in aCompletion) {
|
||||
protoValue.return = this.createValueGrip(aCompletion.yield);
|
||||
} else if ("throw" in aCompletion) {
|
||||
protoValue.throw = this.createValueGrip(aCompletion.throw);
|
||||
} else {
|
||||
protoValue.terminated = true;
|
||||
}
|
||||
return protoValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a grip for the given debuggee object.
|
||||
*
|
||||
@ -746,9 +760,7 @@ ThreadActor.prototype = {
|
||||
*/
|
||||
onNewScript: function TA_onNewScript(aScript, aFunction) {
|
||||
// Use a sparse array for storing the scripts for each URL in order to
|
||||
// optimize retrieval. XXX: in case this is not fast enough for very large
|
||||
// files with too many scripts, we could sort the hash of script locations
|
||||
// or use a trie.
|
||||
// optimize retrieval.
|
||||
if (!this._scripts[aScript.url]) {
|
||||
this._scripts[aScript.url] = [];
|
||||
}
|
||||
@ -819,7 +831,7 @@ ObjectActor.prototype = {
|
||||
*/
|
||||
grip: function OA_grip() {
|
||||
return { "type": "object",
|
||||
"class": this.obj["class"],
|
||||
"class": this.obj.class,
|
||||
"actor": this.actorID };
|
||||
},
|
||||
|
||||
@ -902,9 +914,8 @@ ObjectActor.prototype = {
|
||||
if (this.threadActor.state !== "paused") {
|
||||
return this.WRONG_STATE_RESPONSE;
|
||||
}
|
||||
// XXX: spec this.
|
||||
if (!aRequest.name) {
|
||||
return { error: "noPropertyName",
|
||||
return { error: "missingParameter",
|
||||
message: "no property name was specified" };
|
||||
}
|
||||
|
||||
@ -945,9 +956,8 @@ ObjectActor.prototype = {
|
||||
return this.WRONG_STATE_RESPONSE;
|
||||
}
|
||||
|
||||
if (this.obj["class"] !== "Function") {
|
||||
// XXXspec: Error type for this.
|
||||
return { error: "unrecognizedPacketType",
|
||||
if (this.obj.class !== "Function") {
|
||||
return { error: "objectNotFunction",
|
||||
message: "decompile request is only valid for object grips " +
|
||||
"with a 'Function' class." };
|
||||
}
|
||||
@ -967,18 +977,21 @@ ObjectActor.prototype = {
|
||||
return this.WRONG_STATE_RESPONSE;
|
||||
}
|
||||
|
||||
if (this.obj["class"] !== "Function") {
|
||||
// XXXspec: Error type for this.
|
||||
return { error: "unrecognizedPacketType",
|
||||
if (this.obj.class !== "Function") {
|
||||
return { error: "objectNotFunction",
|
||||
message: "scope request is only valid for object grips with a" +
|
||||
" 'Function' class." };
|
||||
}
|
||||
|
||||
let packet = { name: this.obj.name || null };
|
||||
let envActor = this.threadActor.createEnvironmentActor(this.obj, this.registeredPool);
|
||||
packet.scope = envActor ? envActor.grip() : envActor;
|
||||
let envActor = this.threadActor.createEnvironmentActor(this.obj,
|
||||
this.registeredPool);
|
||||
if (!envActor) {
|
||||
return { error: "notDebuggee",
|
||||
message: "cannot access the environment of this function." };
|
||||
}
|
||||
|
||||
return packet;
|
||||
return { name: this.obj.name || null,
|
||||
scope: envActor.form() };
|
||||
},
|
||||
|
||||
/**
|
||||
@ -992,10 +1005,10 @@ ObjectActor.prototype = {
|
||||
return this.WRONG_STATE_RESPONSE;
|
||||
}
|
||||
|
||||
if (this.obj["class"] !== "Function") {
|
||||
// XXXspec: Error type for this.
|
||||
return { error: "unrecognizedPacketType",
|
||||
message: "nameAndParameters request is only valid for object grips with a 'Function' class." };
|
||||
if (this.obj.class !== "Function") {
|
||||
return { error: "objectNotFunction",
|
||||
message: "nameAndParameters request is only valid for object " +
|
||||
"grips with a 'Function' class." };
|
||||
}
|
||||
|
||||
return { name: this.obj.name || null,
|
||||
@ -1028,9 +1041,8 @@ ObjectActor.prototype = {
|
||||
return this.WRONG_STATE_RESPONSE;
|
||||
}
|
||||
if (this.registeredPool !== this.threadActor.threadLifetimePool) {
|
||||
// XXXspec: error type?
|
||||
return { error: "unrecognizedPacketType",
|
||||
message: "release is only recognized on thread-lifetime actors." };
|
||||
return { error: "notReleasable",
|
||||
message: "only thread-lifetime actors can be released." };
|
||||
}
|
||||
|
||||
this.release();
|
||||
@ -1090,19 +1102,19 @@ FrameActor.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a grip for this actor for returning in a protocol message.
|
||||
* Returns a frame form for use in a protocol message.
|
||||
*/
|
||||
grip: function FA_grip() {
|
||||
let grip = { actor: this.actorID,
|
||||
form: function FA_form() {
|
||||
let form = { actor: this.actorID,
|
||||
type: this.frame.type };
|
||||
if (this.frame.type === "call") {
|
||||
grip.callee = this.threadActor.createValueGrip(this.frame.callee);
|
||||
form.callee = this.threadActor.createValueGrip(this.frame.callee);
|
||||
if (this.frame.callee.name) {
|
||||
grip.calleeName = this.frame.callee.name;
|
||||
form.calleeName = this.frame.callee.name;
|
||||
} else {
|
||||
let desc = this.frame.callee.getOwnPropertyDescriptor("displayName");
|
||||
if (desc && desc.value && typeof desc.value == "string") {
|
||||
grip.calleeName = desc.value;
|
||||
form.calleeName = desc.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1110,28 +1122,28 @@ FrameActor.prototype = {
|
||||
let envActor = this.threadActor
|
||||
.createEnvironmentActor(this.frame,
|
||||
this.frameLifetimePool);
|
||||
grip.environment = envActor ? envActor.grip() : envActor;
|
||||
grip["this"] = this.threadActor.createValueGrip(this.frame["this"]);
|
||||
grip.arguments = this._args();
|
||||
form.environment = envActor ? envActor.form() : envActor;
|
||||
form.this = this.threadActor.createValueGrip(this.frame.this);
|
||||
form.arguments = this._args();
|
||||
if (this.frame.script) {
|
||||
grip.where = { url: this.frame.script.url,
|
||||
form.where = { url: this.frame.script.url,
|
||||
line: this.frame.script.getOffsetLine(this.frame.offset) };
|
||||
}
|
||||
|
||||
if (!this.frame.older) {
|
||||
grip.oldest = true;
|
||||
form.oldest = true;
|
||||
}
|
||||
|
||||
return grip;
|
||||
return form;
|
||||
},
|
||||
|
||||
_args: function FA__args() {
|
||||
if (!this.frame["arguments"]) {
|
||||
if (!this.frame.arguments) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [this.threadActor.createValueGrip(arg)
|
||||
for each (arg in this.frame["arguments"])];
|
||||
for each (arg in this.frame.arguments)];
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1232,9 +1244,9 @@ EnvironmentActor.prototype = {
|
||||
actorPrefix: "environment",
|
||||
|
||||
/**
|
||||
* Returns a grip for this actor for returning in a protocol message.
|
||||
* Returns an environment form for use in a protocol message.
|
||||
*/
|
||||
grip: function EA_grip() {
|
||||
form: function EA_form() {
|
||||
// Debugger.Frame might be dead by the time we get here, which will cause
|
||||
// accessing its properties to throw.
|
||||
if (!this.obj.live) {
|
||||
@ -1247,25 +1259,29 @@ EnvironmentActor.prototype = {
|
||||
.createEnvironmentActor(this.obj.environment.parent,
|
||||
this.registeredPool);
|
||||
}
|
||||
let grip = { actor: this.actorID,
|
||||
parent: parent ? parent.grip() : parent };
|
||||
let form = { actor: this.actorID,
|
||||
parent: parent ? parent.form() : parent };
|
||||
|
||||
if (this.obj.environment.type == "object") {
|
||||
grip.type = "object"; // XXX: how can we tell if it's "with"?
|
||||
grip.object = this.threadActor.createValueGrip(this.obj.environment.object);
|
||||
} else {
|
||||
if (this.obj["class"] == "Function") {
|
||||
grip.type = "function";
|
||||
grip["function"] = this.threadActor.createValueGrip(this.obj);
|
||||
grip.functionName = this.obj.name;
|
||||
if (this.obj.environment.parent) {
|
||||
form.type = "with";
|
||||
} else {
|
||||
grip.type = "block";
|
||||
form.type = "object";
|
||||
}
|
||||
form.object = this.threadActor.createValueGrip(this.obj.environment.object);
|
||||
} else {
|
||||
if (this.obj.class == "Function") {
|
||||
form.type = "function";
|
||||
form.function = this.threadActor.createValueGrip(this.obj);
|
||||
form.functionName = this.obj.name;
|
||||
} else {
|
||||
form.type = "block";
|
||||
}
|
||||
|
||||
grip.bindings = this._bindings();
|
||||
form.bindings = this._bindings();
|
||||
}
|
||||
|
||||
return grip;
|
||||
return form;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1273,21 +1289,51 @@ EnvironmentActor.prototype = {
|
||||
* specification.
|
||||
*/
|
||||
_bindings: function EA_bindings() {
|
||||
let bindings = { mutable: {}, immutable: {} };
|
||||
let bindings = { arguments: [], variables: {} };
|
||||
|
||||
// TODO: this will be redundant after bug 692984 is fixed.
|
||||
if (typeof this.obj.environment.getVariableDescriptor != "function") {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
for (let name in this.obj.environment.names()) {
|
||||
for (let name in this.obj.parameterNames) {
|
||||
let arg = {};
|
||||
let desc = this.obj.environment.getVariableDescriptor(name);
|
||||
// XXX: the spec doesn't say what to do with accessor properties.
|
||||
if (desc.writable) {
|
||||
grip.bindings.mutable[name] = desc.value;
|
||||
let descForm = {
|
||||
enumerable: true,
|
||||
configurable: desc.configurable
|
||||
};
|
||||
if ("value" in desc) {
|
||||
descForm.value = this.threadActor.createValueGrip(desc.value);
|
||||
descForm.writable = desc.writable;
|
||||
} else {
|
||||
grip.bindings.immutable[name] = desc.value;
|
||||
descForm.get = this.threadActor.createValueGrip(desc.get);
|
||||
descForm.set = this.threadActor.createValueGrip(desc.set);
|
||||
}
|
||||
arg[name] = descForm;
|
||||
bindings.arguments.push(arg);
|
||||
}
|
||||
|
||||
for (let name in this.obj.environment.names()) {
|
||||
if (bindings.arguments.some(function exists(element) {
|
||||
return !!element[name];
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let desc = this.obj.environment.getVariableDescriptor(name);
|
||||
let descForm = {
|
||||
enumerable: true,
|
||||
configurable: desc.configurable
|
||||
};
|
||||
if ("value" in desc) {
|
||||
descForm.value = this.threadActor.createValueGrip(desc.value);
|
||||
descForm.writable = desc.writable;
|
||||
} else {
|
||||
descForm.get = this.threadActor.createValueGrip(desc.get);
|
||||
descForm.set = this.threadActor.createValueGrip(desc.set);
|
||||
}
|
||||
bindings.variables[name] = descForm;
|
||||
}
|
||||
|
||||
return bindings;
|
||||
@ -1313,9 +1359,9 @@ EnvironmentActor.prototype = {
|
||||
this.obj.environment.setVariable(aRequest.name, aRequest.value);
|
||||
} catch (e) {
|
||||
if (e instanceof Debugger.DebuggeeWouldRun) {
|
||||
// XXX: we need to spec this. Is this a real problem?
|
||||
return { error: "debuggeeWouldRun",
|
||||
message: "Assigning this value would cause the debuggee to run." };
|
||||
return { error: "threadWouldRun",
|
||||
cause: e.cause ? e.cause : "setter",
|
||||
message: "Assigning a value would cause the debuggee to run" };
|
||||
}
|
||||
// This should never happen, so let it complain loudly if it does.
|
||||
throw e;
|
||||
|
@ -26,7 +26,7 @@ function run_test()
|
||||
function test_simple_eval()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let arg1Actor = aPacket.frame["arguments"][0].actor;
|
||||
let arg1Actor = aPacket.frame.arguments[0].actor;
|
||||
gThreadClient.eval(null, "({ obj: true })", function(aResponse) {
|
||||
do_check_eq(aResponse.type, "resumed");
|
||||
// Expect a pause notification immediately.
|
||||
@ -34,8 +34,8 @@ function test_simple_eval()
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.value.type, "object");
|
||||
do_check_eq(aPacket.why.value["class"], "Object");
|
||||
do_check_eq(aPacket.why.frameFinished.return.type, "object");
|
||||
do_check_eq(aPacket.why.frameFinished.return.class, "Object");
|
||||
|
||||
// Make sure the previous pause lifetime was correctly dropped.
|
||||
gClient.request({ to: arg1Actor, type: "bogusRequest" }, function(aResponse) {
|
||||
|
@ -33,7 +33,7 @@ function test_throw_eval()
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.exception, "failure");
|
||||
do_check_eq(aPacket.why.frameFinished.throw, "failure");
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
|
@ -33,8 +33,8 @@ function test_syntax_error_eval()
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.exception.type, "object");
|
||||
do_check_eq(aPacket.why.exception["class"], "Error");
|
||||
do_check_eq(aPacket.why.frameFinished.throw.type, "object");
|
||||
do_check_eq(aPacket.why.frameFinished.throw.class, "Error");
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
|
@ -38,14 +38,14 @@ function test_syntax_error_eval()
|
||||
// 'arg' should have been evaluated in frame0
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.value, "arg0");
|
||||
do_check_eq(aPacket.why.frameFinished.return, "arg0");
|
||||
|
||||
// Now eval against the second frame.
|
||||
gThreadClient.eval(frame1.actor, "arg", function(aResponse) {
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
// 'arg' should have been evaluated in frame1
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.value, "arg1");
|
||||
do_check_eq(aPacket.why.frameFinished.return, "arg1");
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
|
@ -34,7 +34,7 @@ function test_pause_frame()
|
||||
do_check_eq(args[3].type, "null");
|
||||
do_check_eq(args[4].type, "undefined");
|
||||
do_check_eq(args[5].type, "object");
|
||||
do_check_eq(args[5]["class"], "Object");
|
||||
do_check_eq(args[5].class, "Object");
|
||||
do_check_true(!!args[5].actor);
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_named_function()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Function");
|
||||
do_check_eq(args[0].class, "Function");
|
||||
// No name for an anonymous function.
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
@ -49,9 +49,9 @@ function test_named_function()
|
||||
|
||||
function test_anon_function() {
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Function");
|
||||
do_check_eq(args[0].class, "Function");
|
||||
// No name for an anonymous function.
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
|
@ -6,7 +6,7 @@ function run_test()
|
||||
var dbg = new Debugger();
|
||||
dbg.addDebuggee(g);
|
||||
dbg.onDebuggerStatement = function(aFrame) {
|
||||
let args = aFrame["arguments"];
|
||||
let args = aFrame.arguments;
|
||||
try {
|
||||
args[0];
|
||||
do_check_true(true);
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
objClient.getOwnPropertyNames(function(aResponse) {
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
objClient.getPrototype(function(aResponse) {
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
objClient.getProperty("x", function(aResponse) {
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
objClient.getPrototypeAndProperties(function(aResponse) {
|
||||
|
@ -26,7 +26,7 @@ function run_test()
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let pauseActor = aPacket["actor"];
|
||||
let pauseActor = aPacket.actor;
|
||||
|
||||
// Make a bogus request to the pause-liftime actor. Should get
|
||||
// unrecognized-packet-type (and not no-such-actor).
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
let objActor = args[0].actor;
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
do_check_true(!!objActor);
|
||||
|
||||
// Make a bogus request to the grip actor. Should get
|
||||
|
@ -26,9 +26,9 @@ function run_test()
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
let objActor = args[0].actor;
|
||||
do_check_eq(args[0]["class"], "Object");
|
||||
do_check_eq(args[0].class, "Object");
|
||||
do_check_true(!!objActor);
|
||||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
|
@ -27,7 +27,7 @@ function run_test()
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let args = aPacket.frame["arguments"];
|
||||
let args = aPacket.frame.arguments;
|
||||
let objActor1 = args[0].actor;
|
||||
|
||||
gThreadClient.getFrames(0, 1, function(aResponse) {
|
||||
|
@ -26,7 +26,7 @@ function run_test()
|
||||
function test_thread_lifetime()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let pauseGrip = aPacket.frame["arguments"][0];
|
||||
let pauseGrip = aPacket.frame.arguments[0];
|
||||
|
||||
gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
|
||||
let threadGrip = aResponse.threadGrip;
|
||||
|
@ -26,7 +26,7 @@ function run_test()
|
||||
function test_thread_lifetime()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let pauseGrip = aPacket.frame["arguments"][0];
|
||||
let pauseGrip = aPacket.frame.arguments[0];
|
||||
|
||||
gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
|
||||
let threadGrip = aResponse.threadGrip;
|
||||
|
@ -27,7 +27,7 @@ function test_thread_lifetime()
|
||||
{
|
||||
// Get three thread-lifetime grips.
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
aPacket.frame["arguments"][0];
|
||||
aPacket.frame.arguments[0];
|
||||
let grips = [];
|
||||
|
||||
let handler = function(aResponse) {
|
||||
@ -37,7 +37,7 @@ function test_thread_lifetime()
|
||||
}
|
||||
};
|
||||
for (let i = 0; i < 3; i++) {
|
||||
gClient.request({ to: aPacket.frame["arguments"][i].actor, type: "threadGrip" },
|
||||
gClient.request({ to: aPacket.frame.arguments[i].actor, type: "threadGrip" },
|
||||
handler);
|
||||
}
|
||||
});
|
||||
|