From db0eb77c876e28f4c204c493aba739ea6c7921ec Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 27 Jan 2012 11:22:35 +0100 Subject: [PATCH 01/24] Fix backout of bug 455553 --- browser/themes/gnomestripe/newtab/strip.png | Bin 2552 -> 0 bytes browser/themes/gnomestripe/newtab/toolbar.png | Bin 1538 -> 0 bytes browser/themes/pinstripe/newtab/strip.png | Bin 2552 -> 0 bytes browser/themes/pinstripe/newtab/toolbar.png | Bin 1568 -> 0 bytes browser/themes/winstripe/newtab/strip.png | Bin 2552 -> 0 bytes browser/themes/winstripe/newtab/toolbar.png | Bin 1704 -> 0 bytes 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 browser/themes/gnomestripe/newtab/strip.png delete mode 100644 browser/themes/gnomestripe/newtab/toolbar.png delete mode 100644 browser/themes/pinstripe/newtab/strip.png delete mode 100644 browser/themes/pinstripe/newtab/toolbar.png delete mode 100644 browser/themes/winstripe/newtab/strip.png delete mode 100644 browser/themes/winstripe/newtab/toolbar.png diff --git a/browser/themes/gnomestripe/newtab/strip.png b/browser/themes/gnomestripe/newtab/strip.png deleted file mode 100644 index 2527df6e72b5c80b91e180af9644ba96a5c148d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2552 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 O0000 diff --git a/browser/themes/gnomestripe/newtab/toolbar.png b/browser/themes/gnomestripe/newtab/toolbar.png deleted file mode 100644 index 389f689aa2a7611f53977594c048f79c4991affd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1538 zcmV+d2L1VoP)Px#32;bRa{vGf6951U69E94oEQKA1*b_wK~z}7z1Lk#Q)e8<@o%-;l_RE+GhM_8 z&Z*1|BRcVpq)WWhXf)~+B`Co`d;xW!BVJ5kIGwy`!52``xw)t_CD}4`B+G6vOo(iX zAqGoCN3E_gn~4eZ{GVOW9(rnfS}x{EPSW4gp8lWbJkL3wb8G-7F1F?XH@0n9?j>wH zak13_tlYL?d9&;MH5FH^6-f+R4E27QdCfxE%t1Hjgud28D1&Ros{egobxbpYV#=}Y0AAXL00f1L-Qw)uNwh`Y9|wOM7Q z)V<(H2a30@OAWQxG+pWdvcfxS4}H+}z%cM4?7J7iGXa2zm_})pm8kcEAJ>Q4zCQVF zhvZnhn2Xi>4U9?<^)J_ODIDUn61>d!d#@5u85OeinTZxkiFMTt=ypu9NW zD@w9O$-eU9{AwjaXb+w8SXqhWDG{YardQTBJ+7>6S_M#9+qAK=wrNO-JgKa0sxa2T zfs%rw(N52Sk^(PKoyc_`op*5&n|~4!mtEXE`XAO7=#phuy4ix%pPo8_VP(EA zv?37}=n?mUh@ASPuT%vBiCK{99hx`$$0F!Rb_R0{@H zr+9+j8*@CcI>ly{1q=%wu1+y5m~mw=wgqZ<#L@y4h?$%4Vc3=cp`LyyUVl%~6e1%q4Px1}`QRk89&91EtNyyNf|%pbL2urQ-h z>H2P^>qc>a!NLr$()Dbm>-z=^GpY&b7&~B?j+#fHG{)eRnN+ipU5|ahm@%v6-7$s&4BHjy75%@&p0~#$`crecvkJJUVE@5knNXS&TQiyE`w*{*cMf+@AV zu`NK?EiD+&^FTBU97q4`5YeMspdGpGK%&1FXh&{4eR~#o diff --git a/browser/themes/pinstripe/newtab/strip.png b/browser/themes/pinstripe/newtab/strip.png deleted file mode 100644 index 2527df6e72b5c80b91e180af9644ba96a5c148d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2552 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 O0000 diff --git a/browser/themes/pinstripe/newtab/toolbar.png b/browser/themes/pinstripe/newtab/toolbar.png deleted file mode 100644 index 75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1568 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 O0000 diff --git a/browser/themes/winstripe/newtab/toolbar.png b/browser/themes/winstripe/newtab/toolbar.png deleted file mode 100644 index 33bb4a320e76cc7a346ca4beb60e89a85a48aa2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1704 zcmV;Z23PrsP)Px#32;bRa{vGf6951U69E94oEQKA22DvsK~z}7y_bJ%Q`Z&8Kd#bFNHprK+M`uL zwCfKgT{N16NmNLrGYB?Ip_!c0EebG0NZU+=gtZGSrP4|gQ#5dB9ZH&nrHpnf9i5{E zEtE(_s#capf#4BfqYIE`cnoE*QH9#?p1VJIezAk|V*XgKbR~c9_0>7|-1F||9tXgi z`@71451%V5j*`^g+~4H{N}ek#ZV$cvfliE9tt@d&r^%r0{&l!1t7Tt!wTRve47KbF zdtNAC9tCLG7j}y1!$3jHzVJ*Dm9kiCZL0x7Z-3wdnt&3(37iFv0`Y1zbP`E$TjCK z0!6hI&kh3w+kb0qal@Jw4m&NPS`)@=);?R7H2!?DamxV!rHmMGJ!$T`83}W-r0mj8 zYtdfw=cdHiFZaCDBueTgM=J{;5bAU)m2&3eiJS<8Iz4q&tD<_6K|3uXE~~jIk9?MOJ`GJ(a&C3<=EEJsi)G)P;US~F+ai5$wnJ@bT4>ZqNPZ*Y^txR2xt)!JrVM$v=#|yk!xDS*AQ$w*br>X184}g6*L6f z!dm1^L$Iyb%7HDll{?afXG?8m6bNMU-6!jxZ&*9}>dw|50AceIDtUEhE26DDxdx0` z_rU+F{bI+SIY2G2%*=_8flq+eEwz=SmIHd-x-y{G(b}4lXnNf`r`(~Reqzg?_g;^D zWV!$MrB25~J!9HVXX4<)N3J$y#r*!2al>c>PRIQIrFV67L;+%czcX$ahqQzIzLyJU z=K4}UJ7gLSJk&F0&jKZNS+RKhFz{C(2k5z8UcMBF#p3ZpK)!Y`^2OKGAGDI@l<25Q z_rN6mVE5%E+AuO>!Ifv8nFSmH9tBRD_dq@{61!6`Ubg-0g_HN6luXZlZurtIEI7aX zzH@WKm(sJ~-uK>%e!hJ9V$+Enb8ZCid_OpR0dUNHf5bZD^S;@(TH=Pqf{VV{Wl7^x zvtazjjdU!yVTIV3^d7L$qHkrv1MdzuN!&=!f|Er>&han5Jd_B#c?3B?PsfkHzRbV( z-~YrgQdin&E!qXB(Up%_EcpC~52j~9-+~2BAlbOb-1!mUQSIRL7kBILeYfY>KQhgM z``S-iEV#5L$DReTc)T>(_`?4F^8g*3W%Yu ziJ^S%(BMILXfO}J9U3ffhX%u9s59=+-~_vW|Pbs|}_00z=2WUe6QV-BEz!Ua!+IpJ~Uv-kD1$zx$`tfIIY= zEeo_rU6xX*bwU5KWgZ|l>5bThmf)mEAa>gI`rnr5OzVO_c|5jt!IQncw^bLocAdS2 z1^-(A*g4m(v*}szWN&Zu=%Phw>w-l`j}8O4n};UOxH{Kir<3b~D;sjlCW2&B7sO&Q z+qz&{{wF`n)3Cs~Bhn1Cz^V%_znJfE zZy(T8>6j8*7Tgo)pK-OW@Foj y^;ilEvbP>fPSmf41$S@#WJ(tNw|>DW!2ba3q~P6d-#~K!0000 Date: Fri, 27 Jan 2012 11:22:35 +0100 Subject: [PATCH 02/24] Bug 721422 - [Page Thumbs] Re-enable tests and make them work with URI_DANGEROUS_TO_LOAD; r=dietrich --- browser/components/thumbnails/Makefile.in | 7 +- .../components/thumbnails/test/Makefile.in | 1 - .../test/browser_thumbnails_cache.js | 34 -------- .../test/browser_thumbnails_capture.js | 28 ++---- browser/components/thumbnails/test/head.js | 86 +++++++++++++++++-- 5 files changed, 85 insertions(+), 71 deletions(-) delete mode 100644 browser/components/thumbnails/test/browser_thumbnails_cache.js diff --git a/browser/components/thumbnails/Makefile.in b/browser/components/thumbnails/Makefile.in index c106a04572c1..5a7ccad7b568 100644 --- a/browser/components/thumbnails/Makefile.in +++ b/browser/components/thumbnails/Makefile.in @@ -18,10 +18,9 @@ EXTRA_PP_JS_MODULES = \ PageThumbs.jsm \ $(NULL) -# FIXME Bug 721422 - Re-enable tests and make them work with URI_DANGEROUS_TO_LOAD -#ifdef ENABLE_TESTS -# DIRS += test -#endif +ifdef ENABLE_TESTS + DIRS += test +endif include $(topsrcdir)/config/rules.mk diff --git a/browser/components/thumbnails/test/Makefile.in b/browser/components/thumbnails/test/Makefile.in index 014bf0828a31..03fea12b2770 100644 --- a/browser/components/thumbnails/test/Makefile.in +++ b/browser/components/thumbnails/test/Makefile.in @@ -12,7 +12,6 @@ include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ - browser_thumbnails_cache.js \ browser_thumbnails_capture.js \ head.js \ $(NULL) diff --git a/browser/components/thumbnails/test/browser_thumbnails_cache.js b/browser/components/thumbnails/test/browser_thumbnails_cache.js deleted file mode 100644 index c0917f74fffd..000000000000 --- a/browser/components/thumbnails/test/browser_thumbnails_cache.js +++ /dev/null @@ -1,34 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * These tests ensure that saving a thumbnail to the cache works. They also - * retrieve the thumbnail and display it using an element to compare - * its pixel colors. - */ -function runTests() { - // Create a new tab with a red background. - yield addTab("data:text/html,"); - let cw = gBrowser.selectedTab.linkedBrowser.contentWindow; - - // Capture a thumbnail for the tab. - let canvas = PageThumbs.capture(cw); - - // Store the tab into the thumbnail cache. - yield PageThumbs.store("key", canvas, next); - - let {width, height} = canvas; - let thumb = PageThumbs.getThumbnailURL("key", width, height); - - // Create a new tab with an image displaying the previously stored thumbnail. - yield addTab("data:text/html," + - ""); - - cw = gBrowser.selectedTab.linkedBrowser.contentWindow; - let [img, canvas] = cw.document.querySelectorAll("img, canvas"); - - // Draw the image to a canvas and compare the pixel color values. - let ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, width, height); - checkCanvasColor(ctx, 255, 0, 0, "we have a red image and canvas"); -} diff --git a/browser/components/thumbnails/test/browser_thumbnails_capture.js b/browser/components/thumbnails/test/browser_thumbnails_capture.js index 38886159659d..6f704118360d 100644 --- a/browser/components/thumbnails/test/browser_thumbnails_capture.js +++ b/browser/components/thumbnails/test/browser_thumbnails_capture.js @@ -2,37 +2,19 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ /** - * These tests ensure that capturing a site's screenshot to a canvas actually - * works. + * These tests ensure that capturing a sites's thumbnail, saving it and + * retrieving it from the cache works. */ function runTests() { // Create a tab with a red background. yield addTab("data:text/html,"); - checkCurrentThumbnailColor(255, 0, 0, "we have a red thumbnail"); + yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail"); // Load a page with a green background. yield navigateTo("data:text/html,"); - checkCurrentThumbnailColor(0, 255, 0, "we have a green thumbnail"); + yield captureAndCheckColor(0, 255, 0, "we have a green thumbnail"); // Load a page with a blue background. yield navigateTo("data:text/html,"); - checkCurrentThumbnailColor(0, 0, 255, "we have a blue thumbnail"); -} - -/** - * Captures a thumbnail of the currently selected tab and checks the color of - * the resulting canvas. - * @param aRed The red component's intensity. - * @param aGreen The green component's intensity. - * @param aBlue The blue component's intensity. - * @param aMessage The info message to print when checking the pixel color. - */ -function checkCurrentThumbnailColor(aRed, aGreen, aBlue, aMessage) { - let tab = gBrowser.selectedTab; - let cw = tab.linkedBrowser.contentWindow; - - let canvas = PageThumbs.capture(cw); - let ctx = canvas.getContext("2d"); - - checkCanvasColor(ctx, aRed, aGreen, aBlue, aMessage); + yield captureAndCheckColor(0, 0, 255, "we have a blue thumbnail"); } diff --git a/browser/components/thumbnails/test/head.js b/browser/components/thumbnails/test/head.js index 65eb8c4003b2..fd902b58079d 100644 --- a/browser/components/thumbnails/test/head.js +++ b/browser/components/thumbnails/test/head.js @@ -8,6 +8,8 @@ registerCleanupFunction(function () { gBrowser.removeTab(gBrowser.tabs[1]); }); +let cachedXULDocument; + /** * Provide the default test function to start our test runner. */ @@ -54,7 +56,7 @@ function next() { */ function addTab(aURI) { let tab = gBrowser.selectedTab = gBrowser.addTab(aURI); - whenBrowserLoaded(tab.linkedBrowser); + whenLoaded(tab.linkedBrowser); } /** @@ -63,22 +65,88 @@ function addTab(aURI) { */ function navigateTo(aURI) { let browser = gBrowser.selectedTab.linkedBrowser; - whenBrowserLoaded(browser); + whenLoaded(browser); browser.loadURI(aURI); } /** - * Continues the current test execution when a load event for the given browser - * has been received - * @param aBrowser The browser to listen on. + * Continues the current test execution when a load event for the given element + * has been received. + * @param aElement The DOM element to listen on. + * @param aCallback The function to call when the load event was dispatched. */ -function whenBrowserLoaded(aBrowser) { - aBrowser.addEventListener("load", function onLoad() { - aBrowser.removeEventListener("load", onLoad, true); - executeSoon(next); +function whenLoaded(aElement, aCallback) { + aElement.addEventListener("load", function onLoad() { + aElement.removeEventListener("load", onLoad, true); + executeSoon(aCallback || next); }, true); } +/** + * Captures a screenshot for the currently selected tab, stores it in the cache, + * retrieves it from the cache and compares pixel color values. + * @param aRed The red component's intensity. + * @param aGreen The green component's intensity. + * @param aBlue The blue component's intensity. + * @param aMessage The info message to print when comparing the pixel color. + */ +function captureAndCheckColor(aRed, aGreen, aBlue, aMessage) { + let window = gBrowser.selectedTab.linkedBrowser.contentWindow; + + let key = Date.now(); + let data = PageThumbs.capture(window); + + // Store the thumbnail in the cache. + PageThumbs.store(key, data, function () { + let width = 100, height = 100; + let thumb = PageThumbs.getThumbnailURL(key, width, height); + + getXULDocument(function (aDocument) { + let htmlns = "http://www.w3.org/1999/xhtml"; + let img = aDocument.createElementNS(htmlns, "img"); + img.setAttribute("src", thumb); + + whenLoaded(img, function () { + let canvas = aDocument.createElementNS(htmlns, "canvas"); + canvas.setAttribute("width", width); + canvas.setAttribute("height", height); + + // Draw the image to a canvas and compare the pixel color values. + let ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, width, height); + checkCanvasColor(ctx, aRed, aGreen, aBlue, aMessage); + + next(); + }); + }); + }); +} + +/** + * Passes a XUL document (created if necessary) to the given callback. + * @param aCallback The function to be called when the XUL document has been + * created. The first argument will be the document. + */ +function getXULDocument(aCallback) { + let hiddenWindow = Services.appShell.hiddenDOMWindow; + let doc = cachedXULDocument || hiddenWindow.document; + + if (doc instanceof XULDocument) { + aCallback(cachedXULDocument = doc); + return; + } + + let iframe = doc.createElement("iframe"); + iframe.setAttribute("src", "chrome://global/content/mozilla.xhtml"); + + iframe.addEventListener("DOMContentLoaded", function onLoad() { + iframe.removeEventListener("DOMContentLoaded", onLoad, false); + aCallback(cachedXULDocument = iframe.contentDocument); + }, false); + + doc.body.appendChild(iframe); +} + /** * Checks the top-left pixel of a given canvas' 2d context for a given color. * @param aContext The 2D context of a canvas. From 2ed39b812412d10106ac47ec81bf3b6e01334851 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 27 Jan 2012 13:42:05 +0000 Subject: [PATCH 03/24] Bug 717425 - GCLI forms should 'submit' when ENTER is pressed; r=dcamp --- browser/devtools/webconsole/gcli.jsm | 58 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/browser/devtools/webconsole/gcli.jsm b/browser/devtools/webconsole/gcli.jsm index 5a8c5d69cdd8..adf976b0fe36 100644 --- a/browser/devtools/webconsole/gcli.jsm +++ b/browser/devtools/webconsole/gcli.jsm @@ -6544,6 +6544,7 @@ define('gcli/ui/field', ['require', 'exports', 'module' , 'gcli/util', 'gcli/l10 var dom = require('gcli/util').dom; var createEvent = require('gcli/util').createEvent; +var KeyEvent = require('gcli/util').event.KeyEvent; var l10n = require('gcli/l10n'); var Argument = require('gcli/argument').Argument; @@ -6572,16 +6573,21 @@ var Menu = require('gcli/ui/menu').Menu; * This class is designed to be inherited from. It's important that all * subclasses have a similar constructor signature because they are created * via getField(...) - * @param document The document we use in calling createElement * @param type The type to use in conversions - * @param named Is this parameter named? That is to say, are positional - * arguments disallowed, if true, then we need to provide updates to the - * command line that explicitly name the parameter in use (e.g. --verbose, or - * --name Fred rather than just true or Fred) - * @param name If this parameter is named, what name should we use - * @param requ The requisition that we're attached to + * @param options A set of properties to help fields configure themselves: + * - document: The document we use in calling createElement + * - named: Is this parameter named? That is to say, are positional + * arguments disallowed, if true, then we need to provide updates to + * the command line that explicitly name the parameter in use + * (e.g. --verbose, or --name Fred rather than just true or Fred) + * - name: If this parameter is named, what name should we use + * - requisition: The requisition that we're attached to + * - required: Boolean to indicate if this is a mandatory field */ -function Field(document, type, named, name, requ) { +function Field(type, options) { + this.type = type; + this.document = options.document; + this.requisition = options.requisition; } /** @@ -6638,10 +6644,14 @@ Field.prototype.setMessage = function(message) { * Method to be called by subclasses when their input changes, which allows us * to properly pass on the fieldChanged event. */ -Field.prototype.onInputChange = function() { +Field.prototype.onInputChange = function(ev) { var conversion = this.getConversion(); this.fieldChanged({ conversion: conversion }); this.setMessage(conversion.message); + + if (ev.keyCode === KeyEvent.DOM_VK_RETURN) { + this.requisition.exec(); + } }; /** @@ -6715,8 +6725,7 @@ exports.getField = getField; * A field that allows editing of strings */ function StringField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); this.arg = new Argument(); this.element = dom.createElement(this.document, 'input'); @@ -6763,8 +6772,7 @@ addField(StringField); * A field that allows editing of numbers using an [input type=number] field */ function NumberField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); this.arg = new Argument(); this.element = dom.createElement(this.document, 'input'); @@ -6818,8 +6826,8 @@ addField(NumberField); * A field that uses a checkbox to toggle a boolean field */ function BooleanField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); + this.name = options.name; this.named = options.named; @@ -6876,8 +6884,8 @@ addField(BooleanField); * */ function SelectionField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); + this.items = []; this.element = dom.createElement(this.document, 'select'); @@ -6944,9 +6952,7 @@ addField(SelectionField); * A field that allows editing of javascript */ function JavascriptField(type, options) { - this.document = options.document; - this.type = type; - this.requ = options.requisition; + Field.call(this, type, options); this.onInputChange = this.onInputChange.bind(this); this.arg = new Argument('', '{ ', ' }'); @@ -7050,10 +7056,8 @@ addField(JavascriptField); * last possible time */ function DeferredField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); this.options = options; - this.requisition = options.requisition; this.requisition.assignmentChange.add(this.update, this); this.element = dom.createElement(this.document, 'div'); @@ -7111,8 +7115,8 @@ addField(DeferredField); * BlankFields are not for general use. */ function BlankField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); + this.element = dom.createElement(this.document, 'div'); this.fieldChanged = createEvent('BlankField.fieldChanged'); @@ -7139,10 +7143,8 @@ addField(BlankField); * given for a parameter. */ function ArrayField(type, options) { - this.document = options.document; - this.type = type; + Field.call(this, type, options); this.options = options; - this.requ = options.requisition; this._onAdd = this._onAdd.bind(this); this.members = []; From e09959b68708154e9738b7d32d35a55a0375bf3d Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 27 Jan 2012 13:42:05 +0000 Subject: [PATCH 04/24] Bug 697043 - GCLI's inspect command should use an overlay rather than direct node manipulation; r=dcamp --- browser/devtools/webconsole/gcli.jsm | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/browser/devtools/webconsole/gcli.jsm b/browser/devtools/webconsole/gcli.jsm index adf976b0fe36..799543ba6698 100644 --- a/browser/devtools/webconsole/gcli.jsm +++ b/browser/devtools/webconsole/gcli.jsm @@ -3603,15 +3603,8 @@ define('gcli/host', ['require', 'exports', 'module' ], function(require, exports * There is likely a better way to do this, but this will do for now. */ exports.flashNode = function(node, color) { - if (!node.__gcliHighlighting) { - node.__gcliHighlighting = true; - var original = node.style.background; - node.style.background = color; - setTimeout(function() { - node.style.background = original; - delete node.__gcliHighlighting; - }, 1000); - } + // We avoid changing the DOM under firefox developer tools so this is a no-op + // In future we will use the multi-highlighter implemented in bug 653545. }; From ca1fa6d6a7ed1eaf7fd4a7200a91ece263adaa69 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 27 Jan 2012 13:42:05 +0000 Subject: [PATCH 05/24] Bug 719292 - Error: hud.jsterm is null in resource:///modules/HUDService.jsm:2074; r=msucan --- browser/devtools/webconsole/HUDService.jsm | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/browser/devtools/webconsole/HUDService.jsm b/browser/devtools/webconsole/HUDService.jsm index 934930d012bb..a57e8f519938 100644 --- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -2067,7 +2067,16 @@ HUD_SERVICE.prototype = // Pipe the message to createMessageNode(). let hud = HUDService.hudReferences[aHUDId]; function formatResult(x) { - return (typeof(x) == "string") ? x : hud.jsterm.formatResult(x); + if (typeof(x) == "string") { + return x; + } + if (hud.gcliterm) { + return hud.gcliterm.formatResult(x); + } + if (hud.jsterm) { + return hud.jsterm.formatResult(x); + } + return x; } let body = null; @@ -7068,5 +7077,8 @@ GcliTerm.prototype = { }, clearOutput: JSTerm.prototype.clearOutput, -}; + formatResult: JSTerm.prototype.formatResult, + getResultType: JSTerm.prototype.getResultType, + formatString: JSTerm.prototype.formatString, +}; From e917b7526eca01c21c12c5ebfaaf3efe688b0994 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 27 Jan 2012 13:42:06 +0000 Subject: [PATCH 06/24] =?UTF-8?q?Bug=20718431=20-=20WebConsole=20doesn't?= =?UTF-8?q?=20show=20the=20warning=20icons=20on=20warning=20and=20errors;?= =?UTF-8?q?=20r=3Dpaul,d=C3=83=C2=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/themes/gnomestripe/devtools/gcli.css | 1 + browser/themes/gnomestripe/devtools/webconsole.css | 7 +++++-- browser/themes/pinstripe/devtools/gcli.css | 1 + browser/themes/pinstripe/devtools/webconsole.css | 7 +++++-- browser/themes/winstripe/devtools/gcli.css | 1 + browser/themes/winstripe/devtools/webconsole.css | 7 +++++-- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/browser/themes/gnomestripe/devtools/gcli.css b/browser/themes/gnomestripe/devtools/gcli.css index b924b667b33b..2c28933a2149 100644 --- a/browser/themes/gnomestripe/devtools/gcli.css +++ b/browser/themes/gnomestripe/devtools/gcli.css @@ -110,6 +110,7 @@ margin-bottom: 3px; -moz-margin-start: 3px; -moz-margin-end: 6px; + list-style-image: none; } /* Extract from display.css, we only want these 2 rules */ diff --git a/browser/themes/gnomestripe/devtools/webconsole.css b/browser/themes/gnomestripe/devtools/webconsole.css index 2b8196df7b5f..77635f3f891e 100644 --- a/browser/themes/gnomestripe/devtools/webconsole.css +++ b/browser/themes/gnomestripe/devtools/webconsole.css @@ -70,6 +70,11 @@ font: 12px "DejaVu Sans Mono", monospace; } +.hud-msg-node { + list-style-image: url(chrome://browser/skin/devtools/webconsole.png); + -moz-image-region: rect(0, 1px, 0, 0); +} + .webconsole-msg-icon { margin: 3px 4px; width: 8px; @@ -87,8 +92,6 @@ -moz-margin-start: 3px; -moz-margin-end: 6px; white-space: pre-wrap; - list-style-image: url(chrome://browser/skin/devtools/webconsole.png); - -moz-image-region: rect(0, 1px, 0, 0); font: 12px "DejaVu Sans Mono", monospace; } diff --git a/browser/themes/pinstripe/devtools/gcli.css b/browser/themes/pinstripe/devtools/gcli.css index 59125ab97ae0..f2d40e298bd1 100644 --- a/browser/themes/pinstripe/devtools/gcli.css +++ b/browser/themes/pinstripe/devtools/gcli.css @@ -110,6 +110,7 @@ margin-bottom: 3px; -moz-margin-start: 3px; -moz-margin-end: 6px; + list-style-image: none; } /* Extract from display.css, we only want these 2 rules */ diff --git a/browser/themes/pinstripe/devtools/webconsole.css b/browser/themes/pinstripe/devtools/webconsole.css index a5bc2e4220ae..ef28d4ccbc9b 100644 --- a/browser/themes/pinstripe/devtools/webconsole.css +++ b/browser/themes/pinstripe/devtools/webconsole.css @@ -73,6 +73,11 @@ font: 11px Menlo, Monaco, monospace; } +.hud-msg-node { + list-style-image: url(chrome://browser/skin/devtools/webconsole.png); + -moz-image-region: rect(0, 1px, 0, 0); +} + .webconsole-msg-icon { margin: 3px 4px; width: 8px; @@ -90,8 +95,6 @@ -moz-margin-start: 3px; -moz-margin-end: 6px; white-space: pre-wrap; - list-style-image: url(chrome://browser/skin/devtools/webconsole.png); - -moz-image-region: rect(0, 1px, 0, 0); font: 11px Menlo, Monaco, monospace; } diff --git a/browser/themes/winstripe/devtools/gcli.css b/browser/themes/winstripe/devtools/gcli.css index f6aa20db2a31..5002b2c6510b 100644 --- a/browser/themes/winstripe/devtools/gcli.css +++ b/browser/themes/winstripe/devtools/gcli.css @@ -110,6 +110,7 @@ margin-bottom: 3px; -moz-margin-start: 3px; -moz-margin-end: 6px; + list-style-image: none; } /* Extract from display.css, we only want these 2 rules */ diff --git a/browser/themes/winstripe/devtools/webconsole.css b/browser/themes/winstripe/devtools/webconsole.css index 9fbc63c2dea0..07a2d7d3e47d 100644 --- a/browser/themes/winstripe/devtools/webconsole.css +++ b/browser/themes/winstripe/devtools/webconsole.css @@ -69,6 +69,11 @@ font: 12px Consolas, Lucida Console, monospace; } +.hud-msg-node { + list-style-image: url(chrome://browser/skin/devtools/webconsole.png); + -moz-image-region: rect(0, 1px, 0, 0); +} + .webconsole-msg-icon { margin: 3px 4px; width: 8px; @@ -86,8 +91,6 @@ -moz-margin-start: 3px; -moz-margin-end: 6px; white-space: pre-wrap; - list-style-image: url(chrome://browser/skin/devtools/webconsole.png); - -moz-image-region: rect(0, 1px, 0, 0); font: 12px Consolas, Lucida Console, monospace; } From 383d0c64c57b88e5779d610d77906c77dd947013 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Wed, 25 Jan 2012 23:40:18 +0100 Subject: [PATCH 07/24] Bug 455553 - Part 1 - XUL/HTML Page and Scripts; r=blair,dietrich --- browser/base/content/newtab/batch.js | 76 ++++++ browser/base/content/newtab/cells.js | 137 +++++++++++ browser/base/content/newtab/drag.js | 140 +++++++++++ browser/base/content/newtab/drop.js | 147 ++++++++++++ browser/base/content/newtab/dropPreview.js | 222 +++++++++++++++++ browser/base/content/newtab/dropTargetShim.js | 178 ++++++++++++++ browser/base/content/newtab/grid.js | 132 ++++++++++ browser/base/content/newtab/newTab.js | 47 ++++ browser/base/content/newtab/newTab.xul | 42 ++++ browser/base/content/newtab/page.js | 173 ++++++++++++++ browser/base/content/newtab/sites.js | 207 ++++++++++++++++ browser/base/content/newtab/toolbar.js | 77 ++++++ .../base/content/newtab/transformations.js | 226 ++++++++++++++++++ browser/base/content/newtab/updater.js | 182 ++++++++++++++ 14 files changed, 1986 insertions(+) create mode 100644 browser/base/content/newtab/batch.js create mode 100644 browser/base/content/newtab/cells.js create mode 100644 browser/base/content/newtab/drag.js create mode 100644 browser/base/content/newtab/drop.js create mode 100644 browser/base/content/newtab/dropPreview.js create mode 100644 browser/base/content/newtab/dropTargetShim.js create mode 100644 browser/base/content/newtab/grid.js create mode 100644 browser/base/content/newtab/newTab.js create mode 100644 browser/base/content/newtab/newTab.xul create mode 100644 browser/base/content/newtab/page.js create mode 100644 browser/base/content/newtab/sites.js create mode 100644 browser/base/content/newtab/toolbar.js create mode 100644 browser/base/content/newtab/transformations.js create mode 100644 browser/base/content/newtab/updater.js diff --git a/browser/base/content/newtab/batch.js b/browser/base/content/newtab/batch.js new file mode 100644 index 000000000000..9d940a63ddfb --- /dev/null +++ b/browser/base/content/newtab/batch.js @@ -0,0 +1,76 @@ +#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 class makes it easy to wait until a batch of callbacks has finished. + * + * Example: + * + * let batch = new Batch(function () alert("finished")); + * let pop = batch.pop.bind(batch); + * + * for (let i = 0; i < 5; i++) { + * batch.push(); + * setTimeout(pop, i * 1000); + * } + * + * batch.close(); + */ +function Batch(aCallback) { + this._callback = aCallback; +} + +Batch.prototype = { + /** + * The number of batch entries. + */ + _count: 0, + + /** + * Whether this batch is closed. + */ + _closed: false, + + /** + * Increases the number of batch entries by one. + */ + push: function Batch_push() { + if (!this._closed) + this._count++; + }, + + /** + * Decreases the number of batch entries by one. + */ + pop: function Batch_pop() { + if (this._count) + this._count--; + + if (this._closed) + this._check(); + }, + + /** + * Closes the batch so that no new entries can be added. + */ + close: function Batch_close() { + if (this._closed) + return; + + this._closed = true; + this._check(); + }, + + /** + * Checks if the batch has finished. + */ + _check: function Batch_check() { + if (this._count == 0 && this._callback) { + this._callback(); + this._callback = null; + } + } +}; diff --git a/browser/base/content/newtab/cells.js b/browser/base/content/newtab/cells.js new file mode 100644 index 000000000000..02cf6d74cbbd --- /dev/null +++ b/browser/base/content/newtab/cells.js @@ -0,0 +1,137 @@ +#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 class manages a cell's DOM node (not the actually cell content, a site). + * It's mostly read-only, i.e. all manipulation of both position and content + * aren't handled here. + */ +function Cell(aGrid, aNode) { + this._grid = aGrid; + this._node = 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); + }, this); +} + +Cell.prototype = { + /** + * + */ + _grid: null, + + /** + * The cell's DOM node. + */ + get node() this._node, + + /** + * The cell's offset in the grid. + */ + get index() { + let index = this._grid.cells.indexOf(this); + + // Cache this value, overwrite the getter. + Object.defineProperty(this, "index", {value: index, enumerable: true}); + + return index; + }, + + /** + * The previous cell in the grid. + */ + get previousSibling() { + let prev = this.node.previousElementSibling; + prev = prev && prev._newtabCell; + + // Cache this value, overwrite the getter. + Object.defineProperty(this, "previousSibling", {value: prev, enumerable: true}); + + return prev; + }, + + /** + * The next cell in the grid. + */ + get nextSibling() { + let next = this.node.nextElementSibling; + next = next && next._newtabCell; + + // Cache this value, overwrite the getter. + Object.defineProperty(this, "nextSibling", {value: next, enumerable: true}); + + return next; + }, + + /** + * The site contained in the cell, if any. + */ + get site() { + let firstChild = this.node.firstElementChild; + return firstChild && firstChild._newtabSite; + }, + + /** + * Checks whether the cell contains a pinned site. + * @return Whether the cell contains a pinned site. + */ + containsPinnedSite: function Cell_containsPinnedSite() { + let site = this.site; + return site && site.isPinned(); + }, + + /** + * Checks whether the cell contains a site (is empty). + * @return Whether the cell is empty. + */ + isEmpty: function Cell_isEmpty() { + return !this.site; + }, + + /** + * Event handler for the 'dragenter' event. + * @param aEvent The dragenter event. + */ + onDragEnter: function Cell_onDragEnter(aEvent) { + if (gDrag.isValid(aEvent)) { + aEvent.preventDefault(); + gDrop.enter(this, aEvent); + } + }, + + /** + * 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); + } + } +}; diff --git a/browser/base/content/newtab/drag.js b/browser/base/content/newtab/drag.js new file mode 100644 index 000000000000..80ff72c80822 --- /dev/null +++ b/browser/base/content/newtab/drag.js @@ -0,0 +1,140 @@ +#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 implements site dragging functionality. + */ +let gDrag = { + /** + * The site offset to the drag start point. + */ + _offsetX: null, + _offsetY: null, + + /** + * The site that is dragged. + */ + _draggedSite: null, + get draggedSite() this._draggedSite, + + /** + * The cell width/height at the point the drag started. + */ + _cellWidth: null, + _cellHeight: null, + get cellWidth() this._cellWidth, + get cellHeight() this._cellHeight, + + /** + * Start a new drag operation. + * @param aSite The site that's being dragged. + * @param aEvent The 'dragstart' event. + */ + 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"); + + this._setDragData(aSite, aEvent); + + // Store the cursor offset. + let node = aSite.node; + let rect = node.getBoundingClientRect(); + this._offsetX = aEvent.clientX - rect.left; + this._offsetY = aEvent.clientY - rect.top; + + // Store the cell dimensions. + let cellNode = aSite.cell.node; + this._cellWidth = cellNode.offsetWidth; + this._cellHeight = cellNode.offsetHeight; + + gTransformation.freezeSitePosition(aSite); + }, + + /** + * Handles the 'drag' event. + * @param aSite The site that's being dragged. + * @param aEvent The 'drag' event. + */ + drag: function Drag_drag(aSite, aEvent) { + // Get the viewport size. + let {clientWidth, clientHeight} = document.documentElement; + + // We'll want a padding of 5px. + let border = 5; + + // Enforce minimum constraints to keep the drag image inside the window. + let left = Math.max(scrollX + aEvent.clientX - this._offsetX, border); + let top = Math.max(scrollY + aEvent.clientY - this._offsetY, border); + + // Enforce maximum constraints to keep the drag image inside the window. + left = Math.min(left, scrollX + clientWidth - this.cellWidth - border); + top = Math.min(top, scrollY + clientHeight - this.cellHeight - border); + + // Update the drag image's position. + gTransformation.setSitePosition(aSite, {left: left, top: top}); + }, + + /** + * Ends the current drag operation. + * @param aSite The site that's being dragged. + * @param aEvent The 'dragend' event. + */ + end: function Drag_end(aSite, aEvent) { + aSite.node.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") + }); + + this._draggedSite = null; + }, + + /** + * Checks whether we're responsible for a given drag event. + * @param aEvent The drag event to check. + * @return Whether we should handle this drag and drop operation. + */ + isValid: function Drag_isValid(aEvent) { + let dt = aEvent.dataTransfer; + return dt && dt.types.contains("text/x-moz-url"); + }, + + /** + * Initializes the drag data for the current drag operation. + * @param aSite The site that's being dragged. + * @param aEvent The 'dragstart' event. + */ + _setDragData: function Drag_setDragData(aSite, aEvent) { + let {url, title} = aSite; + + let dt = aEvent.dataTransfer; + dt.mozCursor = "default"; + dt.effectAllowed = "move"; + dt.setData("text/plain", url); + dt.setData("text/uri-list", url); + dt.setData("text/x-moz-url", url + "\n" + title); + dt.setData("text/html", "" + url + ""); + + // 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); + 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); + } +}; diff --git a/browser/base/content/newtab/drop.js b/browser/base/content/newtab/drop.js new file mode 100644 index 000000000000..094b3acabcac --- /dev/null +++ b/browser/base/content/newtab/drop.js @@ -0,0 +1,147 @@ +#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 + +// A little delay that prevents the grid from being too sensitive when dragging +// sites around. +const DELAY_REARRANGE_MS = 100; + +/** + * This singleton implements site dropping functionality. + */ +let gDrop = { + /** + * The last drop target. + */ + _lastDropTarget: null, + + /** + * Handles the 'dragenter' event. + * @param aCell The drop target cell. + */ + enter: function Drop_enter(aCell) { + this._delayedRearrange(aCell); + }, + + /** + * Handles the 'dragexit' event. + * @param aCell The drop target cell. + * @param aEvent The 'dragexit' event. + */ + exit: function Drop_exit(aCell, aEvent) { + if (aEvent.dataTransfer && !aEvent.dataTransfer.mozUserCancelled) { + this._delayedRearrange(); + } else { + // The drag operation has been cancelled. + this._cancelDelayedArrange(); + this._rearrange(); + } + }, + + /** + * Handles the 'drop' event. + * @param aCell The drop target cell. + * @param aEvent The 'dragexit' event. + * @param aCallback The callback to call when the drop is finished. + */ + drop: function Drop_drop(aCell, aEvent, aCallback) { + // The cell that is the drop target could contain a pinned site. We need + // to find out where that site has gone and re-pin it there. + if (aCell.containsPinnedSite()) + this._repinSitesAfterDrop(aCell); + + // Pin the dragged or insert the new site. + this._pinDraggedSite(aCell, aEvent); + + this._cancelDelayedArrange(); + + // Update the grid and move all sites to their new places. + gUpdater.updateGrid(aCallback); + }, + + /** + * Re-pins all pinned sites in their (new) positions. + * @param aCell The drop target cell. + */ + _repinSitesAfterDrop: function Drop_repinSitesAfterDrop(aCell) { + let sites = gDropPreview.rearrange(aCell); + + // Filter out pinned sites. + let pinnedSites = sites.filter(function (aSite) { + return aSite && aSite.isPinned(); + }); + + // Re-pin all shifted pinned cells. + pinnedSites.forEach(function (aSite) aSite.pin(sites.indexOf(aSite)), this); + }, + + /** + * Pins the dragged site in its new place. + * @param aCell The drop target cell. + * @param aEvent The 'dragexit' event. + */ + _pinDraggedSite: function Drop_pinDraggedSite(aCell, aEvent) { + let index = aCell.index; + let draggedSite = gDrag.draggedSite; + + if (draggedSite) { + // Pin the dragged site at its new place. + if (aCell != draggedSite.cell) + draggedSite.pin(index); + } else { + // A new link was dragged onto the grid. Create it by pinning its URL. + let dt = aEvent.dataTransfer; + let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/); + gPinnedLinks.pin({url: url, title: title}, index); + } + }, + + /** + * Time a rearrange with a little delay. + * @param aCell The drop target cell. + */ + _delayedRearrange: function Drop_delayedRearrange(aCell) { + // The last drop target didn't change so there's no need to re-arrange. + if (this._lastDropTarget == aCell) + return; + + let self = this; + + function callback() { + self._rearrangeTimeout = null; + self._rearrange(aCell); + } + + this._cancelDelayedArrange(); + this._rearrangeTimeout = setTimeout(callback, DELAY_REARRANGE_MS); + + // Store the last drop target. + this._lastDropTarget = aCell; + }, + + /** + * Cancels a timed rearrange, if any. + */ + _cancelDelayedArrange: function Drop_cancelDelayedArrange() { + if (this._rearrangeTimeout) { + clearTimeout(this._rearrangeTimeout); + this._rearrangeTimeout = null; + } + }, + + /** + * Rearrange all sites in the grid depending on the current drop target. + * @param aCell The drop target cell. + */ + _rearrange: function Drop_rearrange(aCell) { + let sites = gGrid.sites; + + // We need to rearrange the grid only if there's a current drop target. + if (aCell) + sites = gDropPreview.rearrange(aCell); + + gTransformation.rearrangeSites(sites, {unfreeze: !aCell}); + } +}; diff --git a/browser/base/content/newtab/dropPreview.js b/browser/base/content/newtab/dropPreview.js new file mode 100644 index 000000000000..903762345706 --- /dev/null +++ b/browser/base/content/newtab/dropPreview.js @@ -0,0 +1,222 @@ +#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 provides the ability to re-arrange the current grid to + * indicate the transformation that results from dropping a cell at a certain + * position. + */ +let gDropPreview = { + /** + * Rearranges the sites currently contained in the grid when a site would be + * dropped onto the given cell. + * @param aCell The drop target cell. + * @return The re-arranged array of sites. + */ + rearrange: function DropPreview_rearrange(aCell) { + let sites = gGrid.sites; + + // Insert the dragged site into the current grid. + this._insertDraggedSite(sites, aCell); + + // After the new site has been inserted we need to correct the positions + // of all pinned tabs that have been moved around. + this._repositionPinnedSites(sites, aCell); + + return sites; + }, + + /** + * Inserts the currently dragged site into the given array of sites. + * @param aSites The array of sites to insert into. + * @param aCell The drop target cell. + */ + _insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) { + let dropIndex = aCell.index; + let draggedSite = gDrag.draggedSite; + + // We're currently dragging a site. + if (draggedSite) { + let dragCell = draggedSite.cell; + let dragIndex = dragCell.index; + + // Move the dragged site into its new position. + if (dragIndex != dropIndex) { + aSites.splice(dragIndex, 1); + aSites.splice(dropIndex, 0, draggedSite); + } + // We're handling an external drag item. + } else { + aSites.splice(dropIndex, 0, null); + } + }, + + /** + * Correct the position of all pinned sites that might have been moved to + * different positions after the dragged site has been inserted. + * @param aSites The array of sites containing the dragged site. + * @param aCell The drop target cell. + */ + _repositionPinnedSites: + function DropPreview_repositionPinnedSites(aSites, aCell) { + + // Collect all pinned sites. + let pinnedSites = this._filterPinnedSites(aSites, aCell); + + // Correct pinned site positions. + pinnedSites.forEach(function (aSite) { + aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index]; + aSites[aSite.cell.index] = aSite; + }, this); + + // There might be a pinned cell that got pushed out of the grid, try to + // sneak it in by removing a lower-priority cell. + if (this._hasOverflowedPinnedSite(aSites, aCell)) + this._repositionOverflowedPinnedSite(aSites, aCell); + }, + + /** + * Filter pinned sites out of the grid that are still on their old positions + * and have not moved. + * @param aSites The array of sites to filter. + * @param aCell The drop target cell. + * @return The filtered array of sites. + */ + _filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) { + let draggedSite = gDrag.draggedSite; + + // When dropping on a cell that contains a pinned site make sure that all + // pinned cells surrounding the drop target are moved as well. + let range = this._getPinnedRange(aCell); + + return aSites.filter(function (aSite, aIndex) { + // The site must be valid, pinned and not the dragged site. + if (!aSite || aSite == draggedSite || !aSite.isPinned()) + return false; + + let index = aSite.cell.index; + + // If it's not in the 'pinned range' it's a valid pinned site. + return (index > range.end || index < range.start); + }); + }, + + /** + * Determines the range of pinned sites surrounding the drop target cell. + * @param aCell The drop target cell. + * @return The range of pinned cells. + */ + _getPinnedRange: function DropPreview_getPinnedRange(aCell) { + let dropIndex = aCell.index; + let range = {start: dropIndex, end: dropIndex}; + + // We need a pinned range only when dropping on a pinned site. + if (aCell.containsPinnedSite()) { + let links = gPinnedLinks.links; + + // Find all previous siblings of the drop target that are pinned as well. + while (range.start && links[range.start - 1]) + range.start--; + + let maxEnd = links.length - 1; + + // Find all next siblings of the drop target that are pinned as well. + while (range.end < maxEnd && links[range.end + 1]) + range.end++; + } + + return range; + }, + + /** + * Checks if the given array of sites contains a pinned site that has + * been pushed out of the grid. + * @param aSites The array of sites to check. + * @param aCell The drop target cell. + * @return Whether there is an overflowed pinned cell. + */ + _hasOverflowedPinnedSite: + function DropPreview_hasOverflowedPinnedSite(aSites, aCell) { + + // If the drop target isn't pinned there's no way a pinned site has been + // pushed out of the grid so we can just exit here. + if (!aCell.containsPinnedSite()) + return false; + + let cells = gGrid.cells; + + // No cells have been pushed out of the grid, nothing to do here. + if (aSites.length <= cells.length) + return false; + + let overflowedSite = aSites[cells.length]; + + // Nothing to do if the site that got pushed out of the grid is not pinned. + return (overflowedSite && overflowedSite.isPinned()); + }, + + /** + * We have a overflowed pinned site that we need to re-position so that it's + * visible again. We try to find a lower-priority cell (empty or containing + * an unpinned site) that we can move it to. + * @param aSites The array of sites. + * @param aCell The drop target cell. + */ + _repositionOverflowedPinnedSite: + function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) { + + // Try to find a lower-priority cell (empty or containing an unpinned site). + let index = this._indexOfLowerPrioritySite(aSites, aCell); + + if (index > -1) { + let cells = gGrid.cells; + let dropIndex = aCell.index; + + // Move all pinned cells to their new positions to let the overflowed + // site fit into the grid. + for (let i = index + 1, lastPosition = index; i < aSites.length; i++) { + if (i != dropIndex) { + aSites[lastPosition] = aSites[i]; + lastPosition = i; + } + } + + // Finally, remove the overflowed site from its previous position. + aSites.splice(cells.length, 1); + } + }, + + /** + * Finds the index of the last cell that is empty or contains an unpinned + * site. These are considered to be of a lower priority. + * @param aSites The array of sites. + * @param aCell The drop target cell. + * @return The cell's index. + */ + _indexOfLowerPrioritySite: + function DropPreview_indexOfLowerPrioritySite(aSites, aCell) { + + let cells = gGrid.cells; + let dropIndex = aCell.index; + + // Search (beginning with the last site in the grid) for a site that is + // empty or unpinned (an thus lower-priority) and can be pushed out of the + // grid instead of the pinned site. + for (let i = cells.length - 1; i >= 0; i--) { + // The cell that is our drop target is not a good choice. + if (i == dropIndex) + continue; + + let site = aSites[i]; + + // We can use the cell only if it's empty or the site is un-pinned. + if (!site || !site.isPinned()) + return i; + } + + return -1; + } +}; diff --git a/browser/base/content/newtab/dropTargetShim.js b/browser/base/content/newtab/dropTargetShim.js new file mode 100644 index 000000000000..5e6ea5c3c1e3 --- /dev/null +++ b/browser/base/content/newtab/dropTargetShim.js @@ -0,0 +1,178 @@ +#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 provides a custom drop target detection. We need this because + * the default DnD target detection relies on the cursor's position. We want + * to pick a drop target based on the dragged site's position. + */ +let gDropTargetShim = { + /** + * Cache for the position of all cells, cleaned after drag finished. + */ + _cellPositions: null, + + /** + * The last drop target that was hovered. + */ + _lastDropTarget: null, + + /** + * Initializes the drop target shim. + */ + 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); + }, + + /** + * Handles the 'dragstart' event. + * @param aEvent The 'dragstart' event. + */ + _start: function DropTargetShim_start(aEvent) { + gGrid.lock(); + + // XXX bug 505521 - Listen for dragover on the document. + document.documentElement.addEventListener("dragover", this._dragover, false); + }, + + /** + * Handles the 'drag' event and determines the current drop target. + * @param aEvent The 'drag' event. + */ + _drag: function DropTargetShim_drag(aEvent) { + // 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 (this._lastDropTarget) + // We left the last drop target. + this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget); + + if (target) + // We're now hovering a (new) drop target. + this._dispatchEvent(aEvent, "dragenter", target); + + if (this._lastDropTarget) + // We left the last drop target. + this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget); + + this._lastDropTarget = target; + } + }, + + /** + * Handles the 'dragover' event as long as bug 505521 isn't fixed to get + * current mouse cursor coordinates while dragging. + * @param aEvent The 'dragover' event. + */ + _dragover: function DropTargetShim_dragover(aEvent) { + let sourceNode = aEvent.dataTransfer.mozSourceNode; + gDrag.drag(sourceNode._newtabSite, aEvent); + + this._drag(aEvent); + }, + + /** + * Handles the 'dragend' event. + * @param aEvent The 'dragend' event. + */ + _end: function DropTargetShim_end(aEvent) { + // Make sure to determine the current drop target in case the dragenter + // event hasn't been fired. + this._drag(aEvent); + + if (this._lastDropTarget) { + if (aEvent.dataTransfer.mozUserCancelled) { + // The drag operation was cancelled. + this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget); + this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget); + } else { + // A site was successfully dropped. + this._dispatchEvent(aEvent, "drop", this._lastDropTarget); + } + + // Clean up. + this._lastDropTarget = null; + this._cellPositions = null; + } + + gGrid.unlock(); + + // XXX bug 505521 - Remove the document's dragover listener. + document.documentElement.removeEventListener("dragover", this._dragover, false); + }, + + /** + * Determines the current drop target by matching the dragged site's position + * against all cells in the grid. + * @return The currently hovered drop target or null. + */ + _findDropTarget: function DropTargetShim_findDropTarget() { + // These are the minimum intersection values - we want to use the cell if + // the site is >= 50% hovering its position. + let minWidth = gDrag.cellWidth / 2; + let minHeight = gDrag.cellHeight / 2; + + let cellPositions = this._getCellPositions(); + let rect = gTransformation.getNodePosition(gDrag.draggedSite.node); + + // Compare each cell's position to the dragged site's position. + for (let i = 0; i < cellPositions.length; i++) { + let inter = rect.intersect(cellPositions[i].rect); + + // If the intersection is big enough we found a drop target. + if (inter.width >= minWidth && inter.height >= minHeight) + return cellPositions[i].cell; + } + + // No drop target found. + return null; + }, + + /** + * Gets the positions of all cell nodes. + * @return The (cached) cell positions. + */ + _getCellPositions: function DropTargetShim_getCellPositions() { + if (this._cellPositions) + return this._cellPositions; + + return this._cellPositions = gGrid.cells.map(function (cell) { + return {cell: cell, rect: gTransformation.getNodePosition(cell.node)}; + }); + }, + + /** + * Dispatches a custom DragEvent on the given target node. + * @param aEvent The source event. + * @param aType The event type. + * @param aTarget The target node that receives the event. + */ + _dispatchEvent: + function DropTargetShim_dispatchEvent(aEvent, aType, aTarget) { + + let node = aTarget.node; + let event = document.createEvent("DragEvents"); + + event.initDragEvent(aType, true, true, window, 0, 0, 0, 0, 0, false, false, + false, false, 0, node, aEvent.dataTransfer); + + node.dispatchEvent(event); + } +}; diff --git a/browser/base/content/newtab/grid.js b/browser/base/content/newtab/grid.js new file mode 100644 index 000000000000..72acde0dfc66 --- /dev/null +++ b/browser/base/content/newtab/grid.js @@ -0,0 +1,132 @@ +#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 grid that contains all sites. + */ +let gGrid = { + /** + * The DOM node of the grid. + */ + _node: null, + get node() this._node, + + /** + * The cached DOM fragment for sites. + */ + _siteFragment: null, + + /** + * All cells contained in the grid. + */ + get cells() { + let children = this.node.querySelectorAll("li"); + let cells = [new Cell(this, child) for each (child in children)]; + + // Replace the getter with our cached value. + Object.defineProperty(this, "cells", {value: cells, enumerable: true}); + + return cells; + }, + + /** + * All sites contained in the grid's cells. Sites may be empty. + */ + get sites() [cell.site for each (cell in this.cells)], + + /** + * Initializes the grid. + * @param aSelector The query selector of the grid. + */ + init: function Grid_init(aSelector) { + this._node = document.querySelector(aSelector); + this._createSiteFragment(); + this._draw(); + }, + + /** + * Creates a new site in the grid. + * @param aLink The new site's link. + * @param aCell The cell that will contain the new site. + * @return The newly created site. + */ + createSite: function Grid_createSite(aLink, aCell) { + let node = aCell.node; + node.appendChild(this._siteFragment.cloneNode(true)); + return new Site(node.firstElementChild, aLink); + }, + + /** + * Refreshes the grid and re-creates all sites. + */ + refresh: function Grid_refresh() { + // Remove all sites. + this.cells.forEach(function (cell) { + let node = cell.node; + let child = node.firstElementChild; + + if (child) + node.removeChild(child); + }, this); + + // Draw the grid again. + this._draw(); + }, + + /** + * Locks the grid to block all pointer events. + */ + lock: function Grid_lock() { + this.node.setAttribute("locked", "true"); + }, + + /** + * Unlocks the grid to allow all pointer events. + */ + unlock: function Grid_unlock() { + this.node.removeAttribute("locked"); + }, + + /** + * 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"); + site.setAttribute("draggable", "true"); + + // Create the site's inner HTML code. + site.innerHTML = + '' + + '' + + '' + + ' ' + + ' ' + + ''; + + this._siteFragment = document.createDocumentFragment(); + this._siteFragment.appendChild(site); + }, + + /** + * Draws the grid, creates all sites and puts them into their cells. + */ + _draw: function Grid_draw() { + let cells = this.cells; + + // Put sites into the cells. + let links = gLinks.getLinks(); + let length = Math.min(links.length, cells.length); + + for (let i = 0; i < length; i++) { + if (links[i]) + this.createSite(links[i], cells[i]); + } + } +}; diff --git a/browser/base/content/newtab/newTab.js b/browser/base/content/newtab/newTab.js new file mode 100644 index 000000000000..eb0f6d0139d5 --- /dev/null +++ b/browser/base/content/newtab/newTab.js @@ -0,0 +1,47 @@ +/* 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/. */ + +"use strict"; + +let Cu = Components.utils; +let Ci = Components.interfaces; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource:///modules/PageThumbs.jsm"); +Cu.import("resource:///modules/NewTabUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Rect", + "resource://gre/modules/Geometry.jsm"); + +let { + links: gLinks, + allPages: gAllPages, + pinnedLinks: gPinnedLinks, + blockedLinks: gBlockedLinks +} = NewTabUtils; + +XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() { + return Services.strings. + createBundle("chrome://browser/locale/newTab.properties"); +}); + +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 +#include drag.js +#include drop.js +#include dropTargetShim.js +#include dropPreview.js +#include updater.js diff --git a/browser/base/content/newtab/newTab.xul b/browser/base/content/newtab/newTab.xul new file mode 100644 index 000000000000..67c3b260f53b --- /dev/null +++ b/browser/base/content/newtab/newTab.xul @@ -0,0 +1,42 @@ + + +# 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/. + + + + + + + %newTabDTD; +]> + + + + +
+ + + +
+ +
    +
  • +
  • +
  • +
