2010-06-16 17:19:11 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is tabitems.js.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
2010-08-11 15:28:45 -07:00
|
|
|
* the Mozilla Foundation.
|
2010-06-16 17:19:11 -07:00
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2010-08-11 15:28:45 -07:00
|
|
|
* Ian Gilman <ian@iangilman.com>
|
2010-06-16 17:19:11 -07:00
|
|
|
* Aza Raskin <aza@mozilla.com>
|
|
|
|
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
|
|
|
* Ehsan Akhgari <ehsan@mozilla.com>
|
2010-06-23 02:25:34 -07:00
|
|
|
* Raymond Lee <raymond@appcoast.com>
|
2010-06-16 17:19:11 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
// **********
|
|
|
|
// Title: tabitems.js
|
2010-05-11 17:22:06 -07:00
|
|
|
|
2010-03-29 11:55:13 -07:00
|
|
|
// ##########
|
2010-05-13 17:24:37 -07:00
|
|
|
// Class: TabItem
|
2010-07-27 20:02:51 -07:00
|
|
|
// An <Item> that represents a tab. Also implements the <Subscribable> interface.
|
|
|
|
//
|
|
|
|
// Parameters:
|
|
|
|
// tab - a xul:tab
|
2010-09-08 10:02:08 -07:00
|
|
|
function TabItem(tab) {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assert(tab, "tab");
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
this.tab = tab;
|
|
|
|
// register this as the tab's tabItem
|
|
|
|
this.tab.tabItem = this;
|
|
|
|
|
|
|
|
// ___ set up div
|
|
|
|
var $div = iQ('<div>')
|
|
|
|
.addClass('tab')
|
2010-09-08 16:47:58 -07:00
|
|
|
.html("<div class='thumb'>" +
|
2010-07-27 20:02:51 -07:00
|
|
|
"<img class='cached-thumb' style='display:none'/><canvas/></div>" +
|
|
|
|
"<div class='favicon'><img/></div>" +
|
|
|
|
"<span class='tab-title'> </span>"
|
|
|
|
)
|
|
|
|
.appendTo('body');
|
|
|
|
|
|
|
|
this.canvasSizeForced = false;
|
|
|
|
this.isShowingCachedData = false;
|
2010-07-28 22:02:26 -07:00
|
|
|
this.favEl = (iQ('.favicon>img', $div))[0];
|
|
|
|
this.nameEl = (iQ('.tab-title', $div))[0];
|
|
|
|
this.canvasEl = (iQ('.thumb canvas', $div))[0];
|
|
|
|
this.cachedThumbEl = (iQ('img.cached-thumb', $div))[0];
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
this.tabCanvas = new TabCanvas(this.tab, this.canvasEl);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-04-30 17:24:03 -07:00
|
|
|
this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
|
2010-05-11 12:03:31 -07:00
|
|
|
this.locked = {};
|
2010-06-14 15:43:02 -07:00
|
|
|
this.isATabItem = true;
|
|
|
|
this._zoomPrep = false;
|
|
|
|
this.sizeExtra = new Point();
|
2010-06-19 17:45:23 -07:00
|
|
|
this.keepProportional = true;
|
2010-05-11 12:03:31 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
var self = this;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-19 11:56:07 -07:00
|
|
|
this.isDragging = false;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
this.sizeExtra.x = parseInt($div.css('padding-left'))
|
2010-06-28 16:11:22 -07:00
|
|
|
+ parseInt($div.css('padding-right'));
|
|
|
|
|
2010-07-18 08:58:10 -07:00
|
|
|
this.sizeExtra.y = parseInt($div.css('padding-top'))
|
2010-06-28 16:11:22 -07:00
|
|
|
+ parseInt($div.css('padding-bottom'));
|
|
|
|
|
|
|
|
this.bounds = $div.bounds();
|
2010-08-10 11:39:28 -07:00
|
|
|
|
2010-06-15 14:38:55 -07:00
|
|
|
// ___ superclass setup
|
2010-07-28 22:02:26 -07:00
|
|
|
this._init($div[0]);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-15 16:33:58 -07:00
|
|
|
// ___ drag/drop
|
2010-06-15 14:38:55 -07:00
|
|
|
// override dropOptions with custom tabitem methods
|
2010-08-06 15:46:55 -07:00
|
|
|
// This is mostly to support the phantom groupItems.
|
2010-07-30 02:54:30 -07:00
|
|
|
this.dropOptions.drop = function(e) {
|
2010-07-18 08:58:10 -07:00
|
|
|
var $target = iQ(this.container);
|
2010-07-17 22:03:31 -07:00
|
|
|
this.isDropTarget = false;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-08-06 15:46:55 -07:00
|
|
|
var phantom = $target.data("phantomGroupItem");
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-08-06 15:46:55 -07:00
|
|
|
var groupItem = drag.info.item.parent;
|
|
|
|
if (groupItem) {
|
|
|
|
groupItem.add(drag.info.$el);
|
2010-07-17 22:03:31 -07:00
|
|
|
} else {
|
|
|
|
phantom.removeClass("phantom acceptsDrop");
|
2010-08-06 15:46:55 -07:00
|
|
|
new GroupItem([$target, drag.info.$el], {container:phantom, bounds:phantom.bounds()});
|
2010-07-17 22:03:31 -07:00
|
|
|
}
|
2010-06-19 12:05:36 -07:00
|
|
|
};
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-30 02:54:30 -07:00
|
|
|
this.dropOptions.over = function(e) {
|
2010-06-22 16:42:06 -07:00
|
|
|
var $target = iQ(this.container);
|
2010-07-17 22:03:31 -07:00
|
|
|
this.isDropTarget = true;
|
2010-06-15 14:38:55 -07:00
|
|
|
|
2010-07-17 22:03:31 -07:00
|
|
|
$target.removeClass("acceptsDrop");
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 20:40:25 -07:00
|
|
|
var phantomMargin = 40;
|
|
|
|
|
2010-08-06 15:46:55 -07:00
|
|
|
var groupItemBounds = this.getBoundsWithTitle();
|
|
|
|
groupItemBounds.inset(-phantomMargin, -phantomMargin);
|
2010-06-15 14:38:55 -07:00
|
|
|
|
2010-06-19 12:05:36 -07:00
|
|
|
iQ(".phantom").remove();
|
|
|
|
var phantom = iQ("<div>")
|
2010-08-06 15:46:55 -07:00
|
|
|
.addClass("groupItem phantom acceptsDrop")
|
2010-06-19 12:05:36 -07:00
|
|
|
.css({
|
2010-07-03 18:13:31 -07:00
|
|
|
position: "absolute",
|
2010-06-19 12:05:36 -07:00
|
|
|
zIndex: -99
|
|
|
|
})
|
2010-08-06 15:46:55 -07:00
|
|
|
.css(groupItemBounds.css())
|
2010-06-19 12:05:36 -07:00
|
|
|
.hide()
|
2010-07-17 22:03:31 -07:00
|
|
|
.appendTo("body");
|
|
|
|
|
2010-07-22 20:40:25 -07:00
|
|
|
var defaultRadius = Trenches.defaultRadius;
|
|
|
|
// Extend the margin so that it covers the case where the target tab item
|
|
|
|
// is right next to a trench.
|
|
|
|
Trenches.defaultRadius = phantomMargin + 1;
|
2010-08-06 15:46:55 -07:00
|
|
|
var updatedBounds = drag.info.snapBounds(groupItemBounds,'none');
|
2010-07-22 20:40:25 -07:00
|
|
|
Trenches.defaultRadius = defaultRadius;
|
2010-07-17 22:03:31 -07:00
|
|
|
|
|
|
|
// Utils.log('updatedBounds:',updatedBounds);
|
|
|
|
if (updatedBounds)
|
|
|
|
phantom.css(updatedBounds.css());
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-17 22:03:31 -07:00
|
|
|
phantom.fadeIn();
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-08-06 15:46:55 -07:00
|
|
|
$target.data("phantomGroupItem", phantom);
|
2010-06-19 12:05:36 -07:00
|
|
|
};
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-30 02:54:30 -07:00
|
|
|
this.dropOptions.out = function(e) {
|
2010-07-17 22:03:31 -07:00
|
|
|
this.isDropTarget = false;
|
2010-08-06 15:46:55 -07:00
|
|
|
var phantom = iQ(this.container).data("phantomGroupItem");
|
2010-07-18 08:58:10 -07:00
|
|
|
if (phantom) {
|
2010-07-30 02:54:30 -07:00
|
|
|
phantom.fadeOut(function() {
|
2010-06-19 12:05:36 -07:00
|
|
|
iQ(this).remove();
|
|
|
|
});
|
|
|
|
}
|
2010-06-22 16:42:06 -07:00
|
|
|
};
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-22 16:42:06 -07:00
|
|
|
this.draggable();
|
2010-09-04 12:15:31 -07:00
|
|
|
this.droppable(true);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-15 16:33:58 -07:00
|
|
|
// ___ more div setup
|
2010-06-14 15:43:02 -07:00
|
|
|
$div.mousedown(function(e) {
|
2010-07-11 17:54:42 -07:00
|
|
|
if (!Utils.isRightClick(e))
|
2010-06-14 15:43:02 -07:00
|
|
|
self.lastMouseDownTarget = e.target;
|
|
|
|
});
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
$div.mouseup(function(e) {
|
|
|
|
var same = (e.target == self.lastMouseDownTarget);
|
|
|
|
self.lastMouseDownTarget = null;
|
2010-07-11 17:54:42 -07:00
|
|
|
if (!same)
|
2010-06-14 15:43:02 -07:00
|
|
|
return;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
if (iQ(e.target).hasClass("close"))
|
2010-08-10 11:39:28 -07:00
|
|
|
self.close();
|
2010-06-14 15:43:02 -07:00
|
|
|
else {
|
2010-07-18 08:58:10 -07:00
|
|
|
if (!Items.item(this).isDragging)
|
2010-06-14 15:43:02 -07:00
|
|
|
self.zoomIn();
|
|
|
|
}
|
|
|
|
});
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
iQ("<div>")
|
|
|
|
.addClass('close')
|
2010-07-18 08:58:10 -07:00
|
|
|
.appendTo($div);
|
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
iQ("<div>")
|
|
|
|
.addClass('expander')
|
|
|
|
.appendTo($div);
|
|
|
|
|
2010-09-04 12:15:31 -07:00
|
|
|
// ___ additional setup
|
|
|
|
this.reconnected = false;
|
|
|
|
this._hasBeenDrawn = false;
|
|
|
|
this.setResizable(true);
|
|
|
|
|
2010-06-28 16:11:22 -07:00
|
|
|
this._updateDebugBounds();
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-18 17:08:45 -07:00
|
|
|
TabItems.register(this);
|
2010-09-04 12:15:31 -07:00
|
|
|
|
|
|
|
if (!TabItems.reconnect(this))
|
|
|
|
GroupItems.newTab(this);
|
2010-03-29 11:55:13 -07:00
|
|
|
};
|
|
|
|
|
2010-09-08 10:02:08 -07:00
|
|
|
TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
2010-07-27 20:02:51 -07:00
|
|
|
// ----------
|
|
|
|
// Function: forceCanvasSize
|
|
|
|
// Repaints the thumbnail with the given resolution, and forces it
|
|
|
|
// to stay that resolution until unforceCanvasSize is called.
|
2010-09-08 10:02:08 -07:00
|
|
|
forceCanvasSize: function TabItem_forceCanvasSize(w, h) {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.canvasSizeForced = true;
|
|
|
|
this.canvasEl.width = w;
|
|
|
|
this.canvasEl.height = h;
|
|
|
|
this.tabCanvas.paint();
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: unforceCanvasSize
|
|
|
|
// Stops holding the thumbnail resolution; allows it to shift to the
|
|
|
|
// size of thumbnail on screen. Note that this call does not nest, unlike
|
|
|
|
// <TabItems.resumePainting>; if you call forceCanvasSize multiple
|
|
|
|
// times, you just need a single unforce to clear them all.
|
2010-09-08 10:02:08 -07:00
|
|
|
unforceCanvasSize: function TabItem_unforceCanvasSize() {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.canvasSizeForced = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: showCachedData
|
|
|
|
// Shows the cached data i.e. image and title. Note: this method should only
|
|
|
|
// be called at browser startup with the cached data avaliable.
|
2010-09-08 10:02:08 -07:00
|
|
|
showCachedData: function TabItem_showCachedData(tabData) {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.isShowingCachedData = true;
|
|
|
|
var $nameElement = iQ(this.nameEl);
|
|
|
|
var $canvasElement = iQ(this.canvasEl);
|
|
|
|
var $cachedThumbElement = iQ(this.cachedThumbEl);
|
|
|
|
$cachedThumbElement.attr("src", tabData.imageData).show();
|
|
|
|
$canvasElement.css({opacity: 0.0});
|
|
|
|
$nameElement.text(tabData.title ? tabData.title : "");
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: hideCachedData
|
|
|
|
// Hides the cached data i.e. image and title and show the canvas.
|
2010-09-08 10:02:08 -07:00
|
|
|
hideCachedData: function TabItem_hideCachedData() {
|
2010-07-27 20:02:51 -07:00
|
|
|
var $canvasElement = iQ(this.canvasEl);
|
|
|
|
var $cachedThumbElement = iQ(this.cachedThumbEl);
|
|
|
|
$cachedThumbElement.hide();
|
|
|
|
$canvasElement.css({opacity: 1.0});
|
2010-07-29 14:45:08 -07:00
|
|
|
this.isShowingCachedData = false;
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
2010-07-18 08:58:10 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: getStorageData
|
2010-07-18 08:58:10 -07:00
|
|
|
// Get data to be used for persistent storage of this object.
|
|
|
|
//
|
|
|
|
// Parameters:
|
2010-07-16 17:27:01 -07:00
|
|
|
// getImageData - true to include thumbnail pixels (and page title as well); default false
|
2010-09-08 10:02:08 -07:00
|
|
|
getStorageData: function TabItem_getStorageData(getImageData) {
|
2010-04-23 17:11:06 -07:00
|
|
|
return {
|
2010-07-18 08:58:10 -07:00
|
|
|
bounds: this.getBounds(),
|
2010-07-22 12:46:51 -07:00
|
|
|
userSize: (Utils.isPoint(this.userSize) ? new Point(this.userSize) : null),
|
2010-07-22 15:09:36 -07:00
|
|
|
url: this.tab.linkedBrowser.currentURI.spec,
|
2010-07-14 19:40:46 -07:00
|
|
|
groupID: (this.parent ? this.parent.id : 0),
|
2010-07-27 20:02:51 -07:00
|
|
|
imageData: (getImageData && this.tabCanvas ?
|
|
|
|
this.tabCanvas.toImageData() : null),
|
2010-07-22 15:09:36 -07:00
|
|
|
title: getImageData && this.tab.label || null
|
2010-04-23 17:11:06 -07:00
|
|
|
};
|
|
|
|
},
|
2010-05-21 15:44:15 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: save
|
2010-07-18 08:58:10 -07:00
|
|
|
// Store persistent for this object.
|
|
|
|
//
|
|
|
|
// Parameters:
|
2010-07-16 17:27:01 -07:00
|
|
|
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
2010-09-08 10:02:08 -07:00
|
|
|
save: function TabItem_save(saveImageData) {
|
2010-05-21 15:44:15 -07:00
|
|
|
try{
|
2010-07-24 16:28:17 -07:00
|
|
|
if (!this.tab || this.tab.parentNode == null || !this.reconnected) // too soon/late to save
|
2010-05-21 15:44:15 -07:00
|
|
|
return;
|
2010-05-24 14:49:03 -07:00
|
|
|
|
2010-07-14 19:40:46 -07:00
|
|
|
var data = this.getStorageData(saveImageData);
|
2010-07-11 17:54:42 -07:00
|
|
|
if (TabItems.storageSanity(data))
|
2010-07-22 15:09:36 -07:00
|
|
|
Storage.saveTab(this.tab, data);
|
2010-07-30 02:54:30 -07:00
|
|
|
} catch(e) {
|
2010-05-21 15:44:15 -07:00
|
|
|
Utils.log("Error in saving tab value: "+e);
|
|
|
|
}
|
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: setBounds
|
2010-07-18 08:58:10 -07:00
|
|
|
// Moves this item to the specified location and size.
|
|
|
|
//
|
|
|
|
// Parameters:
|
2010-07-16 17:27:01 -07:00
|
|
|
// rect - a <Rect> giving the new bounds
|
|
|
|
// immediately - true if it should not animate; default false
|
|
|
|
// options - an object with additional parameters, see below
|
2010-07-18 08:58:10 -07:00
|
|
|
//
|
|
|
|
// Possible options:
|
2010-07-16 17:27:01 -07:00
|
|
|
// force - true to always update the DOM even if the bounds haven't changed; default false
|
2010-09-08 10:02:08 -07:00
|
|
|
setBounds: function TabItem_setBounds(rect, immediately, options) {
|
2010-07-22 12:46:51 -07:00
|
|
|
if (!Utils.isRect(rect)) {
|
2010-05-11 17:22:06 -07:00
|
|
|
Utils.trace('TabItem.setBounds: rect is not a real rectangle!', rect);
|
|
|
|
return;
|
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (!options)
|
2010-06-14 15:43:02 -07:00
|
|
|
options = {};
|
2010-06-15 16:08:21 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (this._zoomPrep)
|
2010-06-14 15:43:02 -07:00
|
|
|
this.bounds.copy(rect);
|
|
|
|
else {
|
|
|
|
var $container = iQ(this.container);
|
|
|
|
var $title = iQ('.tab-title', $container);
|
|
|
|
var $thumb = iQ('.thumb', $container);
|
|
|
|
var $close = iQ('.close', $container);
|
2010-06-24 23:59:32 -07:00
|
|
|
var $fav = iQ('.favicon', $container);
|
2010-06-14 15:43:02 -07:00
|
|
|
var css = {};
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 21:35:07 -07:00
|
|
|
const fontSizeRange = new Range(8,15);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (rect.left != this.bounds.left || options.force)
|
2010-06-14 15:43:02 -07:00
|
|
|
css.left = rect.left;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (rect.top != this.bounds.top || options.force)
|
2010-06-14 15:43:02 -07:00
|
|
|
css.top = rect.top;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (rect.width != this.bounds.width || options.force) {
|
2010-06-15 15:55:47 -07:00
|
|
|
css.width = rect.width - this.sizeExtra.x;
|
2010-07-22 21:35:07 -07:00
|
|
|
let widthRange = new Range(0,TabItems.tabWidth);
|
|
|
|
let proportion = widthRange.proportion(css.width, true); // in [0,1]
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 21:35:07 -07:00
|
|
|
css.fontSize = fontSizeRange.scale(proportion); // returns a value in the fontSizeRange
|
2010-07-22 19:20:44 -07:00
|
|
|
css.fontSize += 'px';
|
2010-06-14 15:43:02 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
if (rect.height != this.bounds.height || options.force)
|
|
|
|
css.height = rect.height - this.sizeExtra.y;
|
|
|
|
|
2010-07-23 14:33:02 -07:00
|
|
|
if (Utils.isEmptyObject(css))
|
2010-06-14 15:43:02 -07:00
|
|
|
return;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
this.bounds.copy(rect);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
// If this is a brand new tab don't animate it in from
|
|
|
|
// a random location (i.e., from [0,0]). Instead, just
|
|
|
|
// have it appear where it should be.
|
2010-07-30 02:54:30 -07:00
|
|
|
if (immediately || (!this._hasBeenDrawn)) {
|
2010-06-14 15:43:02 -07:00
|
|
|
$container.css(css);
|
|
|
|
} else {
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.pausePainting();
|
2010-06-14 15:43:02 -07:00
|
|
|
$container.animate(css, {
|
|
|
|
duration: 200,
|
2010-07-29 12:37:25 -07:00
|
|
|
easing: "tabviewBounce",
|
2010-06-14 15:43:02 -07:00
|
|
|
complete: function() {
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.resumePainting();
|
2010-06-14 15:43:02 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (css.fontSize && !this.inStack()) {
|
2010-07-30 02:54:30 -07:00
|
|
|
if (css.fontSize < fontSizeRange.min)
|
2010-09-04 12:15:31 -07:00
|
|
|
$title.fadeOut();
|
2010-06-14 15:43:02 -07:00
|
|
|
else
|
2010-09-04 12:15:31 -07:00
|
|
|
$title.fadeIn();
|
2010-06-14 15:43:02 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 21:35:07 -07:00
|
|
|
if (css.width) {
|
2010-08-04 16:42:36 -07:00
|
|
|
TabItems.update(this.tab);
|
2010-07-22 21:35:07 -07:00
|
|
|
|
|
|
|
let widthRange, proportion;
|
|
|
|
|
|
|
|
if (this.inStack()) {
|
|
|
|
$fav.css({top:0, left:0});
|
|
|
|
widthRange = new Range(70, 90);
|
|
|
|
proportion = widthRange.proportion(css.width); // between 0 and 1
|
|
|
|
} else {
|
|
|
|
$fav.css({top:4,left:4});
|
|
|
|
widthRange = new Range(60, 70);
|
|
|
|
proportion = widthRange.proportion(css.width); // between 0 and 1
|
|
|
|
$close.show().css({opacity:proportion});
|
2010-07-30 02:54:30 -07:00
|
|
|
if (proportion <= .1)
|
2010-07-22 21:35:07 -07:00
|
|
|
$close.hide()
|
2010-06-25 15:15:51 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 21:35:07 -07:00
|
|
|
var pad = 1 + 5 * proportion;
|
|
|
|
var alphaRange = new Range(0.1,0.2);
|
2010-06-25 15:15:51 -07:00
|
|
|
$fav.css({
|
|
|
|
"padding-left": pad + "px",
|
|
|
|
"padding-right": pad + 2 + "px",
|
|
|
|
"padding-top": pad + "px",
|
|
|
|
"padding-bottom": pad + "px",
|
2010-07-22 21:35:07 -07:00
|
|
|
"border-color": "rgba(0,0,0,"+ alphaRange.scale(proportion) +")",
|
2010-06-25 15:15:51 -07:00
|
|
|
});
|
2010-07-18 08:58:10 -07:00
|
|
|
}
|
2010-03-29 16:08:48 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
this._hasBeenDrawn = true;
|
2010-04-12 17:20:35 -07:00
|
|
|
}
|
|
|
|
|
2010-04-01 17:20:59 -07:00
|
|
|
this._updateDebugBounds();
|
2010-06-22 20:45:51 -07:00
|
|
|
rect = this.getBounds(); // ensure that it's a <Rect>
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 12:46:51 -07:00
|
|
|
if (!Utils.isRect(this.bounds))
|
2010-05-11 17:22:06 -07:00
|
|
|
Utils.trace('TabItem.setBounds: this.bounds is not a real rectangle!', this.bounds);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 15:09:36 -07:00
|
|
|
if (!this.parent && this.tab.parentNode != null)
|
2010-06-19 12:05:36 -07:00
|
|
|
this.setTrenches(rect);
|
2010-05-21 15:44:15 -07:00
|
|
|
|
|
|
|
this.save();
|
2010-04-01 17:20:59 -07:00
|
|
|
},
|
2010-04-02 17:33:06 -07:00
|
|
|
|
2010-07-22 19:20:44 -07:00
|
|
|
// ----------
|
|
|
|
// Function: getBoundsWithTitle
|
2010-08-06 15:46:55 -07:00
|
|
|
// Returns a <Rect> for the groupItem's bounds, including the title
|
2010-09-08 10:02:08 -07:00
|
|
|
getBoundsWithTitle: function TabItem_getBoundsWithTitle() {
|
2010-07-22 19:20:44 -07:00
|
|
|
var b = this.getBounds();
|
2010-08-08 15:32:08 -07:00
|
|
|
var $title = iQ(this.container).find('.tab-title');
|
2010-08-04 22:43:05 -07:00
|
|
|
var height = b.height;
|
2010-08-08 18:49:43 -07:00
|
|
|
if ( Utils.isNumber($title.height()) )
|
|
|
|
height += $title.height();
|
2010-08-04 22:43:05 -07:00
|
|
|
return new Rect(b.left, b.top, b.width, height);
|
2010-07-22 19:20:44 -07:00
|
|
|
},
|
|
|
|
|
2010-05-12 20:31:51 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: inStack
|
2010-08-06 15:46:55 -07:00
|
|
|
// Returns true if this item is in a stacked groupItem.
|
2010-09-08 10:02:08 -07:00
|
|
|
inStack: function TabItem_inStack() {
|
2010-06-04 12:34:03 -07:00
|
|
|
return iQ(this.container).hasClass("stacked");
|
2010-05-12 20:31:51 -07:00
|
|
|
},
|
|
|
|
|
2010-04-02 17:33:06 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: setZ
|
2010-07-18 08:58:10 -07:00
|
|
|
// Sets the z-index for this item.
|
2010-09-08 10:02:08 -07:00
|
|
|
setZ: function TabItem_setZ(value) {
|
2010-07-07 14:12:04 -07:00
|
|
|
this.zIndex = value;
|
2010-06-04 12:34:03 -07:00
|
|
|
iQ(this.container).css({zIndex: value});
|
2010-04-02 17:33:06 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: close
|
|
|
|
// Closes this item (actually closes the tab associated with it, which automatically
|
|
|
|
// closes the item.
|
2010-09-08 10:02:08 -07:00
|
|
|
close: function TabItem_close() {
|
2010-07-23 14:26:17 -07:00
|
|
|
gBrowser.removeTab(this.tab);
|
2010-08-10 11:39:28 -07:00
|
|
|
this._sendToSubscribers("tabRemoved");
|
2010-05-21 15:44:15 -07:00
|
|
|
|
|
|
|
// No need to explicitly delete the tab data, becasue sessionstore data
|
|
|
|
// associated with the tab will automatically go away
|
2010-03-29 16:08:48 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-04-29 00:42:37 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: addClass
|
2010-07-18 08:58:10 -07:00
|
|
|
// Adds the specified CSS class to this item's container DOM element.
|
2010-09-08 10:02:08 -07:00
|
|
|
addClass: function TabItem_addClass(className) {
|
2010-06-04 12:34:03 -07:00
|
|
|
iQ(this.container).addClass(className);
|
2010-04-29 00:42:37 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-04-29 00:42:37 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: removeClass
|
2010-07-18 08:58:10 -07:00
|
|
|
// Removes the specified CSS class from this item's container DOM element.
|
2010-09-08 10:02:08 -07:00
|
|
|
removeClass: function TabItem_removeClass(className) {
|
2010-06-04 12:34:03 -07:00
|
|
|
iQ(this.container).removeClass(className);
|
2010-04-29 00:42:37 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: setResizable
|
|
|
|
// If value is true, makes this item resizable, otherwise non-resizable.
|
|
|
|
// Shows/hides a visible resize handle as appropriate.
|
2010-09-08 10:02:08 -07:00
|
|
|
setResizable: function TabItem_setResizable(value) {
|
2010-06-09 14:45:48 -07:00
|
|
|
var $resizer = iQ('.expander', this.container);
|
2010-06-19 17:45:23 -07:00
|
|
|
|
2010-09-04 12:15:31 -07:00
|
|
|
this.resizeOptions.minWidth = TabItems.minTabWidth;
|
|
|
|
this.resizeOptions.minHeight = TabItems.minTabWidth * (TabItems.tabHeight / TabItems.tabWidth);
|
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (value) {
|
2010-09-04 12:15:31 -07:00
|
|
|
$resizer.fadeIn();
|
2010-06-22 16:42:06 -07:00
|
|
|
this.resizable(true);
|
2010-04-12 17:20:35 -07:00
|
|
|
} else {
|
2010-09-04 12:15:31 -07:00
|
|
|
$resizer.fadeOut();
|
2010-06-22 16:42:06 -07:00
|
|
|
this.resizable(false);
|
2010-04-12 17:20:35 -07:00
|
|
|
}
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: makeActive
|
|
|
|
// Updates this item to visually indicate that it's active.
|
2010-09-08 10:02:08 -07:00
|
|
|
makeActive: function TabItem_makeActive() {
|
2010-09-08 16:47:58 -07:00
|
|
|
iQ(this.container).addClass("focus");
|
2010-09-17 08:24:39 -07:00
|
|
|
|
|
|
|
if (this.parent)
|
|
|
|
this.parent.setActiveTab(this);
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
|
|
|
|
2010-07-18 08:58:10 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: makeDeactive
|
|
|
|
// Updates this item to visually indicate that it's not active.
|
2010-09-08 10:02:08 -07:00
|
|
|
makeDeactive: function TabItem_makeDeactive() {
|
2010-09-08 16:47:58 -07:00
|
|
|
iQ(this.container).removeClass("focus");
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
// ----------
|
2010-06-14 15:43:02 -07:00
|
|
|
// Function: zoomIn
|
|
|
|
// Allows you to select the tab and zoom in on it, thereby bringing you
|
|
|
|
// to the tab in Firefox to interact with.
|
2010-08-09 00:01:30 -07:00
|
|
|
// Parameters:
|
|
|
|
// isNewBlankTab - boolean indicates whether it is a newly opened blank tab.
|
2010-09-08 10:02:08 -07:00
|
|
|
zoomIn: function TabItem_zoomIn(isNewBlankTab) {
|
2010-09-10 07:40:27 -07:00
|
|
|
// don't allow zoom in if its group is hidden
|
|
|
|
if (this.parent && this.parent.hidden)
|
|
|
|
return;
|
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
var self = this;
|
|
|
|
var $tabEl = iQ(this.container);
|
|
|
|
var childHitResult = { shouldZoom: true };
|
2010-07-11 17:54:42 -07:00
|
|
|
if (this.parent)
|
2010-06-14 15:43:02 -07:00
|
|
|
childHitResult = this.parent.childHit(this);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (childHitResult.shouldZoom) {
|
2010-07-18 08:58:10 -07:00
|
|
|
// Zoom in!
|
2010-08-10 06:22:38 -07:00
|
|
|
var orig = $tabEl.bounds();
|
2010-06-14 15:43:02 -07:00
|
|
|
var scale = window.innerWidth/orig.width;
|
|
|
|
var tab = this.tab;
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-07-30 02:54:30 -07:00
|
|
|
function onZoomDone() {
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.resumePainting();
|
2010-08-18 00:06:20 -07:00
|
|
|
|
|
|
|
$tabEl
|
|
|
|
.css(orig.css())
|
|
|
|
.removeClass("front");
|
|
|
|
|
2010-09-10 02:50:14 -07:00
|
|
|
UI.goToTab(tab);
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-08-09 00:01:30 -07:00
|
|
|
if (isNewBlankTab)
|
|
|
|
gWindow.gURLBar.focus();
|
|
|
|
|
2010-07-11 17:54:42 -07:00
|
|
|
if (childHitResult.callback)
|
2010-07-18 08:58:10 -07:00
|
|
|
childHitResult.callback();
|
2010-06-14 15:43:02 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
// The scaleCheat is a clever way to speed up the zoom-in code.
|
|
|
|
// Because image scaling is slowest on big images, we cheat and stop the image
|
|
|
|
// at scaled-down size and placed accordingly. Because the animation is fast, you can't
|
|
|
|
// see the difference but it feels a lot zippier. The only trick is choosing the
|
2010-07-18 08:58:10 -07:00
|
|
|
// right animation function so that you don't see a change in percieved
|
2010-06-14 15:43:02 -07:00
|
|
|
// animation speed.
|
|
|
|
var scaleCheat = 1.7;
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.pausePainting();
|
2010-06-14 15:43:02 -07:00
|
|
|
$tabEl
|
|
|
|
.addClass("front")
|
|
|
|
.animate({
|
2010-08-10 06:22:38 -07:00
|
|
|
top: orig.top * (1 - 1/scaleCheat),
|
|
|
|
left: orig.left * (1 - 1/scaleCheat),
|
|
|
|
width: orig.width * scale/scaleCheat,
|
|
|
|
height: orig.height * scale/scaleCheat
|
2010-06-14 15:43:02 -07:00
|
|
|
}, {
|
|
|
|
duration: 230,
|
|
|
|
easing: 'fast',
|
|
|
|
complete: onZoomDone
|
|
|
|
});
|
2010-07-18 08:58:10 -07:00
|
|
|
}
|
2010-06-14 15:43:02 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
// ----------
|
|
|
|
// Function: zoomOut
|
2010-07-29 12:37:25 -07:00
|
|
|
// Handles the zoom down animation after returning to TabView.
|
2010-06-14 15:43:02 -07:00
|
|
|
// It is expected that this routine will be called from the chrome thread
|
2010-07-18 08:58:10 -07:00
|
|
|
//
|
|
|
|
// Parameters:
|
2010-06-14 15:43:02 -07:00
|
|
|
// complete - a function to call after the zoom down animation
|
2010-09-08 10:02:08 -07:00
|
|
|
zoomOut: function TabItem_zoomOut(complete) {
|
2010-06-14 15:43:02 -07:00
|
|
|
var $tab = iQ(this.container);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
var box = this.getBounds();
|
|
|
|
box.width -= this.sizeExtra.x;
|
|
|
|
box.height -= this.sizeExtra.y;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.pausePainting();
|
2010-06-14 15:43:02 -07:00
|
|
|
|
|
|
|
var self = this;
|
|
|
|
$tab.animate({
|
|
|
|
left: box.left,
|
2010-07-18 08:58:10 -07:00
|
|
|
top: box.top,
|
2010-06-14 15:43:02 -07:00
|
|
|
width: box.width,
|
|
|
|
height: box.height
|
|
|
|
}, {
|
|
|
|
duration: 300,
|
2010-06-14 17:23:17 -07:00
|
|
|
easing: 'cubic-bezier', // note that this is legal easing, even without parameters
|
2010-06-14 15:43:02 -07:00
|
|
|
complete: function() { // note that this will happen on the DOM thread
|
2010-08-18 00:06:20 -07:00
|
|
|
self.setZoomPrep(false);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-08-08 18:49:43 -07:00
|
|
|
GroupItems.setActiveOrphanTab(null);
|
2010-08-04 22:43:05 -07:00
|
|
|
|
2010-07-27 20:02:51 -07:00
|
|
|
TabItems.resumePainting();
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-23 19:29:32 -07:00
|
|
|
if (typeof complete == "function")
|
2010-08-04 22:43:05 -07:00
|
|
|
complete();
|
2010-06-14 15:43:02 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-14 15:43:02 -07:00
|
|
|
// ----------
|
|
|
|
// Function: setZoomPrep
|
2010-07-18 08:58:10 -07:00
|
|
|
// Either go into or return from (depending on <value>) "zoom prep" mode,
|
|
|
|
// where the tab fills a large portion of the screen in anticipation of
|
2010-06-14 15:43:02 -07:00
|
|
|
// the zoom out animation.
|
2010-09-08 10:02:08 -07:00
|
|
|
setZoomPrep: function TabItem_setZoomPrep(value) {
|
2010-06-14 15:43:02 -07:00
|
|
|
var $div = iQ(this.container);
|
|
|
|
var data;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-25 16:00:51 -07:00
|
|
|
var box = this.getBounds();
|
2010-07-18 08:58:10 -07:00
|
|
|
if (value) {
|
2010-06-14 15:43:02 -07:00
|
|
|
this._zoomPrep = true;
|
|
|
|
|
|
|
|
// The divide by two part here is a clever way to speed up the zoom-out code.
|
|
|
|
// Because image scaling is slowest on big images, we cheat and start the image
|
|
|
|
// at half-size and placed accordingly. Because the animation is fast, you can't
|
|
|
|
// see the difference but it feels a lot zippier. The only trick is choosing the
|
2010-07-18 08:58:10 -07:00
|
|
|
// right animation function so that you don't see a change in percieved
|
|
|
|
// animation speed from frame #1 (the tab) to frame #2 (the half-size image) to
|
2010-06-14 15:43:02 -07:00
|
|
|
// frame #3 (the first frame of real animation). Choosing an animation that starts
|
|
|
|
// fast is key.
|
|
|
|
var scaleCheat = 2;
|
|
|
|
$div
|
|
|
|
.addClass('front')
|
|
|
|
.css({
|
|
|
|
left: box.left * (1-1/scaleCheat),
|
2010-07-18 08:58:10 -07:00
|
|
|
top: box.top * (1-1/scaleCheat),
|
2010-06-14 15:43:02 -07:00
|
|
|
width: window.innerWidth/scaleCheat,
|
|
|
|
height: box.height * (window.innerWidth / box.width)/scaleCheat
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this._zoomPrep = false;
|
2010-06-25 16:00:51 -07:00
|
|
|
$div.removeClass('front');
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-06-28 16:11:22 -07:00
|
|
|
this.setBounds(box, true, {force: true});
|
2010-07-18 08:58:10 -07:00
|
|
|
}
|
2010-03-29 16:08:48 -07:00
|
|
|
}
|
|
|
|
});
|
2010-03-29 11:55:13 -07:00
|
|
|
|
|
|
|
// ##########
|
2010-05-13 17:24:37 -07:00
|
|
|
// Class: TabItems
|
|
|
|
// Singleton for managing <TabItem>s
|
2010-09-08 10:02:08 -07:00
|
|
|
let TabItems = {
|
2010-07-18 08:58:10 -07:00
|
|
|
minTabWidth: 40,
|
2010-03-31 17:24:16 -07:00
|
|
|
tabWidth: 160,
|
2010-07-18 08:58:10 -07:00
|
|
|
tabHeight: 120,
|
2010-03-31 17:24:16 -07:00
|
|
|
fontSize: 9,
|
2010-07-20 09:46:01 -07:00
|
|
|
items: [],
|
2010-07-27 20:02:51 -07:00
|
|
|
paintingPaused: 0,
|
2010-08-04 16:42:36 -07:00
|
|
|
_tabsWaitingForUpdate: [],
|
|
|
|
_heartbeatOn: false,
|
|
|
|
_heartbeatTiming: 100, // milliseconds between beats
|
|
|
|
_lastUpdateTime: Date.now(),
|
2010-08-11 21:36:58 -07:00
|
|
|
_eventListeners: [],
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: init
|
|
|
|
// Set up the necessary tracking to maintain the <TabItems>s.
|
2010-09-08 10:02:08 -07:00
|
|
|
init: function TabItems_init() {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assert(window.AllTabs, "AllTabs must be initialized first");
|
2010-07-27 20:02:51 -07:00
|
|
|
var self = this;
|
|
|
|
|
|
|
|
// When a tab is opened, create the TabItem
|
2010-08-11 21:36:58 -07:00
|
|
|
this._eventListeners["open"] = function(tab) {
|
2010-09-10 02:50:14 -07:00
|
|
|
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
2010-07-28 14:20:41 -07:00
|
|
|
return;
|
|
|
|
|
2010-08-15 21:46:22 -07:00
|
|
|
self.link(tab);
|
2010-08-11 21:36:58 -07:00
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
// When a tab's content is loaded, show the canvas and hide the cached data
|
|
|
|
// if necessary.
|
2010-08-11 21:36:58 -07:00
|
|
|
this._eventListeners["attrModified"] = function(tab) {
|
2010-09-10 02:50:14 -07:00
|
|
|
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
2010-07-28 14:20:41 -07:00
|
|
|
return;
|
|
|
|
|
2010-08-15 21:46:22 -07:00
|
|
|
self.update(tab);
|
2010-08-11 21:36:58 -07:00
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
// When a tab is closed, unlink.
|
2010-08-11 21:36:58 -07:00
|
|
|
this._eventListeners["close"] = function(tab) {
|
2010-09-10 02:50:14 -07:00
|
|
|
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
2010-07-28 14:20:41 -07:00
|
|
|
return;
|
|
|
|
|
2010-08-15 21:46:22 -07:00
|
|
|
self.unlink(tab);
|
2010-08-11 21:36:58 -07:00
|
|
|
}
|
|
|
|
for (let name in this._eventListeners) {
|
|
|
|
AllTabs.register(name, this._eventListeners[name]);
|
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
// For each tab, create the link.
|
2010-08-06 15:19:57 -07:00
|
|
|
AllTabs.tabs.forEach(function(tab) {
|
2010-09-10 02:50:14 -07:00
|
|
|
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
2010-07-28 14:20:41 -07:00
|
|
|
return;
|
|
|
|
|
2010-09-04 12:15:31 -07:00
|
|
|
self.link(tab);
|
2010-07-29 17:23:49 -07:00
|
|
|
self.update(tab);
|
2010-07-27 20:02:51 -07:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2010-08-11 21:36:58 -07:00
|
|
|
// ----------
|
|
|
|
// Function: uninit
|
2010-09-08 10:02:08 -07:00
|
|
|
uninit: function TabItems_uninit() {
|
2010-08-11 21:36:58 -07:00
|
|
|
for (let name in this._eventListeners) {
|
|
|
|
AllTabs.unregister(name, this._eventListeners[name]);
|
|
|
|
}
|
2010-08-11 23:39:12 -07:00
|
|
|
this.items.forEach(function(tabItem) {
|
2010-08-11 23:46:16 -07:00
|
|
|
for (let x in tabItem) {
|
2010-08-11 23:39:12 -07:00
|
|
|
if (typeof tabItem[x] == "object")
|
|
|
|
tabItem[x] = null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2010-08-11 21:36:58 -07:00
|
|
|
this.items = null;
|
|
|
|
this._eventListeners = null;
|
|
|
|
this._lastUpdateTime = null;
|
|
|
|
this._tabsWaitingForUpdate = null;
|
|
|
|
},
|
|
|
|
|
2010-07-27 20:02:51 -07:00
|
|
|
// ----------
|
2010-07-29 14:45:08 -07:00
|
|
|
// Function: update
|
|
|
|
// Takes in a xul:tab.
|
2010-09-08 10:02:08 -07:00
|
|
|
update: function TabItems_update(tab) {
|
2010-07-27 20:02:51 -07:00
|
|
|
try {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(tab, "tab");
|
2010-09-10 02:50:14 -07:00
|
|
|
Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
|
|
|
|
Utils.assertThrow(tab.tabItem, "should already be linked");
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
let shouldDefer = (
|
2010-08-08 20:52:26 -07:00
|
|
|
this.isPaintingPaused() ||
|
2010-08-05 10:39:33 -07:00
|
|
|
this._tabsWaitingForUpdate.length ||
|
|
|
|
Date.now() - this._lastUpdateTime < this._heartbeatTiming
|
|
|
|
);
|
|
|
|
|
|
|
|
let isCurrentTab = (
|
2010-08-08 20:52:26 -07:00
|
|
|
!UI._isTabViewVisible() &&
|
2010-08-05 10:39:33 -07:00
|
|
|
tab == gBrowser.selectedTab
|
|
|
|
);
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
if (shouldDefer && !isCurrentTab) {
|
2010-08-04 16:42:36 -07:00
|
|
|
if (this._tabsWaitingForUpdate.indexOf(tab) == -1)
|
|
|
|
this._tabsWaitingForUpdate.push(tab);
|
2010-08-08 20:52:26 -07:00
|
|
|
} else
|
2010-08-04 16:42:36 -07:00
|
|
|
this._update(tab);
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: _update
|
|
|
|
// Takes in a xul:tab.
|
2010-09-08 10:02:08 -07:00
|
|
|
_update: function TabItems__update(tab) {
|
2010-08-04 16:42:36 -07:00
|
|
|
try {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(tab, "tab");
|
2010-07-30 02:54:30 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ remove from waiting list if needed
|
|
|
|
let index = this._tabsWaitingForUpdate.indexOf(tab);
|
|
|
|
if (index != -1)
|
2010-08-08 20:52:26 -07:00
|
|
|
this._tabsWaitingForUpdate.splice(index, 1);
|
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ get the TabItem
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(tab.tabItem, "must already be linked");
|
2010-07-29 14:45:08 -07:00
|
|
|
let tabItem = tab.tabItem;
|
2010-07-30 02:54:30 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ icon
|
2010-07-29 14:45:08 -07:00
|
|
|
let iconUrl = tab.image;
|
|
|
|
if (iconUrl == null)
|
2010-09-10 02:50:14 -07:00
|
|
|
iconUrl = Utils.defaultFaviconURL;
|
2010-07-29 14:45:08 -07:00
|
|
|
|
|
|
|
if (iconUrl != tabItem.favEl.src)
|
|
|
|
tabItem.favEl.src = iconUrl;
|
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ URL
|
2010-07-29 14:45:08 -07:00
|
|
|
let tabUrl = tab.linkedBrowser.currentURI.spec;
|
|
|
|
if (tabUrl != tabItem.url) {
|
2010-08-05 10:39:33 -07:00
|
|
|
let oldURL = tabItem.url;
|
2010-07-29 14:45:08 -07:00
|
|
|
tabItem.url = tabUrl;
|
2010-08-10 15:36:56 -07:00
|
|
|
|
|
|
|
if (!tabItem.reconnected && (oldURL == 'about:blank' || !oldURL))
|
|
|
|
this.reconnect(tabItem);
|
2010-08-11 21:36:58 -07:00
|
|
|
|
2010-08-10 15:36:56 -07:00
|
|
|
tabItem.save();
|
2010-07-29 14:45:08 -07:00
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ label
|
|
|
|
let label = tab.label;
|
|
|
|
let $name = iQ(tabItem.nameEl);
|
2010-07-29 14:45:08 -07:00
|
|
|
if (!tabItem.isShowingCachedData && $name.text() != label)
|
|
|
|
$name.text(label);
|
2010-07-27 20:02:51 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ thumbnail
|
|
|
|
let $canvas = iQ(tabItem.canvasEl);
|
2010-07-29 14:45:08 -07:00
|
|
|
if (!tabItem.canvasSizeForced) {
|
2010-08-05 10:39:33 -07:00
|
|
|
let w = $canvas.width();
|
|
|
|
let h = $canvas.height();
|
2010-07-29 14:45:08 -07:00
|
|
|
if (w != tabItem.canvasEl.width || h != tabItem.canvasEl.height) {
|
|
|
|
tabItem.canvasEl.width = w;
|
|
|
|
tabItem.canvasEl.height = h;
|
2010-07-27 20:02:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-29 14:45:08 -07:00
|
|
|
tabItem.tabCanvas.paint();
|
2010-07-27 20:02:51 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
// ___ cache
|
2010-07-29 14:45:08 -07:00
|
|
|
// TODO: this logic needs to be better; hiding too soon now
|
|
|
|
if (tabItem.isShowingCachedData && !tab.hasAttribute("busy"))
|
|
|
|
tabItem.hideCachedData();
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
|
|
|
}
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
this._lastUpdateTime = Date.now();
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: link
|
2010-09-10 02:50:14 -07:00
|
|
|
// Takes in a xul:tab, creates a TabItem for it and adds it to the scene.
|
2010-09-08 10:02:08 -07:00
|
|
|
link: function TabItems_link(tab){
|
2010-07-29 14:45:08 -07:00
|
|
|
try {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(tab, "tab");
|
2010-09-10 02:50:14 -07:00
|
|
|
Utils.assertThrow(!tab.pinned, "shouldn't be an app tab");
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(!tab.tabItem, "shouldn't already be linked");
|
2010-09-04 12:15:31 -07:00
|
|
|
new TabItem(tab); // sets tab.tabItem to itself
|
2010-07-29 14:45:08 -07:00
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: unlink
|
2010-09-10 02:50:14 -07:00
|
|
|
// Takes in a xul:tab and destroys the TabItem associated with it.
|
2010-09-08 10:02:08 -07:00
|
|
|
unlink: function TabItems_unlink(tab) {
|
2010-07-29 14:45:08 -07:00
|
|
|
try {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assertThrow(tab, "tab");
|
|
|
|
Utils.assertThrow(tab.tabItem, "should already be linked");
|
2010-09-12 20:45:02 -07:00
|
|
|
// note that it's ok to unlink an app tab; see .handleTabUnpin
|
2010-07-27 20:02:51 -07:00
|
|
|
|
2010-08-10 15:36:56 -07:00
|
|
|
this.unregister(tab.tabItem);
|
2010-08-10 11:39:28 -07:00
|
|
|
tab.tabItem._sendToSubscribers("close");
|
2010-08-10 15:36:56 -07:00
|
|
|
iQ(tab.tabItem.container).remove();
|
|
|
|
tab.tabItem.removeTrenches();
|
|
|
|
Items.unsquish(null, tab.tabItem);
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
tab.tabItem = null;
|
2010-08-16 16:56:28 -07:00
|
|
|
Storage.saveTab(tab, null);
|
2010-08-04 16:42:36 -07:00
|
|
|
|
|
|
|
let index = this._tabsWaitingForUpdate.indexOf(tab);
|
|
|
|
if (index != -1)
|
2010-08-08 20:52:26 -07:00
|
|
|
this._tabsWaitingForUpdate.splice(index, 1);
|
2010-07-29 14:45:08 -07:00
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
2010-07-27 20:02:51 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-09-12 20:45:02 -07:00
|
|
|
// ----------
|
|
|
|
// when a tab becomes pinned, destroy its TabItem
|
|
|
|
handleTabPin: function TabItems_handleTabPin(xulTab) {
|
|
|
|
this.unlink(xulTab);
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// when a tab becomes unpinned, create a TabItem for it
|
|
|
|
handleTabUnpin: function TabItems_handleTabUnpin(xulTab) {
|
|
|
|
this.link(xulTab);
|
|
|
|
this.update(xulTab);
|
|
|
|
},
|
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
// ----------
|
|
|
|
// Function: heartbeat
|
|
|
|
// Allows us to spreadout update calls over a period of time.
|
2010-09-08 10:02:08 -07:00
|
|
|
heartbeat: function TabItems_heartbeat() {
|
2010-08-04 16:42:36 -07:00
|
|
|
if (!this._heartbeatOn)
|
|
|
|
return;
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-05 10:39:33 -07:00
|
|
|
if (this._tabsWaitingForUpdate.length) {
|
|
|
|
this._update(this._tabsWaitingForUpdate[0]);
|
|
|
|
// _update will remove the tab from the waiting list
|
|
|
|
}
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
let self = this;
|
|
|
|
if (this._tabsWaitingForUpdate.length) {
|
2010-08-10 06:30:23 -07:00
|
|
|
setTimeout(function() {
|
2010-08-04 16:42:36 -07:00
|
|
|
self.heartbeat();
|
|
|
|
}, this._heartbeatTiming);
|
|
|
|
} else
|
|
|
|
this._hearbeatOn = false;
|
|
|
|
},
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
// ----------
|
2010-07-27 20:02:51 -07:00
|
|
|
// Function: pausePainting
|
|
|
|
// Tells TabItems to stop updating thumbnails (so you can do
|
|
|
|
// animations without thumbnail paints causing stutters).
|
|
|
|
// pausePainting can be called multiple times, but every call to
|
|
|
|
// pausePainting needs to be mirrored with a call to <resumePainting>.
|
2010-09-08 10:02:08 -07:00
|
|
|
pausePainting: function TabItems_pausePainting() {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.paintingPaused++;
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
if (this.isPaintingPaused() && this._heartbeatOn)
|
|
|
|
this._heartbeatOn = false;
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
// ----------
|
2010-07-27 20:02:51 -07:00
|
|
|
// Function: resumePainting
|
|
|
|
// Undoes a call to <pausePainting>. For instance, if you called
|
|
|
|
// pausePainting three times in a row, you'll need to call resumePainting
|
|
|
|
// three times before TabItems will start updating thumbnails again.
|
2010-09-08 10:02:08 -07:00
|
|
|
resumePainting: function TabItems_resumePainting() {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.paintingPaused--;
|
2010-08-08 20:52:26 -07:00
|
|
|
|
2010-08-10 16:20:05 -07:00
|
|
|
if (!this.isPaintingPaused() &&
|
|
|
|
this._tabsWaitingForUpdate.length &&
|
|
|
|
!this._heartbeatOn) {
|
2010-08-04 16:42:36 -07:00
|
|
|
this._heartbeatOn = true;
|
|
|
|
this.heartbeat();
|
|
|
|
}
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
2010-08-04 16:42:36 -07:00
|
|
|
// ----------
|
2010-07-27 20:02:51 -07:00
|
|
|
// Function: isPaintingPaused
|
|
|
|
// Returns a boolean indicating whether painting
|
|
|
|
// is paused or not.
|
2010-09-08 10:02:08 -07:00
|
|
|
isPaintingPaused: function TabItems_isPaintingPaused() {
|
2010-08-04 16:42:36 -07:00
|
|
|
return this.paintingPaused > 0;
|
2010-07-27 20:02:51 -07:00
|
|
|
},
|
|
|
|
|
2010-07-18 08:58:10 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: register
|
2010-07-18 08:58:10 -07:00
|
|
|
// Adds the given <TabItem> to the master list.
|
2010-09-08 10:02:08 -07:00
|
|
|
register: function TabItems_register(item) {
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assert(item && item.isAnItem, 'item must be a TabItem');
|
|
|
|
Utils.assert(this.items.indexOf(item) == -1, 'only register once per item');
|
2010-05-18 17:08:45 -07:00
|
|
|
this.items.push(item);
|
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: unregister
|
2010-07-18 08:58:10 -07:00
|
|
|
// Removes the given <TabItem> from the master list.
|
2010-09-08 10:02:08 -07:00
|
|
|
unregister: function TabItems_unregister(item) {
|
2010-07-13 17:10:53 -07:00
|
|
|
var index = this.items.indexOf(item);
|
2010-07-11 17:54:42 -07:00
|
|
|
if (index != -1)
|
2010-07-18 08:58:10 -07:00
|
|
|
this.items.splice(index, 1);
|
2010-05-18 17:08:45 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-04-23 17:11:06 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: getItems
|
|
|
|
// Returns a copy of the master array of <TabItem>s.
|
2010-09-08 10:02:08 -07:00
|
|
|
getItems: function TabItems_getItems() {
|
2010-05-18 17:08:45 -07:00
|
|
|
return Utils.copy(this.items);
|
2010-04-23 17:11:06 -07:00
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-24 14:49:03 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: saveAll
|
2010-07-18 08:58:10 -07:00
|
|
|
// Saves all open <TabItem>s.
|
|
|
|
//
|
|
|
|
// Parameters:
|
2010-07-16 17:27:01 -07:00
|
|
|
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
2010-09-08 10:02:08 -07:00
|
|
|
saveAll: function TabItems_saveAll(saveImageData) {
|
2010-05-24 14:49:03 -07:00
|
|
|
var items = this.getItems();
|
2010-07-13 16:38:51 -07:00
|
|
|
items.forEach(function(item) {
|
2010-07-14 19:40:46 -07:00
|
|
|
item.save(saveImageData);
|
2010-05-24 14:49:03 -07:00
|
|
|
});
|
|
|
|
},
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-11 12:03:31 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: storageSanity
|
|
|
|
// Checks the specified data (as returned by TabItem.getStorageData or loaded from storage)
|
|
|
|
// and returns true if it looks valid.
|
2010-07-18 08:58:10 -07:00
|
|
|
// TODO: check everything
|
2010-09-08 10:02:08 -07:00
|
|
|
storageSanity: function TabItems_storageSanity(data) {
|
2010-05-11 12:03:31 -07:00
|
|
|
var sane = true;
|
2010-07-22 12:46:51 -07:00
|
|
|
if (!Utils.isRect(data.bounds)) {
|
2010-05-24 14:49:03 -07:00
|
|
|
Utils.log('TabItems.storageSanity: bad bounds', data.bounds);
|
|
|
|
sane = false;
|
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-11 12:03:31 -07:00
|
|
|
return sane;
|
|
|
|
},
|
|
|
|
|
2010-04-26 13:37:39 -07:00
|
|
|
// ----------
|
2010-07-16 17:27:01 -07:00
|
|
|
// Function: reconnect
|
|
|
|
// Given a <TabItem>, attempts to load its persistent data from storage.
|
2010-09-08 10:02:08 -07:00
|
|
|
reconnect: function TabItems_reconnect(item) {
|
2010-05-24 14:49:03 -07:00
|
|
|
var found = false;
|
|
|
|
|
2010-05-21 15:44:15 -07:00
|
|
|
try{
|
2010-08-10 11:13:10 -07:00
|
|
|
Utils.assert(item, 'item');
|
|
|
|
Utils.assert(item.tab, 'item.tab');
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
if (item.reconnected)
|
2010-05-21 15:44:15 -07:00
|
|
|
return true;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 15:09:36 -07:00
|
|
|
if (!item.tab)
|
2010-06-14 16:56:27 -07:00
|
|
|
return false;
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 15:09:36 -07:00
|
|
|
let tabData = Storage.getTabData(item.tab);
|
2010-07-16 08:52:06 -07:00
|
|
|
if (tabData && this.storageSanity(tabData)) {
|
2010-07-11 17:54:42 -07:00
|
|
|
if (item.parent)
|
2010-09-04 12:15:31 -07:00
|
|
|
item.parent.remove(item);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-16 08:52:06 -07:00
|
|
|
item.setBounds(tabData.bounds, true);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-22 12:46:51 -07:00
|
|
|
if (Utils.isPoint(tabData.userSize))
|
2010-07-16 08:52:06 -07:00
|
|
|
item.userSize = new Point(tabData.userSize);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-16 08:52:06 -07:00
|
|
|
if (tabData.groupID) {
|
2010-08-06 15:46:55 -07:00
|
|
|
var groupItem = GroupItems.groupItem(tabData.groupID);
|
|
|
|
if (groupItem) {
|
2010-09-04 12:15:31 -07:00
|
|
|
groupItem.add(item);
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-09-14 03:12:03 -07:00
|
|
|
// if it matches the selected tab or no active tab and the browser
|
|
|
|
// tab is hidden, the active group item would be set.
|
|
|
|
if (item.tab == gBrowser.selectedTab ||
|
|
|
|
(!GroupItems.getActiveGroupItem() && !item.tab.hidden))
|
2010-08-06 15:46:55 -07:00
|
|
|
GroupItems.setActiveGroupItem(item.parent);
|
2010-05-24 14:49:03 -07:00
|
|
|
}
|
2010-07-14 19:40:46 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-07-16 08:52:06 -07:00
|
|
|
if (tabData.imageData) {
|
2010-07-27 20:02:51 -07:00
|
|
|
item.showCachedData(tabData);
|
2010-07-14 19:40:46 -07:00
|
|
|
// the code in the progress listener doesn't fire sometimes because
|
|
|
|
// tab is being restored so need to catch that.
|
2010-08-10 06:30:23 -07:00
|
|
|
setTimeout(function() {
|
2010-07-27 20:02:51 -07:00
|
|
|
if (item && item.isShowingCachedData) {
|
|
|
|
item.hideCachedData();
|
2010-07-20 01:08:03 -07:00
|
|
|
}
|
2010-07-17 09:12:31 -07:00
|
|
|
}, 15000);
|
2010-07-14 19:40:46 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
2010-05-21 15:44:15 -07:00
|
|
|
item.reconnected = true;
|
2010-09-04 12:15:31 -07:00
|
|
|
found = true;
|
2010-10-06 11:56:13 -07:00
|
|
|
} else {
|
|
|
|
// if it's not a blank tab or it belongs to a group, it would mean
|
|
|
|
// the item is reconnected.
|
|
|
|
item.reconnected =
|
|
|
|
(item.tab.linkedBrowser.currentURI.spec != 'about:blank' || item.parent);
|
|
|
|
}
|
2010-05-21 15:44:15 -07:00
|
|
|
item.save();
|
2010-10-07 08:17:26 -07:00
|
|
|
|
|
|
|
if (item.reconnected)
|
|
|
|
item._sendToSubscribers("reconnected");
|
2010-07-30 02:54:30 -07:00
|
|
|
} catch(e) {
|
2010-06-14 16:56:27 -07:00
|
|
|
Utils.log(e);
|
2010-05-21 15:44:15 -07:00
|
|
|
}
|
2010-07-18 08:58:10 -07:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
2010-03-29 11:55:13 -07:00
|
|
|
};
|
2010-07-27 20:02:51 -07:00
|
|
|
|
|
|
|
// ##########
|
|
|
|
// Class: TabCanvas
|
|
|
|
// Takes care of the actual canvas for the tab thumbnail
|
|
|
|
// Does not need to be accessed from outside of tabitems.js
|
2010-09-08 10:02:08 -07:00
|
|
|
function TabCanvas(tab, canvas) {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.init(tab, canvas);
|
|
|
|
};
|
|
|
|
|
|
|
|
TabCanvas.prototype = {
|
|
|
|
// ----------
|
|
|
|
// Function: init
|
2010-09-08 10:02:08 -07:00
|
|
|
init: function TabCanvas_init(tab, canvas) {
|
2010-07-27 20:02:51 -07:00
|
|
|
this.tab = tab;
|
|
|
|
this.canvas = canvas;
|
|
|
|
|
2010-07-29 14:45:08 -07:00
|
|
|
var $canvas = iQ(canvas);
|
2010-07-27 20:02:51 -07:00
|
|
|
var w = $canvas.width();
|
|
|
|
var h = $canvas.height();
|
|
|
|
canvas.width = w;
|
|
|
|
canvas.height = h;
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: paint
|
2010-09-08 10:02:08 -07:00
|
|
|
paint: function TabCanvas_paint(evt) {
|
2010-07-27 20:02:51 -07:00
|
|
|
var ctx = this.canvas.getContext("2d");
|
|
|
|
|
|
|
|
var w = this.canvas.width;
|
|
|
|
var h = this.canvas.height;
|
|
|
|
if (!w || !h)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let fromWin = this.tab.linkedBrowser.contentWindow;
|
|
|
|
if (fromWin == null) {
|
|
|
|
Utils.log('null fromWin in paint');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var scaler = w/fromWin.innerWidth;
|
|
|
|
|
|
|
|
// TODO: Potentially only redraw the dirty rect? (Is it worth it?)
|
|
|
|
|
|
|
|
ctx.save();
|
|
|
|
ctx.scale(scaler, scaler);
|
|
|
|
try{
|
2010-07-30 02:54:30 -07:00
|
|
|
ctx.drawWindow(fromWin, fromWin.scrollX, fromWin.scrollY, w/scaler, h/scaler, "#fff");
|
|
|
|
} catch(e) {
|
2010-07-27 20:02:51 -07:00
|
|
|
Utils.error('paint', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.restore();
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: toImageData
|
2010-09-08 10:02:08 -07:00
|
|
|
toImageData: function TabCanvas_toImageData() {
|
2010-07-27 20:02:51 -07:00
|
|
|
return this.canvas.toDataURL("image/png", "");
|
|
|
|
}
|
|
|
|
};
|