+ + + + gPage.init("#toolbar", "#grid"); + + +
+
diff --git a/browser/base/content/newtab/page.js b/browser/base/content/newtab/page.js new file mode 100644 index 000000000000..f6eb3428944f --- /dev/null +++ b/browser/base/content/newtab/page.js @@ -0,0 +1,173 @@ +#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 whole 'New Tab Page' and takes care of + * initializing all its components. + */ +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; + + // Add ourselves to the list of pages to receive notifications. + gAllPages.register(this); + + // Listen for 'unload' to unregister this page. + function unload() gAllPages.unregister(self); + addEventListener("unload", unload, false); + + // Check if the new tab feature is enabled. + if (gAllPages.enabled) + this._init(); + else + this._updateAttributes(false); + }, + + /** + * Listens for notifications specific to this page. + */ + observe: function Page_observe() { + let enabled = gAllPages.enabled; + this._updateAttributes(enabled); + + // Initialize the whole page if we haven't done that, yet. + if (enabled) + this._init(); + }, + + /** + * 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. + */ + _init: function Page_init() { + if (this._initialized) + return; + + this._initialized = true; + + let self = this; + + // Check if the grid is modified. + this.updateModifiedFlag(); + + // Initialize and render the grid. + gGrid.init(this._gridSelector); + + // Initialize the drop target shim. + gDropTargetShim.init(); + + // Workaround to prevent a delay on MacOSX due to a slow drop animation. + let doc = document.documentElement; + doc.addEventListener("dragover", this.onDragOver, false); + doc.addEventListener("drop", this.onDrop, false); + }, + + /** + * Updates the 'page-disabled' attributes of the respective DOM nodes. + * @param aValue Whether to set or remove attributes. + */ + _updateAttributes: function Page_updateAttributes(aValue) { + let nodes = document.querySelectorAll("#grid, #scrollbox, #toolbar, .toolbar-button"); + + // Set the nodes' states. + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i]; + if (aValue) + node.removeAttribute("page-disabled"); + else + node.setAttribute("page-disabled", "true"); + } + + this._updateTabIndices(aValue, this._isModified()); + }, + + /** + * Checks whether the page is modified. + * @return Whether the page is modified or not. + */ + _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)) + 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)) { + aEvent.preventDefault(); + aEvent.stopPropagation(); + } + } +}; diff --git a/browser/base/content/newtab/sites.js b/browser/base/content/newtab/sites.js new file mode 100644 index 000000000000..0ec6449c291c --- /dev/null +++ b/browser/base/content/newtab/sites.js @@ -0,0 +1,207 @@ +#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 class represents a site that is contained in a cell and can be pinned, + * moved around or deleted. + */ +function Site(aNode, aLink) { + this._node = aNode; + this._node._newtabSite = this; + + this._link = aLink; + + this._render(); + this._addEventHandlers(); +} + +Site.prototype = { + /** + * The site's DOM node. + */ + get node() this._node, + + /** + * The site's link. + */ + get link() this._link, + + /** + * The url of the site's link. + */ + get url() this.link.url, + + /** + * The title of the site's link. + */ + get title() this.link.title, + + /** + * The site's parent cell. + */ + get cell() { + let parentNode = this.node.parentNode; + return parentNode && parentNode._newtabCell; + }, + + /** + * Pins the site on its current or a given index. + * @param aIndex The pinned index (optional). + */ + pin: function Site_pin(aIndex) { + if (typeof aIndex == "undefined") + aIndex = this.cell.index; + + this._updateAttributes(true); + gPinnedLinks.pin(this._link, aIndex); + }, + + /** + * Unpins the site and calls the given callback when done. + * @param aCallback The callback to be called when finished. + */ + unpin: function Site_unpin(aCallback) { + if (this.isPinned()) { + this._updateAttributes(false); + gPinnedLinks.unpin(this._link); + gUpdater.updateGrid(aCallback); + } + }, + + /** + * Checks whether this site is pinned. + * @return Whether this site is pinned. + */ + isPinned: function Site_isPinned() { + return gPinnedLinks.isPinned(this._link); + }, + + /** + * Blocks the site (removes it from the grid) and calls the given callback + * when done. + * @param aCallback The callback to be called when finished. + */ + block: function Site_block(aCallback) { + gBlockedLinks.block(this._link); + gUpdater.updateGrid(aCallback); + gPage.updateModifiedFlag(); + }, + + /** + * Gets the DOM node specified by the given query selector. + * @param aSelector The query selector. + * @return The DOM node we found. + */ + _querySelector: function Site_querySelector(aSelector) { + return this.node.querySelector(aSelector); + }, + + /** + * Updates attributes for all nodes which status depends on this site being + * pinned or unpinned. + * @param aPinned Whether this site is now pinned or unpinned. + */ + _updateAttributes: function (aPinned) { + let buttonPin = this._querySelector(".strip-button-pin"); + + if (aPinned) { + this.node.setAttribute("pinned", true); + buttonPin.setAttribute("title", newTabString("unpin")); + } else { + this.node.removeAttribute("pinned"); + buttonPin.setAttribute("title", newTabString("pin")); + } + }, + + /** + * Renders the site's data (fills the HTML fragment). + */ + _render: function Site_render() { + this.node.setAttribute("href", this.url); + this._querySelector(".site-title").textContent = this.title || this.url; + + 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)); + }, + + /** + * Adds event handlers for the site and its buttons. + */ + _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); + + 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); + }, + + /** + * Event handler for the 'dragstart' event. + * @param aEvent The drag event. + */ + _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); + } +}; diff --git a/browser/base/content/newtab/toolbar.js b/browser/base/content/newtab/toolbar.js new file mode 100644 index 000000000000..a50bf0abc029 --- /dev/null +++ b/browser/base/content/newtab/toolbar.js @@ -0,0 +1,77 @@ +#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); + }, 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)); + }); + }); + }, + + /** + * 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(); + } +}; + diff --git a/browser/base/content/newtab/transformations.js b/browser/base/content/newtab/transformations.js new file mode 100644 index 000000000000..bd05076b782f --- /dev/null +++ b/browser/base/content/newtab/transformations.js @@ -0,0 +1,226 @@ +#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 allows to transform the grid by repositioning a site's node + * in the DOM and by showing or hiding the node. It additionally provides + * convenience methods to work with a site's DOM node. + */ +let gTransformation = { + /** + * Gets a DOM node's position. + * @param aNode The DOM node. + * @return A Rect instance with the position. + */ + getNodePosition: function Transformation_getNodePosition(aNode) { + let {left, top, width, height} = aNode.getBoundingClientRect(); + return new Rect(left + scrollX, top + scrollY, width, height); + }, + + /** + * Fades a given node from zero to full opacity. + * @param aNode The node to fade. + * @param aCallback The callback to call when finished. + */ + fadeNodeIn: function Transformation_fadeNodeIn(aNode, aCallback) { + this._setNodeOpacity(aNode, 1, function () { + // Clear the style property. + aNode.style.opacity = ""; + + if (aCallback) + aCallback(); + }); + }, + + /** + * Fades a given node from full to zero opacity. + * @param aNode The node to fade. + * @param aCallback The callback to call when finished. + */ + fadeNodeOut: function Transformation_fadeNodeOut(aNode, aCallback) { + this._setNodeOpacity(aNode, 0, aCallback); + }, + + /** + * Fades a given site from zero to full opacity. + * @param aSite The site to fade. + * @param aCallback The callback to call when finished. + */ + showSite: function Transformation_showSite(aSite, aCallback) { + this.fadeNodeIn(aSite.node, aCallback); + }, + + /** + * Fades a given site from full to zero opacity. + * @param aSite The site to fade. + * @param aCallback The callback to call when finished. + */ + hideSite: function Transformation_hideSite(aSite, aCallback) { + this.fadeNodeOut(aSite.node, aCallback); + }, + + /** + * Allows to set a site's position. + * @param aSite The site to re-position. + * @param aPosition The desired position for the given site. + */ + setSitePosition: function Transformation_setSitePosition(aSite, aPosition) { + let style = aSite.node.style; + let {top, left} = aPosition; + + style.top = top + "px"; + style.left = left + "px"; + }, + + /** + * Freezes a site in its current position by positioning it absolute. + * @param aSite The site to freeze. + */ + freezeSitePosition: function Transformation_freezeSitePosition(aSite) { + aSite.node.setAttribute("frozen", "true"); + this.setSitePosition(aSite, this.getNodePosition(aSite.node)); + }, + + /** + * Unfreezes a site by removing its absolute positioning. + * @param aSite The site to unfreeze. + */ + unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) { + let style = aSite.node.style; + style.left = style.top = ""; + aSite.node.removeAttribute("frozen"); + }, + + /** + * Slides the given site to the target node's position. + * @param aSite The site to move. + * @param aTarget The slide target. + * @param aOptions Set of options (see below). + * unfreeze - unfreeze the site after sliding + * callback - the callback to call when finished + */ + slideSiteTo: function Transformation_slideSiteTo(aSite, aTarget, aOptions) { + let currentPosition = this.getNodePosition(aSite.node); + let targetPosition = this.getNodePosition(aTarget.node) + let callback = aOptions && aOptions.callback; + + let self = this; + + function finish() { + if (aOptions && aOptions.unfreeze) + self.unfreezeSitePosition(aSite); + + if (callback) + callback(); + } + + // Nothing to do here if the positions already match. + if (currentPosition.equals(targetPosition)) { + finish(); + } else { + this.setSitePosition(aSite, targetPosition); + this._whenTransitionEnded(aSite.node, finish); + } + }, + + /** + * Rearranges a given array of sites and moves them to their new positions or + * fades in/out new/removed sites. + * @param aSites An array of sites to rearrange. + * @param aOptions Set of options (see below). + * unfreeze - unfreeze the site after rearranging + * callback - the callback to call when finished + */ + rearrangeSites: function Transformation_rearrangeSites(aSites, aOptions) { + let batch; + let cells = gGrid.cells; + let callback = aOptions && aOptions.callback; + let unfreeze = aOptions && aOptions.unfreeze; + + if (callback) { + batch = new Batch(callback); + callback = function () batch.pop(); + } + + aSites.forEach(function (aSite, aIndex) { + // Do not re-arrange empty cells or the dragged site. + if (!aSite || aSite == gDrag.draggedSite) + return; + + if (batch) + batch.push(); + + if (!cells[aIndex]) + // The site disappeared from the grid, hide it. + this.hideSite(aSite, callback); + else if (this._getNodeOpacity(aSite.node) != 1) + // The site disappeared before but is now back, show it. + this.showSite(aSite, callback); + else + // The site's position has changed, move it around. + this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: callback}); + }, this); + + if (batch) + batch.close(); + }, + + /** + * Listens for the 'transitionend' event on a given node and calls the given + * callback. + * @param aNode The node that is transitioned. + * @param aCallback The callback to call when finished. + */ + _whenTransitionEnded: + function Transformation_whenTransitionEnded(aNode, aCallback) { + + aNode.addEventListener("transitionend", function onEnd() { + aNode.removeEventListener("transitionend", onEnd, false); + aCallback(); + }, false); + }, + + /** + * Gets a given node's opacity value. + * @param aNode The node to get the opacity value from. + * @return The node's opacity value. + */ + _getNodeOpacity: function Transformation_getNodeOpacity(aNode) { + let cstyle = window.getComputedStyle(aNode, null); + return cstyle.getPropertyValue("opacity"); + }, + + /** + * Sets a given node's opacity. + * @param aNode The node to set the opacity value for. + * @param aOpacity The opacity value to set. + * @param aCallback The callback to call when finished. + */ + _setNodeOpacity: + function Transformation_setNodeOpacity(aNode, aOpacity, aCallback) { + + if (this._getNodeOpacity(aNode) == aOpacity) { + if (aCallback) + aCallback(); + } else { + if (aCallback) + this._whenTransitionEnded(aNode, aCallback); + + aNode.style.opacity = aOpacity; + } + }, + + /** + * Moves a site to the cell with the given index. + * @param aSite The site to move. + * @param aIndex The target cell's index. + * @param aOptions Options that are directly passed to slideSiteTo(). + */ + _moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) { + this.freezeSitePosition(aSite); + this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions); + } +}; diff --git a/browser/base/content/newtab/updater.js b/browser/base/content/newtab/updater.js new file mode 100644 index 000000000000..1b9310466346 --- /dev/null +++ b/browser/base/content/newtab/updater.js @@ -0,0 +1,182 @@ +#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 provides functionality to update the current grid to a new + * set of pinned and blocked sites. It adds, moves and removes sites. + */ +let gUpdater = { + /** + * Updates the current grid according to its pinned and blocked sites. + * This removes old, moves existing and creates new sites to fill gaps. + * @param aCallback The callback to call when finished. + */ + updateGrid: function Updater_updateGrid(aCallback) { + let links = gLinks.getLinks().slice(0, gGrid.cells.length); + + // Find all sites that remain in the grid. + let sites = this._findRemainingSites(links); + + let self = this; + + // Remove sites that are no longer in the grid. + this._removeLegacySites(sites, function () { + // Freeze all site positions so that we can move their DOM nodes around + // without any visual impact. + self._freezeSitePositions(sites); + + // Move the sites' DOM nodes to their new position in the DOM. This will + // have no visual effect as all the sites have been frozen and will + // remain in their current position. + self._moveSiteNodes(sites); + + // Now it's time to animate the sites actually moving to their new + // positions. + self._rearrangeSites(sites, function () { + // Try to fill empty cells and finish. + self._fillEmptyCells(links, aCallback); + + // Update other pages that might be open to keep them synced. + gAllPages.update(gPage); + }); + }); + }, + + /** + * Takes an array of links and tries to correlate them to sites contained in + * the current grid. If no corresponding site can be found (i.e. the link is + * new and a site will be created) then just set it to null. + * @param aLinks The array of links to find sites for. + * @return Array of sites mapped to the given links (can contain null values). + */ + _findRemainingSites: function Updater_findRemainingSites(aLinks) { + let map = {}; + + // Create a map to easily retrieve the site for a given URL. + gGrid.sites.forEach(function (aSite) { + if (aSite) + map[aSite.url] = aSite; + }); + + // Map each link to its corresponding site, if any. + return aLinks.map(function (aLink) { + return aLink && (aLink.url in map) && map[aLink.url]; + }); + }, + + /** + * Freezes the given sites' positions. + * @param aSites The array of sites to freeze. + */ + _freezeSitePositions: function Updater_freezeSitePositions(aSites) { + aSites.forEach(function (aSite) { + if (aSite) + gTransformation.freezeSitePosition(aSite); + }); + }, + + /** + * Moves the given sites' DOM nodes to their new positions. + * @param aSites The array of sites to move. + */ + _moveSiteNodes: function Updater_moveSiteNodes(aSites) { + let cells = gGrid.cells; + + // Truncate the given array of sites to not have more sites than cells. + // This can happen when the user drags a bookmark (or any other new kind + // of link) onto the grid. + let sites = aSites.slice(0, cells.length); + + sites.forEach(function (aSite, aIndex) { + let cell = cells[aIndex]; + let cellSite = cell.site; + + // The site's position didn't change. + if (!aSite || cellSite != aSite) { + let cellNode = cell.node; + + // Empty the cell if necessary. + if (cellSite) + cellNode.removeChild(cellSite.node); + + // Put the new site in place, if any. + if (aSite) + cellNode.appendChild(aSite.node); + } + }, this); + }, + + /** + * Rearranges the given sites and slides them to their new positions. + * @param aSites The array of sites to re-arrange. + * @param aCallback The callback to call when finished. + */ + _rearrangeSites: function Updater_rearrangeSites(aSites, aCallback) { + let options = {callback: aCallback, unfreeze: true}; + gTransformation.rearrangeSites(aSites, options); + }, + + /** + * Removes all sites from the grid that are not in the given links array or + * exceed the grid. + * @param aSites The array of sites remaining in the grid. + * @param aCallback The callback to call when finished. + */ + _removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) { + let batch = new Batch(aCallback); + + // Delete sites that were removed from the grid. + gGrid.sites.forEach(function (aSite) { + // The site must be valid and not in the current grid. + if (!aSite || aSites.indexOf(aSite) != -1) + return; + + batch.push(); + + // Fade out the to-be-removed site. + gTransformation.hideSite(aSite, function () { + let node = aSite.node; + + // Remove the site from the DOM. + node.parentNode.removeChild(node); + batch.pop(); + }); + }); + + batch.close(); + }, + + /** + * Tries to fill empty cells with new links if available. + * @param aLinks The array of links. + * @param aCallback The callback to call when finished. + */ + _fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) { + let {cells, sites} = gGrid; + let batch = new Batch(aCallback); + + // Find empty cells and fill them. + sites.forEach(function (aSite, aIndex) { + if (aSite || !aLinks[aIndex]) + return; + + batch.push(); + + // Create the new site and fade it in. + let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]); + + // Set the site's initial opacity to zero. + site.node.style.opacity = 0; + + // Without the setTimeout() the node would just appear instead of fade in. + setTimeout(function () { + gTransformation.showSite(site, function () batch.pop()); + }, 0); + }); + + batch.close(); + } +}; From 398f6dd2f0a936908b35f7a9de7019a37d5170a5 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Wed, 25 Jan 2012 23:42:15 +0100 Subject: [PATCH 08/24] Bug 455553 - Part 2 - Assets / CSS / Images; r=dao --- browser/base/content/newtab/newTab.css | 173 ++++++++++++++++++ browser/base/jar.mn | 3 + .../locales/en-US/chrome/browser/newTab.dtd | 6 + .../en-US/chrome/browser/newTab.properties | 3 + browser/locales/jar.mn | 2 + browser/themes/gnomestripe/jar.mn | 3 + browser/themes/gnomestripe/newtab/newTab.css | 144 +++++++++++++++ browser/themes/gnomestripe/newtab/strip.png | Bin 0 -> 2552 bytes browser/themes/gnomestripe/newtab/toolbar.png | Bin 0 -> 1538 bytes browser/themes/pinstripe/jar.mn | 3 + browser/themes/pinstripe/newtab/newTab.css | 143 +++++++++++++++ browser/themes/pinstripe/newtab/strip.png | Bin 0 -> 2552 bytes browser/themes/pinstripe/newtab/toolbar.png | Bin 0 -> 1568 bytes browser/themes/winstripe/jar.mn | 6 + browser/themes/winstripe/newtab/newTab.css | 144 +++++++++++++++ browser/themes/winstripe/newtab/strip.png | Bin 0 -> 2552 bytes browser/themes/winstripe/newtab/toolbar.png | Bin 0 -> 1704 bytes 17 files changed, 630 insertions(+) create mode 100644 browser/base/content/newtab/newTab.css create mode 100644 browser/locales/en-US/chrome/browser/newTab.dtd create mode 100644 browser/locales/en-US/chrome/browser/newTab.properties create mode 100644 browser/themes/gnomestripe/newtab/newTab.css create mode 100644 browser/themes/gnomestripe/newtab/strip.png create mode 100644 browser/themes/gnomestripe/newtab/toolbar.png create mode 100644 browser/themes/pinstripe/newtab/newTab.css create mode 100644 browser/themes/pinstripe/newtab/strip.png create mode 100644 browser/themes/pinstripe/newtab/toolbar.png create mode 100644 browser/themes/winstripe/newtab/newTab.css create mode 100644 browser/themes/winstripe/newtab/strip.png create mode 100644 browser/themes/winstripe/newtab/toolbar.png diff --git a/browser/base/content/newtab/newTab.css b/browser/base/content/newtab/newTab.css new file mode 100644 index 000000000000..c1d954c00baf --- /dev/null +++ b/browser/base/content/newtab/newTab.css @@ -0,0 +1,173 @@ +:root { + -moz-appearance: none; +} + +#scrollbox:not([page-disabled]) { + overflow: auto; +} + +#body { + position: relative; + margin: 0; + min-width: 675px; + -moz-user-select: none; +} + +.button { + cursor: pointer; +} + +/* TOOLBAR */ +#toolbar { + position: absolute; +} + +#toolbar[page-disabled] { + position: fixed; +} + +#toolbar:-moz-locale-dir(rtl) { + left: 8px; + right: auto; +} + +.toolbar-button { + position: absolute; + cursor: pointer; + -moz-transition: opacity 200ms ease-out; +} + +#toolbar-button-show, +#toolbar-button-reset { + opacity: 0; + pointer-events: none; +} + +#toolbar-button-reset[modified], +#toolbar-button-show[page-disabled] { + opacity: 1; + pointer-events: auto; +} + +#toolbar-button-hide[page-disabled], +#toolbar-button-reset[page-disabled] { + opacity: 0; + pointer-events: none; +} + +/* GRID */ +#grid { + width: 637px; + height: 411px; + overflow: hidden; + list-style-type: none; + -moz-transition: opacity 200ms ease-out; +} + +#grid[page-disabled] { + opacity: 0; +} + +#grid[page-disabled], +#grid[locked] { + pointer-events: none; +} + +/* 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; +} + +/* SITES */ +.site { + display: block; + position: relative; + width: 201px; + height: 127px; +} + +.site[frozen] { + position: absolute; + pointer-events: none; +} + +.site[ontop] { + 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 { + position: absolute; + left: 0; + top: 0; + width: 195px; + height: 17px; + overflow: hidden; + opacity: 0; + -moz-transition: opacity 200ms ease-out; +} + +.site:hover:not([frozen]) > .site-strip { + opacity: 1; +} + +.strip-button-pin, +.strip-button-block:-moz-locale-dir(rtl) { + float: left; +} + +.strip-button-block, +.strip-button-pin:-moz-locale-dir(rtl) { + float: right; +} + +/* DRAG & DROP */ + +/* + * This is just a temporary drag element used for dataTransfer.setDragImage() + * 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 { + width: 1px; + height: 1px; + background-color: #fff; + opacity: 0.01; +} diff --git a/browser/base/jar.mn b/browser/base/jar.mn index 1986b93f3bde..4581a87c0c40 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -31,6 +31,9 @@ browser.jar: * content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml) * content/browser/content.js (content/content.js) * content/browser/fullscreen-video.xhtml (content/fullscreen-video.xhtml) +* content/browser/newtab/newTab.xul (content/newtab/newTab.xul) +* content/browser/newtab/newTab.js (content/newtab/newTab.js) + content/browser/newtab/newTab.css (content/newtab/newTab.css) * content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul) * content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js) * content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css) diff --git a/browser/locales/en-US/chrome/browser/newTab.dtd b/browser/locales/en-US/chrome/browser/newTab.dtd new file mode 100644 index 000000000000..0232edfd66e3 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/newTab.dtd @@ -0,0 +1,6 @@ + + + + + + diff --git a/browser/locales/en-US/chrome/browser/newTab.properties b/browser/locales/en-US/chrome/browser/newTab.properties new file mode 100644 index 000000000000..9423af6fc71d --- /dev/null +++ b/browser/locales/en-US/chrome/browser/newTab.properties @@ -0,0 +1,3 @@ +newtab.pin=Pin this site at its current position +newtab.unpin=Unpin this site +newtab.block=Remove this site diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index 1346638ed1a2..70f90245bf89 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -28,6 +28,8 @@ locale/browser/devtools/styleinspector.dtd (%chrome/browser/devtools/styleinspector.dtd) locale/browser/devtools/webConsole.dtd (%chrome/browser/devtools/webConsole.dtd) locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties) + locale/browser/newTab.dtd (%chrome/browser/newTab.dtd) + locale/browser/newTab.properties (%chrome/browser/newTab.properties) locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd) locale/browser/openLocation.properties (%chrome/browser/openLocation.properties) * locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd) diff --git a/browser/themes/gnomestripe/jar.mn b/browser/themes/gnomestripe/jar.mn index c144ecd87ad1..87ba7071ae69 100644 --- a/browser/themes/gnomestripe/jar.mn +++ b/browser/themes/gnomestripe/jar.mn @@ -45,6 +45,9 @@ browser.jar: skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png) 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/places/bookmarksMenu.png (places/bookmarksMenu.png) skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png) skin/classic/browser/places/calendar.png (places/calendar.png) diff --git a/browser/themes/gnomestripe/newtab/newTab.css b/browser/themes/gnomestripe/newtab/newTab.css new file mode 100644 index 000000000000..2df64addbdd5 --- /dev/null +++ b/browser/themes/gnomestripe/newtab/newTab.css @@ -0,0 +1,144 @@ +#scrollbox { + padding-bottom: 18px; + background-color: #fff; +} + +#body { + padding-top: 106px; + font-family: sans-serif; +} + +.button { + padding: 0; + border: 0 none; +} + +/* TOOLBAR */ +#toolbar { + top: 8px; + right: 8px; + width: 13px; + height: 30px; + padding: 0; + margin: 0; +} + +.toolbar-button { + background: transparent url(chrome://browser/skin/newtab/toolbar.png); +} + +#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; +} + +/* 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.8); + border: solid transparent; + border-width: 6px 0; + color: #fff; + text-decoration: none; + line-height: 1.2em; + font-weight: 700; +} + +/* SITE STRIP */ +.site-strip { + padding: 3px; + border: solid rgba(30,30,30,0.8); + border-width: 1px 0; + background-color: rgba(0,0,0,0.8); +} + +.strip-button { + width: 17px; + height: 17px; + background: transparent url(chrome://browser/skin/newtab/strip.png); +} + +.strip-button-pin:hover { + background-position: 0 -17px; +} + +.strip-button-pin:active, +.site[pinned] .strip-button-pin { + background-position: 0 -34px; +} + +.strip-button-block { + background-position: -17px 0; +} + +.strip-button-block:hover { + background-position: -17px -17px; +} + +.strip-button-block:active { + background-position: -17px -34px; +} diff --git a/browser/themes/gnomestripe/newtab/strip.png b/browser/themes/gnomestripe/newtab/strip.png new file mode 100644 index 0000000000000000000000000000000000000000..2527df6e72b5c80b91e180af9644ba96a5c148d6 GIT binary patch literal 2552 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 O0000 literal 0 HcmV?d00001 diff --git a/browser/themes/gnomestripe/newtab/toolbar.png b/browser/themes/gnomestripe/newtab/toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..389f689aa2a7611f53977594c048f79c4991affd GIT binary patch literal 1538 zcmV+d2L1VoP)Px#32;bRa{vGf6951U69E94oEQKA1*b_wK~z}7z1Lk#Q)e8<@o%-;l_RE+GhM_8 z&Z*1|BRcVpq)WWhXf)~+B`Co`d;xW!BVJ5kIGwy`!52``xw)t_CD}4`B+G6vOo(iX zAqGoCN3E_gn~4eZ{GVOW9(rnfS}x{EPSW4gp8lWbJkL3wb8G-7F1F?XH@0n9?j>wH zak13_tlYL?d9&;MH5FH^6-f+R4E27QdCfxE%t1Hjgud28D1&Ros{egobxbpYV#=}Y0AAXL00f1L-Qw)uNwh`Y9|wOM7Q z)V<(H2a30@OAWQxG+pWdvcfxS4}H+}z%cM4?7J7iGXa2zm_})pm8kcEAJ>Q4zCQVF zhvZnhn2Xi>4U9?<^)J_ODIDUn61>d!d#@5u85OeinTZxkiFMTt=ypu9NW zD@w9O$-eU9{AwjaXb+w8SXqhWDG{YardQTBJ+7>6S_M#9+qAK=wrNO-JgKa0sxa2T zfs%rw(N52Sk^(PKoyc_`op*5&n|~4!mtEXE`XAO7=#phuy4ix%pPo8_VP(EA zv?37}=n?mUh@ASPuT%vBiCK{99hx`$$0F!Rb_R0{@H zr+9+j8*@CcI>ly{1q=%wu1+y5m~mw=wgqZ<#L@y4h?$%4Vc3=cp`LyyUVl%~6e1%q4Px1}`QRk89&91EtNyyNf|%pbL2urQ-h z>H2P^>qc>a!NLr$()Dbm>-z=^GpY&b7&~B?j+#fHG{)eRnN+ipU5|ahm@%v6-7$s&4BHjy75%@&p0~#$`crecvkJJUVE@5knNXS&TQiyE`w*{*cMf+@AV zu`NK?EiD+&^FTBU97q4`5YeMspdGpGK%&1FXh&{4eR~#o literal 0 HcmV?d00001 diff --git a/browser/themes/pinstripe/jar.mn b/browser/themes/pinstripe/jar.mn index 7ee87a5ed72f..8b1167eb24f3 100644 --- a/browser/themes/pinstripe/jar.mn +++ b/browser/themes/pinstripe/jar.mn @@ -55,6 +55,9 @@ browser.jar: skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png) 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/setDesktopBackground.css skin/classic/browser/inspector.css skin/classic/browser/monitor.png diff --git a/browser/themes/pinstripe/newtab/newTab.css b/browser/themes/pinstripe/newtab/newTab.css new file mode 100644 index 000000000000..4785675f7180 --- /dev/null +++ b/browser/themes/pinstripe/newtab/newTab.css @@ -0,0 +1,143 @@ +#scrollbox { + padding-bottom: 18px; + background-color: #fff; +} + +#body { + padding-top: 106px; + font-family: sans-serif; +} + +.button { + padding: 0; + border: 0 none; +} + +/* TOOLBAR */ +#toolbar { + top: 8px; + right: 8px; + width: 13px; + height: 30px; + padding: 0; + margin: 0; +} + +.toolbar-button { + background: transparent url(chrome://browser/skin/newtab/toolbar.png); +} + +#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; +} + +/* 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.8); + border: solid transparent; + border-width: 6px 0; + color: #fff; + text-decoration: none; + line-height: 1.2em; + font-weight: 700; +} + +/* SITE STRIP */ +.site-strip { + padding: 3px; + border: solid rgba(30,30,30,0.8); + border-width: 1px 0; + background-color: rgba(0,0,0,0.8); +} + +.strip-button { + width: 17px; + height: 17px; + background: transparent url(chrome://browser/skin/newtab/strip.png); +} + +.strip-button-pin:hover { + background-position: 0 -17px; +} + +.strip-button-pin:active, +.site[pinned] .strip-button-pin { + background-position: 0 -34px; +} + +.strip-button-block { + background-position: -17px 0; +} + +.strip-button-block:hover { + background-position: -17px -17px; +} + +.strip-button-block:active { + background-position: -17px -34px; +} diff --git a/browser/themes/pinstripe/newtab/strip.png b/browser/themes/pinstripe/newtab/strip.png new file mode 100644 index 0000000000000000000000000000000000000000..2527df6e72b5c80b91e180af9644ba96a5c148d6 GIT binary patch literal 2552 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 O0000 literal 0 HcmV?d00001 diff --git a/browser/themes/pinstripe/newtab/toolbar.png b/browser/themes/pinstripe/newtab/toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0 GIT binary patch literal 1568 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 O0000 literal 0 HcmV?d00001 diff --git a/browser/themes/winstripe/newtab/toolbar.png b/browser/themes/winstripe/newtab/toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..33bb4a320e76cc7a346ca4beb60e89a85a48aa2c GIT binary patch literal 1704 zcmV;Z23PrsP)Px#32;bRa{vGf6951U69E94oEQKA22DvsK~z}7y_bJ%Q`Z&8Kd#bFNHprK+M`uL zwCfKgT{N16NmNLrGYB?Ip_!c0EebG0NZU+=gtZGSrP4|gQ#5dB9ZH&nrHpnf9i5{E zEtE(_s#capf#4BfqYIE`cnoE*QH9#?p1VJIezAk|V*XgKbR~c9_0>7|-1F||9tXgi z`@71451%V5j*`^g+~4H{N}ek#ZV$cvfliE9tt@d&r^%r0{&l!1t7Tt!wTRve47KbF zdtNAC9tCLG7j}y1!$3jHzVJ*Dm9kiCZL0x7Z-3wdnt&3(37iFv0`Y1zbP`E$TjCK z0!6hI&kh3w+kb0qal@Jw4m&NPS`)@=);?R7H2!?DamxV!rHmMGJ!$T`83}W-r0mj8 zYtdfw=cdHiFZaCDBueTgM=J{;5bAU)m2&3eiJS<8Iz4q&tD<_6K|3uXE~~jIk9?MOJ`GJ(a&C3<=EEJsi)G)P;US~F+ai5$wnJ@bT4>ZqNPZ*Y^txR2xt)!JrVM$v=#|yk!xDS*AQ$w*br>X184}g6*L6f z!dm1^L$Iyb%7HDll{?afXG?8m6bNMU-6!jxZ&*9}>dw|50AceIDtUEhE26DDxdx0` z_rU+F{bI+SIY2G2%*=_8flq+eEwz=SmIHd-x-y{G(b}4lXnNf`r`(~Reqzg?_g;^D zWV!$MrB25~J!9HVXX4<)N3J$y#r*!2al>c>PRIQIrFV67L;+%czcX$ahqQzIzLyJU z=K4}UJ7gLSJk&F0&jKZNS+RKhFz{C(2k5z8UcMBF#p3ZpK)!Y`^2OKGAGDI@l<25Q z_rN6mVE5%E+AuO>!Ifv8nFSmH9tBRD_dq@{61!6`Ubg-0g_HN6luXZlZurtIEI7aX zzH@WKm(sJ~-uK>%e!hJ9V$+Enb8ZCid_OpR0dUNHf5bZD^S;@(TH=Pqf{VV{Wl7^x zvtazjjdU!yVTIV3^d7L$qHkrv1MdzuN!&=!f|Er>&han5Jd_B#c?3B?PsfkHzRbV( z-~YrgQdin&E!qXB(Up%_EcpC~52j~9-+~2BAlbOb-1!mUQSIRL7kBILeYfY>KQhgM z``S-iEV#5L$DReTc)T>(_`?4F^8g*3W%Yu ziJ^S%(BMILXfO}J9U3ffhX%u9s59=+-~_vW|Pbs|}_00z=2WUe6QV-BEz!Ua!+IpJ~Uv-kD1$zx$`tfIIY= zEeo_rU6xX*bwU5KWgZ|l>5bThmf)mEAa>gI`rnr5OzVO_c|5jt!IQncw^bLocAdS2 z1^-(A*g4m(v*}szWN&Zu=%Phw>w-l`j}8O4n};UOxH{Kir<3b~D;sjlCW2&B7sO&Q z+qz&{{wF`n)3Cs~Bhn1Cz^V%_znJfE zZy(T8>6j8*7Tgo)pK-OW@Foj y^;ilEvbP>fPSmf41$S@#WJ(tNw|>DW!2ba3q~P6d-#~K!0000 Date: Wed, 25 Jan 2012 23:43:27 +0100 Subject: [PATCH 09/24] Bug 455553 - Part 3 - about:newtab integration; r=fryn,gavin --- .../tests/mochitest/events/docload_wnd.xul | 2 ++ .../tests/mochitest/events/test_scroll.xul | 2 ++ .../tests/mochitest/name/nsRootAcc_wnd.xul | 3 +++ .../mochitest/relations/test_tabbrowser.xul | 2 ++ .../tests/mochitest/tree/test_tabbrowser.xul | 2 ++ browser/app/profile/firefox.js | 6 +++++ browser/base/content/browser-fullZoom.js | 2 +- browser/base/content/browser-places.js | 2 +- browser/base/content/browser.js | 23 ++++++++++++------- browser/base/content/tabbrowser.xml | 6 ++--- browser/base/content/utilityOverlay.js | 14 ++++++++++- browser/components/about/AboutRedirector.cpp | 2 ++ browser/components/build/nsModule.cpp | 1 + 13 files changed, 53 insertions(+), 14 deletions(-) diff --git a/accessible/tests/mochitest/events/docload_wnd.xul b/accessible/tests/mochitest/events/docload_wnd.xul index b64820c40791..537a618e386c 100644 --- a/accessible/tests/mochitest/events/docload_wnd.xul +++ b/accessible/tests/mochitest/events/docload_wnd.xul @@ -12,6 +12,8 @@