This commit is contained in:
Michael Yoshitaka Erlewine 2010-07-18 11:58:10 -04:00
Родитель 2be7d1674c
Коммит 061c70e020
15 изменённых файлов: 1455 добавлений и 1455 удалений

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

@ -35,11 +35,11 @@
* ***** END LICENSE BLOCK ***** */
// **********
// Title: drag.js
// Title: drag.js
// ----------
// Variable: drag
// The Drag that's currently in process.
// The Drag that's currently in process.
var drag = {
info: null,
zIndex: 100
@ -49,13 +49,13 @@ var drag = {
// ##########
// Class: Drag (formerly DragInfo)
// Helper class for dragging <Item>s
//
//
// ----------
// Constructor: Drag
// Called to create a Drag in response to an <Item> draggable "start" event.
// Note that it is also used partially during <Item>'s resizable method as well.
//
// Parameters:
//
// Parameters:
// item - The <Item> being dragged
// event - The DOM event that kicks off the drag
// isResizing - (boolean) is this a resizing instance? or (if false) dragging?
@ -63,7 +63,7 @@ var Drag = function(item, event, isResizing) {
try {
Utils.assert('must be an item, or at least a faux item',
item && (item.isAnItem || item.isAFauxItem));
this.isResizing = isResizing || false;
this.item = item;
this.el = item.container;
@ -71,17 +71,17 @@ var Drag = function(item, event, isResizing) {
this.parent = this.item.parent;
this.startPosition = new Point(event.clientX, event.clientY);
this.startTime = Utils.getMilliseconds();
this.item.isDragging = true;
this.item.setZ(999999);
if (this.item.isATabItem && !isResizing)
this.safeWindowBounds = Items.getSafeWindowBounds( true );
else
this.safeWindowBounds = Items.getSafeWindowBounds( );
Trenches.activateOthersTrenches(this.el);
// When a tab drag starts, make it the focused tab.
if (this.item.isAGroup) {
var tab = Page.getActiveTab();
@ -101,13 +101,13 @@ Drag.prototype = {
// ----------
// Function: snapBounds
// Adjusts the given bounds according to the currently active trenches. Used by <Drag.snap>
//
// Parameters:
//
// Parameters:
// bounds - (<Rect>) bounds
// stationaryCorner - which corner is stationary? by default, the top left.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// proportionally or not
snapBounds: function Drag_snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional) {
var stationaryCorner = stationaryCorner || 'topleft';
@ -121,7 +121,7 @@ Drag.prototype = {
if ( // if we aren't holding down the meta key...
!Keys.meta
// and we aren't a tab on top of something else...
&& !(this.item.isATabItem && this.item.overlapsWithOtherItems()) ) {
&& !(this.item.isATabItem && this.item.overlapsWithOtherItems()) ) {
newRect = Trenches.snap(bounds,stationaryCorner,assumeConstantSize,keepProportional);
if (newRect) { // might be false if no changes were made
update = true;
@ -151,18 +151,18 @@ Drag.prototype = {
return update ? bounds : false;
},
// ----------
// Function: snap
// Called when a drag or mousemove occurs. Set the bounds based on the mouse move first, then
// call snap and it will adjust the item's bounds if appropriate. Also triggers the display of
// trenches that it snapped to.
//
// Parameters:
//
// Parameters:
// stationaryCorner - which corner is stationary? by default, the top left.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// proportionally or not
snap: function Drag_snap(stationaryCorner, assumeConstantSize, keepProportional) {
var bounds = this.item.getBounds();
@ -173,13 +173,13 @@ Drag.prototype = {
}
return false;
},
// --------
// Function: snapToEdge
// Returns a version of the bounds snapped to the edge if it is close enough. If not,
// returns false. If <Keys.meta> is true, this function will simply enforce the
// Returns a version of the bounds snapped to the edge if it is close enough. If not,
// returns false. If <Keys.meta> is true, this function will simply enforce the
// window edges.
//
//
// Parameters:
// rect - (<Rect>) current bounds of the object
// stationaryCorner - which corner is stationary? by default, the top left.
@ -188,7 +188,7 @@ Drag.prototype = {
// keepProportional - (boolean) if we are allowed to change the rect's size, whether the
// dimensions should scaled proportionally or not.
snapToEdge: function Drag_snapToEdge(rect, stationaryCorner, assumeConstantSize, keepProportional) {
var swb = this.safeWindowBounds;
var update = false;
var updateX = false;
@ -204,7 +204,7 @@ Drag.prototype = {
updateX = true;
snappedTrenches.left = 'edge';
}
if (rect.right > swb.right - snapRadius) {
if (updateX || !assumeConstantSize) {
var newWidth = swb.right - rect.left;
@ -241,20 +241,20 @@ Drag.prototype = {
snappedTrenches.top = 'edge';
delete snappedTrenches.bottom;
}
if (update) {
rect.snappedTrenches = snappedTrenches;
return rect;
}
return false;
},
// ----------
// ----------
// Function: drag
// Called in response to an <Item> draggable "drag" event.
drag: function(event, ui) {
this.snap('topleft',true);
if (this.parent && this.parent.expanded) {
var now = Utils.getMilliseconds();
var distance = this.startPosition.distance(new Point(event.clientX, event.clientY));
@ -265,28 +265,28 @@ Drag.prototype = {
}
},
// ----------
// ----------
// Function: stop
// Called in response to an <Item> draggable "stop" event.
stop: function() {
Trenches.hideGuides();
this.item.isDragging = false;
if (this.parent && !this.parent.locked.close && this.parent != this.item.parent
if (this.parent && !this.parent.locked.close && this.parent != this.item.parent
&& this.parent.isEmpty()) {
this.parent.close();
}
if (this.parent && this.parent.expanded)
this.parent.arrange();
if (this.item && !this.item.parent) {
this.item.setZ(drag.zIndex);
drag.zIndex++;
this.item.pushAway();
}
Trenches.disactivate();
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -44,74 +44,74 @@
// ##########
// Class: InfoItem
// An <Item> in TabCandy used for displaying information, such as the welcome video.
// An <Item> in TabCandy used for displaying information, such as the welcome video.
// Note that it implements the <Subscribable> interface.
//
//
// ----------
// Constructor: InfoItem
//
// Parameters:
//
// Parameters:
// bounds - a <Rect> for where the item should be located
// options - various options for this group (see below)
//
// Possible options:
//
// Possible options:
// locked - see <Item.locked>; default is {}
// dontPush - true if this group shouldn't push away on creation; default is false
window.InfoItem = function(bounds, options) {
try {
Utils.assertThrow('bounds', isRect(bounds));
if (typeof(options) == 'undefined')
options = {};
this._inited = false;
this.isAnInfoItem = true;
this.defaultSize = bounds.size();
this.locked = (options.locked ? Utils.copy(options.locked) : {});
this.bounds = new Rect(bounds);
this.isDragging = false;
var self = this;
var $container = iQ('<div>')
.addClass('info-item')
.css(this.bounds)
.appendTo('body');
this.$contents = iQ('<div>')
.appendTo($container);
var $close = iQ('<div>')
.addClass('close')
.click(function() {
self.close();
})
.appendTo($container);
// ___ locking
if (this.locked.bounds)
$container.css({cursor: 'default'});
$container.css({cursor: 'default'});
if (this.locked.close)
$close.hide();
// ___ Superclass initialization
this._init($container.get(0));
if (this.$debug)
if (this.$debug)
this.$debug.css({zIndex: -1000});
// ___ Finish Up
if (!this.locked.bounds)
this.draggable();
// ___ Position
this.snap();
// ___ Push other objects away
if (!options.dontPush)
this.pushAway();
this.pushAway();
this._inited = true;
this.save();
} catch(e){
@ -122,44 +122,44 @@ window.InfoItem = function(bounds, options) {
// ----------
window.InfoItem.prototype = iQ.extend(new Item(), new Subscribable(), {
// ----------
// Accepts a callback that will be called when this item closes.
// The referenceObject is used to facilitate removal if necessary.
// Accepts a callback that will be called when this item closes.
// The referenceObject is used to facilitate removal if necessary.
addOnClose: function(referenceObject, callback) {
this.addSubscriber(referenceObject, "close", callback);
this.addSubscriber(referenceObject, "close", callback);
},
// ----------
// Removes the close event callback associated with referenceObject.
removeOnClose: function(referenceObject) {
this.removeSubscriber(referenceObject, "close");
this.removeSubscriber(referenceObject, "close");
},
// ----------
// ----------
// Function: getStorageData
// Returns all of the info worth storing about this item.
getStorageData: function() {
var data = null;
try {
data = {
bounds: this.getBounds(),
bounds: this.getBounds(),
locked: Utils.copy(this.locked)
};
} catch(e) {
Utils.log(e);
}
return data;
},
// ----------
// Function: save
// Saves this item to persistent storage.
// Saves this item to persistent storage.
save: function() {
try {
if (!this._inited) // too soon to save now
return;
var data = this.getStorageData();
/*
if (Groups.groupStorageSanity(data))
@ -169,78 +169,78 @@ window.InfoItem.prototype = iQ.extend(new Item(), new Subscribable(), {
Utils.log(e);
}
},
// ----------
// ----------
// Function: setBounds
// Sets the bounds with the given <Rect>, animating unless "immediately" is false.
setBounds: function(rect, immediately) {
try {
Utils.assertThrow('Group.setBounds: rect must be a real rectangle!', isRect(rect));
Utils.assertThrow('Group.setBounds: rect must be a real rectangle!', isRect(rect));
// ___ Determine what has changed
var css = {};
if (rect.left != this.bounds.left)
css.left = rect.left;
if (rect.top != this.bounds.top)
if (rect.top != this.bounds.top)
css.top = rect.top;
if (rect.width != this.bounds.width)
if (rect.width != this.bounds.width)
css.width = rect.width;
if (rect.height != this.bounds.height)
css.height = rect.height;
css.height = rect.height;
if (iQ.isEmptyObject(css))
return;
this.bounds = new Rect(rect);
Utils.assertThrow('Group.setBounds: this.bounds must be a real rectangle!', isRect(this.bounds));
Utils.assertThrow('Group.setBounds: this.bounds must be a real rectangle!', isRect(this.bounds));
// ___ Update our representation
if (immediately) {
iQ(this.container).css(css);
} else {
TabMirror.pausePainting();
iQ(this.container).animate(css, {
duration: 350,
easing: 'tabcandyBounce',
duration: 350,
easing: 'tabcandyBounce',
complete: function() {
TabMirror.resumePainting();
}
});
}
this._updateDebugBounds();
this.setTrenches(rect);
this.setTrenches(rect);
this.save();
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: setZ
// Set the Z order for the item's container.
// Set the Z order for the item's container.
setZ: function(value) {
try {
Utils.assertThrow('value must be a number', typeof(value) == 'number');
this.zIndex = value;
iQ(this.container).css({zIndex: value});
if (this.$debug)
if (this.$debug)
this.$debug.css({zIndex: value + 1});
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: close
// Closes the item.
// Closes the item.
close: function() {
try {
this._sendToSubscribers("close");
@ -249,13 +249,13 @@ window.InfoItem.prototype = iQ.extend(new Item(), new Subscribable(), {
iQ(this).remove();
Items.unsquish();
});
/* Storage.deleteGroup(Utils.getCurrentWindow(), this.id); */
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: html
// Sets the item's container's html to the specified value.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -36,11 +36,11 @@
* ***** END LICENSE BLOCK ***** */
// **********
// Title: storage.js
// Title: storage.js
// ##########
// Class: Storage
// Singleton for permanent storage of TabCandy data.
// Singleton for permanent storage of TabCandy data.
Storage = {
GROUP_DATA_IDENTIFIER: "tabcandy-group",
GROUPS_DATA_IDENTIFIER: "tabcandy-groups",
@ -51,7 +51,7 @@ Storage = {
// ----------
// Function: onReady
// Calls callback when Storage is ready for business. Could be immediately if it's already ready
// or later if needed.
// or later if needed.
onReady: function(callback) {
try {
// ToDo: the session store doesn't expose any public methods/variables for
@ -60,11 +60,11 @@ Storage = {
var alreadyReady = Utils.getCurrentWindow().__SSi;
if (alreadyReady) {
callback();
} else {
} else {
var obsService =
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var observer = {
var observer = {
observe: function(subject, topic, data) {
try {
if (topic == "browser-delayed-startup-finished") {
@ -77,18 +77,18 @@ Storage = {
}
}
};
obsService.addObserver(
observer, "browser-delayed-startup-finished", false);
}
} catch(e) {
Utils.log(e);
}
}
},
// ----------
// Function: init
// Sets up the object.
// Sets up the object.
init: function() {
this._sessionStore =
Components.classes["@mozilla.org/browser/sessionstore;1"]
@ -97,33 +97,33 @@ Storage = {
// ----------
// Function: wipe
// Cleans out all the stored data, leaving empty objects.
// Cleans out all the stored data, leaving empty objects.
wipe: function() {
try {
var win = Utils.getCurrentWindow();
var self = this;
// ___ Tabs
Tabs.forEach(function(tab) {
self.saveTab(tab.raw, null);
});
// ___ Other
this.saveGroupsData(win, {});
this.saveUIData(win, {});
this.saveVisibilityData(win, {});
this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
JSON.stringify({}));
} catch (e) {
Utils.log("Error in wipe: "+e);
}
},
// ----------
// Function: saveTab
// Saves the data for a single tab.
// Saves the data for a single tab.
saveTab: function(tab, data) {
Utils.assert('tab', tab);
@ -148,14 +148,14 @@ Storage = {
// getWindowValue will fail if the property doesn't exist
Utils.log(e);
}
/* Utils.log('tab', existingData); */
return existingData;
},
// ----------
// Function: saveGroup
// Saves the data for a single group, associated with a specific window.
// Saves the data for a single group, associated with a specific window.
saveGroup: function(win, data) {
var id = data.id;
var existingData = this.readGroupData(win);
@ -193,28 +193,28 @@ Storage = {
// ----------
// Function: saveGroupsData
// Saves the global data for the <Groups> singleton for the given window.
// Saves the global data for the <Groups> singleton for the given window.
saveGroupsData: function(win, data) {
this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data);
},
// ----------
// Function: readGroupsData
// Reads the global data for the <Groups> singleton for the given window.
// Reads the global data for the <Groups> singleton for the given window.
readGroupsData: function(win) {
return this.readData(win, this.GROUPS_DATA_IDENTIFIER);
},
// ----------
// Function: saveUIData
// Saves the global data for the <UIClass> singleton for the given window.
// Saves the global data for the <UIClass> singleton for the given window.
saveUIData: function(win, data) {
this.saveData(win, this.UI_DATA_IDENTIFIER, data);
},
// ----------
// Function: readUIData
// Reads the global data for the <UIClass> singleton for the given window.
// Reads the global data for the <UIClass> singleton for the given window.
readUIData: function(win) {
return this.readData(win, this.UI_DATA_IDENTIFIER);
},
@ -232,23 +232,23 @@ Storage = {
readVisibilityData: function(win) {
return this.readData(win, this.VISIBILITY_DATA_IDENTIFIER);
},
// ----------
// Function: saveData
// Generic routine for saving data to a window.
// Generic routine for saving data to a window.
saveData: function(win, id, data) {
try {
this._sessionStore.setWindowValue(win, id, JSON.stringify(data));
} catch (e) {
Utils.log("Error in saveData: "+e);
}
/* Utils.log('save data', id, data); */
},
// ----------
// Function: readData
// Generic routine for reading data from a window.
// Generic routine for reading data from a window.
readData: function(win, id) {
var existingData = {};
try {
@ -258,7 +258,7 @@ Storage = {
} catch (e) {
Utils.log("Error in readData: "+e);
}
/* Utils.log('read data', id, existingData); */
return existingData;
}

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

@ -43,12 +43,12 @@
// ##########
// Class: TabItem
// An <Item> that represents a tab.
// An <Item> that represents a tab.
window.TabItem = function(container, tab) {
Utils.assert('container', container);
Utils.assert('tab', tab);
Utils.assert('tab.mirror', tab.mirror);
this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
this.locked = {};
this.isATabItem = true;
@ -59,14 +59,14 @@ window.TabItem = function(container, tab) {
// ___ set up div
var $div = iQ(container);
var self = this;
$div.data('tabItem', this);
this.isDragging = false;
this.sizeExtra.x = parseInt($div.css('padding-left'))
this.sizeExtra.x = parseInt($div.css('padding-left'))
+ parseInt($div.css('padding-right'));
this.sizeExtra.y = parseInt($div.css('padding-top'))
this.sizeExtra.y = parseInt($div.css('padding-top'))
+ parseInt($div.css('padding-bottom'));
this.bounds = $div.bounds();
@ -75,16 +75,16 @@ window.TabItem = function(container, tab) {
// ___ superclass setup
this._init(container);
// ___ drag/drop
// override dropOptions with custom tabitem methods
// This is mostly to support the phantom groups.
this.dropOptions.drop = function(e){
var $target = iQ(this.container);
var $target = iQ(this.container);
this.isDropTarget = false;
var phantom = $target.data("phantomGroup");
var group = drag.info.item.parent;
if ( group ) {
group.add( drag.info.$el );
@ -93,13 +93,13 @@ window.TabItem = function(container, tab) {
new Group([$target, drag.info.$el], {container:phantom, bounds:phantom.bounds()});
}
};
this.dropOptions.over = function(e){
var $target = iQ(this.container);
this.isDropTarget = true;
$target.removeClass("acceptsDrop");
var groupBounds = Groups.getBoundingBox( [drag.info.$el, $target] );
groupBounds.inset( -20, -20 );
@ -119,49 +119,49 @@ window.TabItem = function(container, tab) {
// Utils.log('updatedBounds:',updatedBounds);
if (updatedBounds)
phantom.css(updatedBounds.css());
phantom.fadeIn();
$target.data("phantomGroup", phantom);
$target.data("phantomGroup", phantom);
};
this.dropOptions.out = function(e){
this.dropOptions.out = function(e){
this.isDropTarget = false;
var phantom = iQ(this.container).data("phantomGroup");
if (phantom) {
if (phantom) {
phantom.fadeOut(function(){
iQ(this).remove();
});
}
};
this.draggable();
this.droppable(true);
// ___ more div setup
$div.mousedown(function(e) {
if (!Utils.isRightClick(e))
self.lastMouseDownTarget = e.target;
});
$div.mouseup(function(e) {
var same = (e.target == self.lastMouseDownTarget);
self.lastMouseDownTarget = null;
if (!same)
return;
if (iQ(e.target).hasClass("close"))
if (iQ(e.target).hasClass("close"))
tab.close();
else {
if (!Items.item(this).isDragging)
if (!Items.item(this).isDragging)
self.zoomIn();
}
});
iQ("<div>")
.addClass('close')
.appendTo($div);
.appendTo($div);
iQ("<div>")
.addClass('expander')
.appendTo($div);
@ -173,15 +173,15 @@ window.TabItem = function(container, tab) {
this.setResizable(true);
this._updateDebugBounds();
TabItems.register(this);
this.tab.mirror.addSubscriber(this, "close", function(who, info) {
TabItems.unregister(self);
self.removeTrenches();
});
});
this.tab.mirror.addSubscriber(this, 'urlChanged', function(who, info) {
if (!self.reconnected && (info.oldURL == 'about:blank' || !info.oldURL))
if (!self.reconnected && (info.oldURL == 'about:blank' || !info.oldURL))
TabItems.reconnect(self);
self.save();
@ -189,15 +189,15 @@ window.TabItem = function(container, tab) {
};
window.TabItem.prototype = iQ.extend(new Item(), {
// ----------
// ----------
// Function: getStorageData
// Get data to be used for persistent storage of this object.
//
// Parameters:
// Get data to be used for persistent storage of this object.
//
// Parameters:
// getImageData - true to include thumbnail pixels (and page title as well); default false
getStorageData: function(getImageData) {
return {
bounds: this.getBounds(),
bounds: this.getBounds(),
userSize: (isPoint(this.userSize) ? new Point(this.userSize) : null),
url: this.tab.url,
groupID: (this.parent ? this.parent.id : 0),
@ -209,9 +209,9 @@ window.TabItem.prototype = iQ.extend(new Item(), {
// ----------
// Function: save
// Store persistent for this object.
//
// Parameters:
// Store persistent for this object.
//
// Parameters:
// saveImageData - true to include thumbnail pixels (and page title as well); default false
save: function(saveImageData) {
try{
@ -225,31 +225,31 @@ window.TabItem.prototype = iQ.extend(new Item(), {
Utils.log("Error in saving tab value: "+e);
}
},
// ----------
// ----------
// Function: getURL
// Returns the URL for the page represented by this tab.
// Returns the URL for the page represented by this tab.
getURL: function() {
return this.tab.url;
},
// ----------
// ----------
// Function: setBounds
// Moves this item to the specified location and size.
//
// Parameters:
// Moves this item to the specified location and size.
//
// Parameters:
// rect - a <Rect> giving the new bounds
// immediately - true if it should not animate; default false
// options - an object with additional parameters, see below
//
// Possible options:
//
// Possible options:
// force - true to always update the DOM even if the bounds haven't changed; default false
setBounds: function(rect, immediately, options) {
if (!isRect(rect)) {
Utils.trace('TabItem.setBounds: rect is not a real rectangle!', rect);
return;
}
if (!options)
options = {};
@ -262,34 +262,34 @@ window.TabItem.prototype = iQ.extend(new Item(), {
var $close = iQ('.close', $container);
var $fav = iQ('.favicon', $container);
var css = {};
const minFontSize = 8;
const maxFontSize = 15;
if (rect.left != this.bounds.left || options.force)
css.left = rect.left;
if (rect.top != this.bounds.top || options.force)
css.top = rect.top;
if (rect.width != this.bounds.width || options.force) {
css.width = rect.width - this.sizeExtra.x;
var scale = css.width / TabItems.tabWidth;
// The ease function ".5+.5*Math.tanh(2*x-2)" is a pretty
// little graph. It goes from near 0 at x=0 to near 1 at x=2
// smoothly and beautifully.
css.fontSize = minFontSize + (maxFontSize-minFontSize)*(.5+.5*Math.tanh(2*scale-2))
}
if (rect.height != this.bounds.height || options.force)
css.height = rect.height - this.sizeExtra.y;
if (rect.height != this.bounds.height || options.force)
css.height = rect.height - this.sizeExtra.y;
if (iQ.isEmptyObject(css))
return;
this.bounds.copy(rect);
// 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.
@ -307,16 +307,16 @@ window.TabItem.prototype = iQ.extend(new Item(), {
});
/* }).dequeue(); */
}
if (css.fontSize && !this.inStack()) {
if (css.fontSize < minFontSize )
$title.fadeOut();//.dequeue();
else
$title.fadeIn();//.dequeue();
}
// Usage
// Usage
// slide({60:0, 70:1}, 66);
// @60- return 0; at @70+ return 1; @65 return 0.5
function slider(bounds, val){
@ -324,7 +324,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
for (var key in bounds){ keys.push(key); bounds[key] = parseFloat(bounds[key]); };
keys.sort(function(a,b){return a-b});
var min = keys[0], max = keys[1];
function slide(value){
if ( value >= max ) return bounds[max];
if ( value <= min ) return bounds[min];
@ -335,7 +335,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
if ( value <= bounds[min] ) return bounds[min];
return value;
}
if ( val == undefined )
return slide;
return slide(val);
@ -343,7 +343,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
if (css.width && !this.inStack()) {
$fav.css({top:4,left:4});
var opacity = slider({70:1, 60:0}, css.width);
$close.show().css({opacity:opacity});
if ( opacity <= .1 ) $close.hide()
@ -356,12 +356,12 @@ window.TabItem.prototype = iQ.extend(new Item(), {
"padding-bottom": pad + "px",
"border-color": "rgba(0,0,0,"+ slider({70:.2, 60:.1}, css.width) +")",
});
}
}
if (css.width && this.inStack()){
$fav.css({top:0, left:0});
var opacity = slider({90:1, 70:0}, css.width);
var pad = slider({90:6, 70:1}, css.width);
$fav.css({
"padding-left": pad + "px",
@ -370,17 +370,17 @@ window.TabItem.prototype = iQ.extend(new Item(), {
"padding-bottom": pad + "px",
"border-color": "rgba(0,0,0,"+ slider({90:.2, 70:.1}, css.width) +")",
});
}
}
this._hasBeenDrawn = true;
}
this._updateDebugBounds();
rect = this.getBounds(); // ensure that it's a <Rect>
if (!isRect(this.bounds))
Utils.trace('TabItem.setBounds: this.bounds is not a real rectangle!', this.bounds);
if (!this.parent && !this.tab.closed)
this.setTrenches(rect);
@ -389,19 +389,19 @@ window.TabItem.prototype = iQ.extend(new Item(), {
// ----------
// Function: inStack
// Returns true if this item is in a stacked group.
// Returns true if this item is in a stacked group.
inStack: function(){
return iQ(this.container).hasClass("stacked");
},
// ----------
// Function: setZ
// Sets the z-index for this item.
// Sets the z-index for this item.
setZ: function(value) {
this.zIndex = value;
iQ(this.container).css({zIndex: value});
},
// ----------
// Function: close
// Closes this item (actually closes the tab associated with it, which automatically
@ -412,37 +412,37 @@ window.TabItem.prototype = iQ.extend(new Item(), {
// No need to explicitly delete the tab data, becasue sessionstore data
// associated with the tab will automatically go away
},
// ----------
// Function: addClass
// Adds the specified CSS class to this item's container DOM element.
// Adds the specified CSS class to this item's container DOM element.
addClass: function(className) {
iQ(this.container).addClass(className);
},
// ----------
// Function: removeClass
// Removes the specified CSS class from this item's container DOM element.
// Removes the specified CSS class from this item's container DOM element.
removeClass: function(className) {
iQ(this.container).removeClass(className);
},
// ----------
// Function: addOnClose
// Accepts a callback that will be called when this item closes.
// The referenceObject is used to facilitate removal if necessary.
// Accepts a callback that will be called when this item closes.
// The referenceObject is used to facilitate removal if necessary.
addOnClose: function(referenceObject, callback) {
this.tab.mirror.addSubscriber(referenceObject, "close", callback);
this.tab.mirror.addSubscriber(referenceObject, "close", callback);
},
// ----------
// Function: removeOnClose
// Removes the close event callback associated with referenceObject.
removeOnClose: function(referenceObject) {
this.tab.mirror.removeSubscriber(referenceObject, "close");
this.tab.mirror.removeSubscriber(referenceObject, "close");
},
// ----------
// ----------
// Function: setResizable
// If value is true, makes this item resizable, otherwise non-resizable.
// Shows/hides a visible resize handle as appropriate.
@ -460,8 +460,8 @@ window.TabItem.prototype = iQ.extend(new Item(), {
this.resizable(false);
}
},
// ----------
// ----------
// Function: makeActive
// Updates this item to visually indicate that it's active.
makeActive: function(){
@ -470,14 +470,14 @@ window.TabItem.prototype = iQ.extend(new Item(), {
},
// ----------
// ----------
// Function: makeDeactive
// Updates this item to visually indicate that it's not active.
makeDeactive: function(){
iQ(this.container).find("canvas").removeClass("focus");
iQ(this.container).find("img.cached-thumb").removeClass("focus");
},
// ----------
// Function: zoomIn
// Allows you to select the tab and zoom in on it, thereby bringing you
@ -488,9 +488,9 @@ window.TabItem.prototype = iQ.extend(new Item(), {
var childHitResult = { shouldZoom: true };
if (this.parent)
childHitResult = this.parent.childHit(this);
if (childHitResult.shouldZoom) {
// Zoom in!
// Zoom in!
var orig = {
width: $tabEl.width(),
height: $tabEl.height(),
@ -498,7 +498,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
};
var scale = window.innerWidth/orig.width;
var tab = this.tab;
function onZoomDone(){
@ -520,25 +520,25 @@ window.TabItem.prototype = iQ.extend(new Item(), {
.removeClass("front");
// If the tab is in a group set then set the active
// group to the tab's parent.
// group to the tab's parent.
if ( self.parent ){
var gID = self.parent.id;
var group = Groups.group(gID);
Groups.setActiveGroup( group );
group.setActiveTab( self );
group.setActiveTab( self );
}
else
Groups.setActiveGroup( null );
if (childHitResult.callback)
childHitResult.callback();
childHitResult.callback();
}
// 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
// right animation function so that you don't see a change in percieved
// right animation function so that you don't see a change in percieved
// animation speed.
var scaleCheat = 1.7;
TabMirror.pausePainting();
@ -554,30 +554,30 @@ window.TabItem.prototype = iQ.extend(new Item(), {
easing: 'fast',
complete: onZoomDone
});
}
}
},
// ----------
// Function: zoomOut
// Handles the zoom down animation after returning to TabCandy.
// It is expected that this routine will be called from the chrome thread
// (in response to Tabs.onFocus()).
//
// Parameters:
//
// Parameters:
// complete - a function to call after the zoom down animation
zoomOut: function(complete) {
var $tab = iQ(this.container);
var box = this.getBounds();
box.width -= this.sizeExtra.x;
box.height -= this.sizeExtra.y;
TabMirror.pausePainting();
var self = this;
$tab.animate({
left: box.left,
top: box.top,
top: box.top,
width: box.width,
height: box.height
}, {
@ -585,37 +585,37 @@ window.TabItem.prototype = iQ.extend(new Item(), {
easing: 'cubic-bezier', // note that this is legal easing, even without parameters
complete: function() { // note that this will happen on the DOM thread
$tab.removeClass('front');
TabMirror.resumePainting();
TabMirror.resumePainting();
self._zoomPrep = false;
self.setBounds(self.getBounds(), true, {force: true});
if (iQ.isFunction(complete))
self.setBounds(self.getBounds(), true, {force: true});
if (iQ.isFunction(complete))
complete();
}
});
},
// ----------
// Function: setZoomPrep
// 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
// 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
// the zoom out animation.
setZoomPrep: function(value) {
var $div = iQ(this.container);
var data;
var box = this.getBounds();
if (value) {
if (value) {
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
// 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
// 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
// frame #3 (the first frame of real animation). Choosing an animation that starts
// fast is key.
var scaleCheat = 2;
@ -623,16 +623,16 @@ window.TabItem.prototype = iQ.extend(new Item(), {
.addClass('front')
.css({
left: box.left * (1-1/scaleCheat),
top: box.top * (1-1/scaleCheat),
top: box.top * (1-1/scaleCheat),
width: window.innerWidth/scaleCheat,
height: box.height * (window.innerWidth / box.width)/scaleCheat
});
} else {
this._zoomPrep = false;
$div.removeClass('front');
this.setBounds(box, true, {force: true});
}
}
}
});
@ -640,9 +640,9 @@ window.TabItem.prototype = iQ.extend(new Item(), {
// Class: TabItems
// Singleton for managing <TabItem>s
window.TabItems = {
minTabWidth: 40,
minTabWidth: 40,
tabWidth: 160,
tabHeight: 120,
tabHeight: 120,
fontSize: 9,
// ----------
@ -650,60 +650,60 @@ window.TabItems = {
// Sets the object up.
init: function() {
this.items = [];
var self = this;
window.TabMirror.customize(function(mirror) {
var $div = iQ(mirror.el);
var tab = mirror.tab;
var item = new TabItem(mirror.el, tab);
item.addOnClose(self, function() {
Items.unsquish(null, item);
});
if (!self.reconnect(item))
Groups.newTab(item);
Groups.newTab(item);
});
},
// ----------
// ----------
// Function: register
// Adds the given <TabItem> to the master list.
// Adds the given <TabItem> to the master list.
register: function(item) {
Utils.assert('item must be a TabItem', item && item.isAnItem);
Utils.assert('only register once per item', this.items.indexOf(item) == -1);
this.items.push(item);
},
// ----------
// ----------
// Function: unregister
// Removes the given <TabItem> from the master list.
// Removes the given <TabItem> from the master list.
unregister: function(item) {
var index = this.items.indexOf(item);
if (index != -1)
this.items.splice(index, 1);
this.items.splice(index, 1);
},
// ----------
// Function: getItems
// Returns a copy of the master array of <TabItem>s.
getItems: function() {
return Utils.copy(this.items);
},
// ----------
// Function: getItemByTabElement
// Given the DOM element that contains the tab's representation on screen,
// Given the DOM element that contains the tab's representation on screen,
// returns the <TabItem> it belongs to.
getItemByTabElement: function(tabElement) {
return iQ(tabElement).data("tabItem");
},
// ----------
// Function: saveAll
// Saves all open <TabItem>s.
//
// Parameters:
// Saves all open <TabItem>s.
//
// Parameters:
// saveImageData - true to include thumbnail pixels (and page title as well); default false
saveAll: function(saveImageData) {
var items = this.getItems();
@ -711,19 +711,19 @@ window.TabItems = {
item.save(saveImageData);
});
},
// ----------
// Function: storageSanity
// Checks the specified data (as returned by TabItem.getStorageData or loaded from storage)
// and returns true if it looks valid.
// TODO: check everything
// TODO: check everything
storageSanity: function(data) {
var sane = true;
if (!isRect(data.bounds)) {
Utils.log('TabItems.storageSanity: bad bounds', data.bounds);
sane = false;
}
return sane;
},
@ -736,33 +736,33 @@ window.TabItems = {
try{
Utils.assert('item', item);
Utils.assert('item.tab', item.tab);
if (item.reconnected)
if (item.reconnected)
return true;
if (!item.tab.raw)
return false;
var tabData = Storage.getTabData(item.tab.raw);
var tabData = Storage.getTabData(item.tab.raw);
if (tabData && this.storageSanity(tabData)) {
if (item.parent)
item.parent.remove(item);
item.setBounds(tabData.bounds, true);
if (isPoint(tabData.userSize))
item.userSize = new Point(tabData.userSize);
if (tabData.groupID) {
var group = Groups.group(tabData.groupID);
if (group) {
group.add(item);
if (item.tab == Utils.activeTab)
group.add(item);
if (item.tab == Utils.activeTab)
Groups.setActiveGroup(item.parent);
}
}
if (tabData.imageData) {
var mirror = item.tab.mirror;
mirror.showCachedData(item.tab, tabData);
@ -772,19 +772,19 @@ window.TabItems = {
mirror.hideCachedData(item.tab);
}, 15000);
}
Groups.updateTabBarForActiveGroup();
item.reconnected = true;
found = true;
} else
item.reconnected = (item.tab.url != 'about:blank');
item.save();
}catch(e){
Utils.log(e);
}
return found;
}
return found;
}
};

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

@ -37,22 +37,22 @@
* ***** END LICENSE BLOCK ***** */
// **********
// Title: trench.js
// Title: trench.js
// ##########
// Class: Trench
//
//
// Class for drag-snapping regions; called "trenches" as they are long and narrow.
// Constructor: Trench
//
//
// Parameters:
// element - the DOM element for Item (Group or TabItem) from which the trench is projected
// xory - either "x" or "y": whether the trench's <position> is along the x- or y-axis.
// In other words, if "x", the trench is vertical; if "y", the trench is horizontal.
// type - either "border" or "guide". Border trenches mark the border of an Item.
// Guide trenches extend out (unless they are intercepted) and act as "guides".
// edge - which edge of the Item that this trench corresponds to.
// edge - which edge of the Item that this trench corresponds to.
// Either "top", "left", "bottom", or "right".
var Trench = function(element, xory, type, edge) {
//----------
@ -126,41 +126,41 @@ Trench.prototype = {
//----------
// Function: setPosition
// set the trench's position.
//
//
// Parameters:
// position - (integer) px center position of the trench
// range - (<Range>) the explicit active range of the trench
// minRange - (<Range>) the minimum range of the trench
setPosition: function Trench_setPos(position, range, minRange) {
this.position = position;
var page = Items.getPageBounds( true );
// optionally, set the range.
if (isRange(range)) {
this.range = range;
} else {
this.range = new Range( 0, (this.xory == 'x' ? page.height : page.width) );
}
// if there's a minRange, set that too.
if (isRange(minRange))
this.minRange = minRange;
// set the appropriate bounds as a rect.
if ( this.xory == "x" ) // vertical
this.rect = new Rect ( this.position - this.radius, this.range.min, 2 * this.radius, this.range.extent );
else // horizontal
this.rect = new Rect ( this.range.min, this.position - this.radius, this.range.extent, 2 * this.radius );
this.show(); // DEBUG
},
//----------
// Function: setActiveRange
// set the trench's currently active range.
//
//
// Parameters:
// activeRange - (<Range>)
setActiveRange: function Trench_setActiveRect(activeRange) {
@ -175,19 +175,19 @@ Trench.prototype = {
this.guideRect = new Rect( this.activeRange.min, this.position, this.activeRange.extent, 0 );
}
},
//----------
// Function: setWithRect
// Set the trench's position using the given rect. We know which side of the rect we should match
// because we've already recorded this information in <edge>.
//
//
// Parameters:
// rect - (<Rect>)
setWithRect: function Trench_setWithRect(rect) {
if (!isRect(rect))
Utils.error('argument must be Rect');
// First, calculate the range for this trench.
// Border trenches are always only active for the length of this range.
// Guide trenches, however, still use this value as its minRange.
@ -208,7 +208,7 @@ Trench.prototype = {
this.setPosition(rect.bottom + this.gutter, range);
} else if (this.type == "guide") {
// guide trenches have no range, but do have a minRange.
if (this.edge == "left")
if (this.edge == "left")
this.setPosition(rect.left, false, range);
else if (this.edge == "right")
this.setPosition(rect.right, false, range);
@ -218,12 +218,12 @@ Trench.prototype = {
this.setPosition(rect.bottom, false, range);
}
},
//----------
// Function: show
//
//
// Show guide (dotted line), if <showGuide> is true.
//
//
// If <Trenches.showDebug> is true, we will draw the trench. Active portions are drawn with 0.5
// opacity. If <active> is false, the entire trench will be
// very translucent.
@ -265,13 +265,13 @@ Trench.prototype = {
activeVisibleTrench.addClass('activeTrench');
else
activeVisibleTrench.removeClass('activeTrench');
visibleTrench.css(this.rect.css());
activeVisibleTrench.css((this.activeRect || this.rect).css());
iQ("body").append(visibleTrench);
iQ("body").append(activeVisibleTrench);
},
//----------
// Function: hide
// Hide the trench.
@ -294,7 +294,7 @@ Trench.prototype = {
// trench should only affect left edges of rectangles. We don't snap right edges to left-edged
// guide trenches. For border trenches, the logic is a bit different, so left snaps to right and
// top snaps to bottom.
//
//
// Parameters:
// rect - (<Rect>) the rectangle in question
// stationaryCorner - which corner is stationary? by default, the top left.
@ -302,7 +302,7 @@ Trench.prototype = {
// assumeConstantSize - (boolean) whether the rect's dimensions are sacred or not
// keepProportional - (boolean) if we are allowed to change the rect's size, whether the
// dimensions should scaled proportionally or not.
//
//
// Returns:
// false - if rect does not overlap with this trench
// newRect - (<Rect>) an adjusted version of rect, if it is affected by this trench
@ -322,7 +322,7 @@ Trench.prototype = {
}
rect.adjustedEdge = edgeToCheck;
switch (edgeToCheck) {
case "left":
if (this.ruleOverlaps(rect.left, rect.yRange)) {
@ -366,16 +366,16 @@ Trench.prototype = {
return rect;
}
}
return false;
},
//----------
// Function: ruleOverlaps
// Computes whether the given "rule" (a line segment, essentially), given by the position and
// range arguments, overlaps with the current trench. Note that this function assumes that
// the rule and the trench are in the same direction: both horizontal, or both vertical.
//
//
// Parameters:
// position - (integer) a position in px
// range - (<Range>) the rule's range
@ -383,27 +383,27 @@ Trench.prototype = {
return (this.position - this.radius <= position && position <= this.position + this.radius
&& this.activeRange.overlaps(range));
},
//----------
// Function: adjustRangeIfIntercept
// Computes whether the given boundary (given as a position and its active range), perpendicular
// to the trench, intercepts the trench or not. If it does, it returns an adjusted <Range> for
// to the trench, intercepts the trench or not. If it does, it returns an adjusted <Range> for
// the trench. If not, it returns false.
//
//
// Parameters:
// position - (integer) the position of the boundary
// range - (<Range>) the target's range, on the trench's transverse axis
adjustRangeIfIntercept: function Trench_adjustRangeIfIntercept(position, range) {
if (this.position - this.radius > range.min && this.position + this.radius < range.max) {
var activeRange = new Range(this.activeRange);
// there are three ways this can go:
// 1. position < minRange.min
// 2. position > minRange.max
// 3. position >= minRange.min && position <= minRange.max
if (position < this.minRange.min) {
activeRange.min = Math.min(this.minRange.min,position);
activeRange.min = Math.min(this.minRange.min,position);
} else if (position > this.minRange.max) {
activeRange.max = Math.max(this.minRange.max,position);
} else {
@ -414,7 +414,7 @@ Trench.prototype = {
}
return false;
},
//----------
// Function: calculateActiveRange
// Computes and sets the <activeRange> for the trench, based on the <Groups> around.
@ -460,7 +460,7 @@ Trench.prototype = {
// ##########
// Class: Trenches
// Singelton for managing all <Trench>es.
// Singelton for managing all <Trench>es.
var Trenches = {
// ---------
// Variables:
@ -477,14 +477,14 @@ var Trenches = {
// preferLeft - (boolean) prefer snapping to the left to the right
preferTop: true,
preferLeft: true,
activeTrenches: {},
trenches: [],
// ---------
// Function: getById
// Return the specified <Trench>.
//
//
// Parameters:
// id - (integer)
getById: function Trenches_getById(id) {
@ -494,10 +494,10 @@ var Trenches = {
// ---------
// Function: register
// Register a new <Trench> and returns the resulting <Trench> ID.
//
//
// Parameters:
// See the constructor <Trench.Trench>'s parameters.
//
//
// Returns:
// id - (int) the new <Trench>'s ID.
register: function Trenches_register(element, xory, type, edge) {
@ -509,11 +509,11 @@ var Trenches = {
// ---------
// Function: registerWithItem
// Register a whole set of <Trench>es using an <Item> and returns the resulting <Trench> IDs.
//
//
// Parameters:
// item - the <Item> to project trenches
// type - either "border" or "guide"
//
//
// Returns:
// ids - array of the new <Trench>es' IDs.
registerWithItem: function Trenches_registerWithItem(item, type) {
@ -535,7 +535,7 @@ var Trenches = {
// ---------
// Function: unregister
// Unregister one or more <Trench>es.
//
//
// Parameters:
// ids - (integer) a single <Trench> ID or (array) a list of <Trench> IDs.
unregister: function Trenches_unregister(ids) {
@ -551,7 +551,7 @@ var Trenches = {
// ---------
// Function: activateOthersTrenches
// Activate all <Trench>es other than those projected by the current element.
//
//
// Parameters:
// element - (DOMElement) the DOM element of the Item being dragged or resized.
activateOthersTrenches: function Trenches_activateOthersTrenches(element) {
@ -585,7 +585,7 @@ var Trenches = {
this.trenches.forEach(function(t) {
t.showGuide = false;
t.show();
});
});
},
// ---------
@ -595,26 +595,26 @@ var Trenches = {
// not leaving the safe bounds of the window.
//
// Parameters:
// rect - (<Rect>) the object's current bounds
// rect - (<Rect>) the object's current bounds
// stationaryCorner - which corner is stationary? by default, the top left.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the rect's dimensions are sacred or not
// keepProportional - (boolean) if we are allowed to change the rect's size, whether the
// dimensions should scaled proportionally or not.
//
//
// Returns:
// (<Rect>) - the updated bounds, if they were updated
// false - if the bounds were not updated
snap: function Trenches_snap(rect,stationaryCorner,assumeConstantSize,keepProportional) {
var aT = this.activeTrenches;
// hide all the guide trenches, because the correct ones will be turned on later.
Trenches.hideGuides();
// if we're currently dragging over a drop-site, don't snap at all.
if (iQ(".acceptsDrop").length)
return;
var updated = false;
var updatedX = false;
var updatedY = false;
@ -629,7 +629,7 @@ var Trenches = {
var newRect = t.rectOverlaps(rect,stationaryCorner,assumeConstantSize,keepProportional);
if (newRect) { // if rectOverlaps returned an updated rect...
if (assumeConstantSize && updatedX && updatedY)
break;
if (assumeConstantSize && updatedX && (newRect.adjustedEdge == "left"||newRect.adjustedEdge == "right"))
@ -639,16 +639,16 @@ var Trenches = {
rect = newRect;
updated = true;
// register this trench as the "snapped trench" for the appropriate edge.
snappedTrenches[newRect.adjustedEdge] = t;
// if updatedX, we don't need to update x any more.
if (newRect.adjustedEdge == "left" && this.preferLeft)
updatedX = true;
if (newRect.adjustedEdge == "right" && !this.preferLeft)
updatedX = true;
// if updatedY, we don't need to update x any more.
if (newRect.adjustedEdge == "top" && this.preferTop)
updatedY = true;
@ -657,7 +657,7 @@ var Trenches = {
}
}
if (updated) {
rect.snappedTrenches = snappedTrenches;
return rect;
@ -672,7 +672,7 @@ var Trenches = {
this.trenches.forEach(function(t){
t.show();
});
},
},
// ---------
// Function: toggleShown

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

@ -39,7 +39,7 @@
* ***** END LICENSE BLOCK ***** */
// **********
// Title: ui.js
// Title: ui.js
(function(){
@ -47,7 +47,7 @@ window.Keys = {meta: false};
// ##########
// Class: Navbar
// Singleton for helping with the browser's nav bar.
// Singleton for helping with the browser's nav bar.
Navbar = {
// ----------
// Variable: urlBar
@ -62,15 +62,15 @@ Navbar = {
// ##########
// Class: Tabbar
// Singleton for managing the tabbar of the browser.
// Singleton for managing the tabbar of the browser.
var Tabbar = {
// ----------
// Variable: el
// The tab bar's element.
// The tab bar's element.
get el() {
return window.Tabs[0].raw.parentNode;
return window.Tabs[0].raw.parentNode;
},
// ----------
// Function: getVisibleTabCount
// Returns the number of tabs that are currently visible
@ -82,7 +82,7 @@ var Tabbar = {
});
return visibleTabCount;
},
// ----------
// Function: getAllTabs
// Returns an array of all tabs which exist in the current window
@ -98,7 +98,7 @@ var Tabbar = {
}
return tabBarTabs;
},
// ----------
// Function: showOnlyTheseTabs
// Hides all of the tabs in the tab bar which are not passed into this function.
@ -107,13 +107,13 @@ var Tabbar = {
// - An array of <BrowserTab> objects.
// - Some options
showOnlyTheseTabs: function(tabs, options){
try {
try {
if (!options)
options = {};
var tabbrowser = Utils.getCurrentWindow().gBrowser;
var tabBarTabs = this.getAllTabs();
// Show all of the tabs in the group.
tabBarTabs.forEach(function(tab){
var collapsed = true;
@ -128,7 +128,7 @@ var Tabbar = {
});
tab.collapsed = collapsed;
});
// Move them (in order) that they appear in the group to the end of the
// tab strip. This way the tab order is matched up to the group's
// thumbnail order.
@ -155,22 +155,22 @@ var Tabbar = {
// ##########
// Class: Page
// Singleton top-level UI manager. TODO: Integrate with <UIClass>.
// Singleton top-level UI manager. TODO: Integrate with <UIClass>.
window.Page = {
startX: 30,
startX: 30,
startY: 70,
closedLastVisibleTab: false,
closedSelectedTabInTabCandy: false,
stopZoomPreparation: false,
// ----------
// Function: isTabCandyVisible
// Returns true if the TabCandy UI is currently shown.
// Returns true if the TabCandy UI is currently shown.
isTabCandyVisible: function(){
return (Utils.getCurrentWindow().document.getElementById("tab-candy-deck").
selectedIndex == 1);
},
// ----------
// Function: hideChrome
// Hides the nav bar, tab bar, etc.
@ -178,11 +178,11 @@ window.Page = {
var currentWin = Utils.getCurrentWindow();
currentWin.document.getElementById("tab-candy-deck").selectedIndex = 1;
currentWin.document.getElementById("tab-candy").contentWindow.focus();
currentWin.gBrowser.updateTitlebar();
this._setActiveTitleColor(true);
},
// ----------
// Function: showChrome
// Shows the nav bar, tab bar, etc.
@ -190,7 +190,7 @@ window.Page = {
var currentWin = Utils.getCurrentWindow();
var tabContainer = currentWin.gBrowser.tabContainer;
currentWin.document.getElementById("tab-candy-deck").selectedIndex = 0;
// set the close button on tab
/* iQ.timeout(function() { // Marshal event from chrome thread to DOM thread */
tabContainer.adjustTabstrip();
@ -202,10 +202,10 @@ window.Page = {
// ----------
// Function: _setActiveTitleColor
// Used on the Mac to make the title bar match the gradient in the rest of the
// TabCandy UI.
//
// Parameters:
// Used on the Mac to make the title bar match the gradient in the rest of the
// TabCandy UI.
//
// Parameters:
// set - true for the special TabCandy color, false for the normal color.
_setActiveTitleColor: function(set) {
// Mac Only
@ -245,19 +245,19 @@ window.Page = {
var activeGroup = Groups.getActiveGroup();
if ( activeGroup )
activeGroup.setTopChild(item);
window.Groups.setActiveGroup(null);
UI.resize(true);
});
}
},
// ----------
// ----------
// Function: init
// Starts this object.
// Starts this object.
init: function() {
var self = this;
// When you click on the background/empty part of TabCandy,
// we create a new group.
var tabCandyContentDoc =
@ -298,22 +298,22 @@ window.Page = {
}
return false;
});
Tabs.onMove(function() {
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
var activeGroup = Groups.getActiveGroup();
if ( activeGroup ) {
activeGroup.reorderBasedOnTabOrder();
activeGroup.reorderBasedOnTabOrder();
}
}, 1);
});
Tabs.onFocus(function() {
self.tabOnFocus(this);
});
},
// ----------
// ----------
// Function: tabOnFocus
// Called when the user switches from one tab to another outside of the TabCandy UI.
tabOnFocus: function(tab) {
@ -321,14 +321,14 @@ window.Page = {
var currentTab = UI.currentTab;
var currentWindow = Utils.getCurrentWindow();
var self = this;
UI.currentTab = focusTab;
// if the last visible tab has just been closed, don't show the chrome UI.
if (this.isTabCandyVisible() &&
(this.closedLastVisibleTab || this.closedSelectedTabInTabCandy)) {
this.closedLastVisibleTab = false;
this.closedSelectedTabInTabCandy = false;
return;
return;
}
// if TabCandy is visible but we didn't just close the last tab or
@ -336,11 +336,11 @@ window.Page = {
if (this.isTabCandyVisible())
this.showChrome();
// reset these vars, just in case.
// reset these vars, just in case.
this.closedLastVisibleTab = false;
this.closedSelectedTabInTabCandy = false;
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
// this value is true when tabcandy is open at browser startup.
if (self.stopZoomPreparation) {
self.stopZoomPreparation = false;
@ -351,18 +351,18 @@ window.Page = {
}
return;
}
if (focusTab != UI.currentTab) {
// things have changed while we were in timeout
return;
}
var visibleTabCount = Tabbar.getVisibleTabCount();
var newItem = null;
if (focusTab && focusTab.mirror)
newItem = TabItems.getItemByTabElement(focusTab.mirror.el);
if (newItem)
Groups.setActiveGroup(newItem.parent);
@ -374,7 +374,7 @@ window.Page = {
if (newItem != oldItem) {
if (oldItem)
oldItem.setZoomPrep(false);
// if the last visible tab is removed, don't set zoom prep because
// we shoud be in the Tab Candy interface.
if (visibleTabCount > 0) {
@ -390,16 +390,16 @@ window.Page = {
}, 1);
},
// ----------
// ----------
_setupKeyHandlers: function(){
var self = this;
iQ(window).keyup(function(e){
if (!e.metaKey) window.Keys.meta = false;
});
iQ(window).keydown(function(event){
if (event.metaKey) window.Keys.meta = true;
if (!self.getActiveTab() || iQ(":focus").length > 0) {
// prevent the default action when tab is pressed so it doesn't gives
// us problem with content focus.
@ -408,8 +408,8 @@ window.Page = {
event.preventDefault();
}
return;
}
}
function getClosestTabBy(norm){
var centers =
[[item.bounds.center(), item] for each(item in TabItems.getItems())];
@ -438,14 +438,14 @@ window.Page = {
case 38: // Up
norm = function(a, me){return a.y < me.y}
break;
}
}
if (norm != null) {
var nextTab = getClosestTabBy(norm);
if (nextTab) {
if (nextTab.inStack() && !nextTab.parent.expanded)
nextTab = nextTab.parent.getChild(0);
self.setActiveTab(nextTab);
self.setActiveTab(nextTab);
}
event.stopPropagation();
event.preventDefault();
@ -462,7 +462,7 @@ window.Page = {
Groups.getOrphanedTabs());
var length = tabItems.length;
var currentIndex = tabItems.indexOf(activeTab);
if (length > 1) {
if (event.shiftKey) {
if (currentIndex == 0) {
@ -475,9 +475,9 @@ window.Page = {
newIndex = 0;
} else {
newIndex = (currentIndex + 1);
}
}
}
self.setActiveTab(tabItems[newIndex]);
self.setActiveTab(tabItems[newIndex]);
}
}
event.stopPropagation();
@ -486,14 +486,14 @@ window.Page = {
});
},
// ----------
// ----------
// Function: createGroupOnDrag
// Called in response to a mousedown in empty space in the TabCandy UI;
// creates a new group based on the user's drag.
createGroupOnDrag: function(e){
const minSize = 60;
const minMinSize = 15;
var startPos = {x:e.clientX, y:e.clientY}
var phantom = iQ("<div>")
.addClass('group phantom')
@ -521,14 +521,14 @@ window.Page = {
setOpacity: function FauxItem_setOpacity( opacity ) {
this.container.css( 'opacity', opacity );
},
// we don't need to pushAway the phantom item at the end, because
// we don't need to pushAway the phantom item at the end, because
// when we create a new Group, it'll do the actual pushAway.
pushAway: function () {},
};
item.setBounds( new Rect( startPos.y, startPos.x, 0, 0 ) );
var dragOutInfo = new Drag(item, e, true); // true = isResizing
function updateSize(e){
var box = new Rect();
box.left = Math.min(startPos.x, e.clientX);
@ -536,32 +536,32 @@ window.Page = {
box.top = Math.min(startPos.y, e.clientY);
box.bottom = Math.max(startPos.y, e.clientY);
item.setBounds(box);
// compute the stationaryCorner
var stationaryCorner = '';
if (startPos.y == box.top)
stationaryCorner += 'top';
else
stationaryCorner += 'bottom';
if (startPos.x == box.left)
stationaryCorner += 'left';
else
stationaryCorner += 'right';
dragOutInfo.snap(stationaryCorner, false, false); // null for ui, which we don't use anyway.
box = item.getBounds();
if (box.width > minMinSize && box.height > minMinSize
&& (box.width > minSize || box.height > minSize))
&& (box.width > minSize || box.height > minSize))
item.setOpacity(1);
else
else
item.setOpacity(0.7);
e.preventDefault();
e.preventDefault();
}
function collapse(){
phantom.animate({
width: 0,
@ -575,11 +575,11 @@ window.Page = {
}
});
}
function finalize(e){
iQ(window).unbind("mousemove", updateSize);
dragOutInfo.stop();
if ( phantom.css("opacity") != 1 )
if ( phantom.css("opacity") != 1 )
collapse();
else {
var bounds = item.getBounds();
@ -593,19 +593,19 @@ window.Page = {
insideTabs.push(tab);
}
}
var group = new Group(insideTabs,{bounds:bounds});
phantom.remove();
dragOutInfo = null;
}
}
iQ(window).mousemove(updateSize)
iQ(Utils.getCurrentWindow()).one('mouseup', finalize);
e.preventDefault();
e.preventDefault();
return false;
},
// ----------
// Function: setActiveTab
// Sets the currently active tab. The idea of a focused tab is useful
@ -619,14 +619,14 @@ window.Page = {
setActiveTab: function(tab){
if (tab == this._activeTab)
return;
if (this._activeTab) {
if (this._activeTab) {
this._activeTab.makeDeactive();
this._activeTab.removeOnClose(this);
}
this._activeTab = tab;
if (this._activeTab) {
var self = this;
this._activeTab.addOnClose(this, function() {
@ -636,7 +636,7 @@ window.Page = {
this._activeTab.makeActive();
}
},
// ----------
// Function: getActiveTab
// Returns the currently active tab as a <TabItem>
@ -649,24 +649,24 @@ window.Page = {
// ##########
// Class: UIClass
// Singleton top-level UI manager. TODO: Integrate with <Page>.
function UIClass() {
function UIClass() {
try {
// Variable: navBar
// A reference to the <Navbar>, for manipulating the browser's nav bar.
// A reference to the <Navbar>, for manipulating the browser's nav bar.
this.navBar = Navbar;
// Variable: tabBar
// A reference to the <Tabbar>, for manipulating the browser's tab bar.
this.tabBar = Tabbar;
// Variable: devMode
// If true (set by an url parameter), adds extra features to the screen.
// If true (set by an url parameter), adds extra features to the screen.
// TODO: Integrate with the dev menu
this.devMode = false;
// Variable: currentTab
// Keeps track of which <Tabs> tab we are currently on.
// Used to facilitate zooming down from a previous tab.
// Used to facilitate zooming down from a previous tab.
this.currentTab = Utils.activeTab;
} catch(e) {
Utils.log(e);
@ -677,7 +677,7 @@ function UIClass() {
UIClass.prototype = {
// ----------
// Function: init
// Must be called after the object is created.
// Must be called after the object is created.
init: function() {
try {
if (window.Tabs)
@ -692,17 +692,17 @@ UIClass.prototype = {
Utils.log(e);
}
},
// -----------
// Function: _secondaryInit
// This is the bulk of the initialization, kicked off automatically by init
// once the system is ready.
_secondaryInit: function() {
try {
try {
var self = this;
this._setBrowserKeyHandler();
// ___ Dev Menu
this.addDevMenu();
@ -717,22 +717,22 @@ UIClass.prototype = {
iQ(window).bind('beforeunload', function() {
// Things may not all be set up by now, so check for everything
if (self.showChrome)
self.showChrome();
self.showChrome();
if (self.tabBar && self.tabBar.showAllTabs)
self.tabBar.showAllTabs();
});
// ___ Page
var currentWindow = Utils.getCurrentWindow();
Page.init();
currentWindow.addEventListener(
"tabcandyshow", function() {
Page.hideChrome();
Page.showTabCandy();
}, false);
currentWindow.addEventListener(
"tabcandyhide", function() {
var activeTab = Page.getActiveTab();
@ -740,7 +740,7 @@ UIClass.prototype = {
activeTab.zoomIn();
}
}, false);
// ___ delay init
Storage.onReady(function() {
self._delayInit();
@ -752,29 +752,29 @@ UIClass.prototype = {
// ----------
// Function: _delayInit
// Called automatically by _secondaryInit once sessionstore is online.
// Called automatically by _secondaryInit once sessionstore is online.
_delayInit : function() {
try {
// ___ Storage
var currentWindow = Utils.getCurrentWindow();
var data = Storage.readUIData(currentWindow);
this.storageSanity(data);
var groupsData = Storage.readGroupsData(currentWindow);
var firstTime = !groupsData || iQ.isEmptyObject(groupsData);
var groupData = Storage.readGroupData(currentWindow);
Groups.reconstitute(groupsData, groupData);
TabItems.init();
if (firstTime) {
var padding = 10;
var infoWidth = 350;
var infoHeight = 350;
var pageBounds = Items.getPageBounds();
pageBounds.inset(padding, padding);
pageBounds.inset(padding, padding);
// ___ make a fresh group
var box = new Rect(pageBounds);
box.width = Math.min(box.width * 0.667, pageBounds.width - (infoWidth + padding));
@ -782,53 +782,53 @@ UIClass.prototype = {
var options = {
bounds: box
};
var group = new Group([], options);
var group = new Group([], options);
var items = TabItems.getItems();
items.forEach(function(item) {
if (item.parent)
item.parent.remove(item);
group.add(item);
});
// ___ make info item
var html =
var html =
"<div class='intro'>"
+ "<h1>Welcome to Firefox Tab Sets</h1>"
+ "<div>(more goes here)</div><br>"
+ "<video src='http://html5demos.com/assets/dizzy.ogv' width='100%' preload controls>"
+ "</div>";
box.left = box.right + padding;
box.width = infoWidth;
box.height = infoHeight;
var infoItem = new InfoItem(box);
infoItem.html(html);
}
}
// ___ resizing
if (data.pageBounds) {
this.pageBounds = data.pageBounds;
this.resize(true);
} else
this.pageBounds = Items.getPageBounds();
var self = this;
iQ(window).resize(function() {
self.resize();
});
// ___ show tab candy at startup
var visibilityData = Storage.readVisibilityData(currentWindow);
if (visibilityData && visibilityData.visible) {
var currentTab = UI.currentTab;
var item;
if (currentTab && currentTab.mirror)
if (currentTab && currentTab.mirror)
item = TabItems.getItemByTabElement(currentTab.mirror.el);
if (item)
item.setZoomPrep(false);
else
@ -836,8 +836,8 @@ UIClass.prototype = {
Page.hideChrome();
} else
Page.showChrome();
Page.showChrome();
// ___ setup observer to save canvas images
Components.utils.import("resource://gre/modules/Services.jsm");
var observer = {
@ -930,7 +930,7 @@ UIClass.prototype = {
}
break;
}
if (!handled) {
// ToDo: the "tabs" binding implements the nsIDOMXULSelectControlElement,
// we might need to rewrite the tabs without using the
@ -948,16 +948,16 @@ UIClass.prototype = {
event.preventDefault();
}
}
}
}
}, false);
},
// ----------
// Function: advanceSelectedTab
// Moves you to the next tab in the current group's tab strip (outside the TabCandy UI).
//
// Parameters:
// reverse - true to go to previous instead of next
// Moves you to the next tab in the current group's tab strip (outside the TabCandy UI).
//
// Parameters:
// reverse - true to go to previous instead of next
// index - go to a particular tab; numerical value from 1 to 9
advanceSelectedTab : function(reverse, index) {
Utils.assert('reverse should be false when index exists', !index || !reverse);
@ -965,7 +965,7 @@ UIClass.prototype = {
var tabs = tabbox.tabs;
var visibleTabs = [];
var selectedIndex;
for (var i = 0; i < tabs.childNodes.length ; i++) {
var tab = tabs.childNodes[i];
if (!tab.collapsed) {
@ -975,7 +975,7 @@ UIClass.prototype = {
}
}
}
// reverse should be false when index exists.
if (index && index > 0) {
if (visibleTabs.length > 1) {
@ -984,7 +984,7 @@ UIClass.prototype = {
} else {
tabs.selectedItem = visibleTabs[visibleTabs.length - 1];
}
}
}
} else {
if (visibleTabs.length > 1) {
if (reverse) {
@ -996,16 +996,16 @@ UIClass.prototype = {
(selectedIndex == (visibleTabs.length - 1)) ? visibleTabs[0] :
visibleTabs[selectedIndex + 1];
}
}
}
}
},
// ----------
// Function: resize
// Update the TabCandy UI contents in response to a window size change.
// Won't do anything if it doesn't deem the resize necessary.
//
// Parameters:
// Update the TabCandy UI contents in response to a window size change.
// Won't do anything if it doesn't deem the resize necessary.
//
// Parameters:
// force - true to update even when "unnecessary"; default false
resize: function(force) {
if ( typeof(force) == "undefined" ) force = false;
@ -1016,17 +1016,17 @@ UIClass.prototype = {
if ( !force && ( isAnimating || !Page.isTabCandyVisible() ) ) {
// TODO: should try again once the animation is done
// Actually, looks like iQ.isAnimating is non-functional;
// perhaps we should clean it out, or maybe we should fix it.
// perhaps we should clean it out, or maybe we should fix it.
return;
}
}
var oldPageBounds = new Rect(this.pageBounds);
var newPageBounds = Items.getPageBounds();
if (newPageBounds.equals(oldPageBounds))
return;
var items = Items.getTopLevelItems();
// compute itemBounds: the union of all the top-level items' bounds.
var itemBounds = new Rect(this.pageBounds); // We start with pageBounds so that we respect
// the empty space the user has left on the page.
@ -1035,12 +1035,12 @@ UIClass.prototype = {
items.forEach(function(item) {
if (item.locked.bounds)
return;
var bounds = item.getBounds();
itemBounds = (itemBounds ? itemBounds.union(bounds) : new Rect(bounds));
});
Groups.repositionNewTabGroup(); // TODO:
Groups.repositionNewTabGroup(); // TODO:
if (newPageBounds.width < this.pageBounds.width && newPageBounds.width > itemBounds.width)
newPageBounds.width = this.pageBounds.width;
@ -1058,32 +1058,32 @@ UIClass.prototype = {
wScale = newPageBounds.width / itemBounds.width;
hScale = newPageBounds.height / this.pageBounds.height;
}
var scale = Math.min(hScale, wScale);
var self = this;
var pairs = [];
items.forEach(function(item) {
if (item.locked.bounds)
return;
var bounds = item.getBounds();
bounds.left += newPageBounds.left - self.pageBounds.left;
bounds.left *= scale;
bounds.width *= scale;
bounds.top += newPageBounds.top - self.pageBounds.top;
bounds.top += newPageBounds.top - self.pageBounds.top;
bounds.top *= scale;
bounds.height *= scale;
pairs.push({
item: item,
bounds: bounds
});
});
Items.unsquish(pairs);
pairs.forEach(function(pair) {
pair.item.setBounds(pair.bounds, true);
pair.item.snap();
@ -1092,20 +1092,20 @@ UIClass.prototype = {
this.pageBounds = Items.getPageBounds();
this.save();
},
// ----------
// Function: addDevMenu
// Fills out the "dev menu" in the TabCandy UI.
addDevMenu: function() {
try {
var self = this;
var $select = iQ('<select>')
.css({
position: 'absolute',
bottom: 5,
right: 5,
zIndex: 99999,
zIndex: 99999,
opacity: .2
})
.appendTo('#content')
@ -1118,44 +1118,44 @@ UIClass.prototype = {
}
iQ(this).val(0);
});
var commands = [{
name: 'dev menu',
name: 'dev menu',
code: function() {
}
}, {
name: 'show trenches',
name: 'show trenches',
code: function() {
Trenches.toggleShown();
iQ(this).html((Trenches.showDebug ? 'hide' : 'show') + ' trenches');
}
}, {
name: 'refresh',
name: 'refresh',
code: function() {
location.href = 'tabcandy.html';
}
}, {
name: 'reset',
name: 'reset',
code: function() {
self.reset();
}
}, {
name: 'code docs',
name: 'code docs',
code: function() {
self.newTab('http://hg.mozilla.org/labs/tabcandy/raw-file/tip/content/doc/index.html');
}
}, {
name: 'save',
name: 'save',
code: function() {
self.saveAll();
}
}, {
name: 'group sites',
name: 'group sites',
code: function() {
self.arrangeBySite();
}
}];
var count = commands.length;
var a;
for (a = 0; a < count; a++) {
@ -1175,14 +1175,14 @@ UIClass.prototype = {
// Wipes all TabCandy storage and refreshes, giving you the "first-run" state.
reset: function() {
Storage.wipe();
location.href = '';
location.href = '';
},
// ----------
// Function: saveAll
// Saves all data associated with TabCandy.
// Saves all data associated with TabCandy.
// TODO: Save info items
saveAll: function() {
saveAll: function() {
this.save();
Groups.saveAll();
TabItems.saveAll();
@ -1191,31 +1191,31 @@ UIClass.prototype = {
// ----------
// Function: save
// Saves the data for this object to persistent storage
save: function() {
if (!this.initialized)
save: function() {
if (!this.initialized)
return;
var data = {
pageBounds: this.pageBounds
};
if (this.storageSanity(data))
Storage.saveUIData(Utils.getCurrentWindow(), data);
},
// ----------
// Function: storageSanity
// Given storage data for this object, returns true if it looks valid.
// Given storage data for this object, returns true if it looks valid.
storageSanity: function(data) {
if (iQ.isEmptyObject(data))
return true;
if (!isRect(data.pageBounds)) {
Utils.log('UI.storageSanity: bad pageBounds', data.pageBounds);
data.pageBounds = null;
return false;
}
return true;
},
@ -1236,30 +1236,30 @@ UIClass.prototype = {
set.forEach(function(el) {
group.add(el);
});
} else
new Group(set, {dontPush: true, dontArrange: true, title: key});
} else
new Group(set, {dontPush: true, dontArrange: true, title: key});
}
Groups.removeAll();
var newTabsGroup = Groups.getNewTabGroup();
var groups = [];
var items = TabItems.getItems();
items.forEach(function(item) {
var url = item.getURL();
var domain = url.split('/')[2];
var url = item.getURL();
var domain = url.split('/')[2];
if (!domain)
newTabsGroup.add(item);
else {
var domainParts = domain.split('.');
var mainDomain = domainParts[domainParts.length - 2];
if (groups[mainDomain])
if (groups[mainDomain])
groups[mainDomain].push(item.container);
else
else
groups[mainDomain] = [item.container];
}
});
var leftovers = [];
for (key in groups) {
var set = groups[key];
@ -1268,12 +1268,12 @@ UIClass.prototype = {
} else
leftovers.push(set[0]);
}
putInGroup(leftovers, 'mixed');
Groups.arrange();
},
},
// ----------
// Function: newTab
// Opens a new tab with the given URL.

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

@ -83,9 +83,9 @@ var iQ = function(selector, context) {
iQ.fn = iQ.prototype = {
// ----------
// Function: init
// You don't call this directly; this is what's called by iQ().
// It works pretty much like jQuery(), with a few exceptions,
// most notably that you can't use strings with complex html,
// You don't call this directly; this is what's called by iQ().
// It works pretty much like jQuery(), with a few exceptions,
// most notably that you can't use strings with complex html,
// just simple tags like '<div>'.
init: function( selector, context ) {
var match, elem, ret, doc;
@ -101,7 +101,7 @@ iQ.fn = iQ.prototype = {
this.length = 1;
return this;
}
// The body element only exists once, optimize finding it
if ( selector === "body" && !context ) {
this.context = document;
@ -137,9 +137,9 @@ iQ.fn = iQ.prototype = {
} else {
Utils.assert('does not support complex HTML creation', false);
}
return iQ.merge( this, selector );
// HANDLE $("#id")
} else {
elem = document.getElementById( match[2] );
@ -196,9 +196,9 @@ iQ.fn = iQ.prototype = {
}
}
return ret;
},
// Start with an empty selector
selector: "",
@ -206,8 +206,8 @@ iQ.fn = iQ.prototype = {
iq: "1.4.2",
// The default length of a iQ object is 0
length: 0,
length: 0,
// ----------
// Function: get
// Get the Nth element in the matched element set OR
@ -334,7 +334,7 @@ iQ.fn = iQ.prototype = {
elem.parentNode.removeChild( elem );
}
}
return this;
},
@ -346,7 +346,7 @@ iQ.fn = iQ.prototype = {
elem.removeChild( elem.firstChild );
}
}
return this;
},
@ -354,7 +354,7 @@ iQ.fn = iQ.prototype = {
// Function: width
width: function(unused) {
Utils.assert('does not yet support setting', unused === undefined);
return parseInt(this.css('width'));
return parseInt(this.css('width'));
},
// ----------
@ -373,7 +373,7 @@ iQ.fn = iQ.prototype = {
top: parseInt(this.css('top'))
};
},
// ----------
// Function: bounds
bounds: function(unused) {
@ -381,7 +381,7 @@ iQ.fn = iQ.prototype = {
var p = this.position();
return new Rect(p.left, p.top, this.width(), this.height());
},
// ----------
// Function: data
data: function(key, value) {
@ -391,19 +391,19 @@ iQ.fn = iQ.prototype = {
data = this[0].iQData;
return (data ? data[key] : null);
}
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
data = elem.iQData;
if (!data)
data = elem.iQData = {};
data[key] = value;
}
return this;
return this;
},
// ----------
// Function: html
// TODO: security
@ -411,11 +411,11 @@ iQ.fn = iQ.prototype = {
Utils.assert('does not yet support multi-objects (or null objects)', this.length == 1);
if (value === undefined)
return this[0].innerHTML;
this[0].innerHTML = value;
return this;
},
},
// ----------
// Function: text
text: function(value) {
@ -423,10 +423,10 @@ iQ.fn = iQ.prototype = {
if (value === undefined) {
return this[0].textContent;
}
return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode(value));
},
},
// ----------
// Function: val
val: function(value) {
@ -434,11 +434,11 @@ iQ.fn = iQ.prototype = {
if (value === undefined) {
return this[0].value;
}
this[0].value = value;
this[0].value = value;
return this;
},
},
// ----------
// Function: appendTo
appendTo: function(selector) {
@ -446,7 +446,7 @@ iQ.fn = iQ.prototype = {
iQ(selector).append(this);
return this;
},
// ----------
// Function: append
append: function(selector) {
@ -456,7 +456,7 @@ iQ.fn = iQ.prototype = {
this[0].appendChild(object[0]);
return this;
},
// ----------
// Function: attr
// Sets or gets an attribute on the element(s).
@ -464,16 +464,16 @@ iQ.fn = iQ.prototype = {
try {
Utils.assert('string key', typeof key === 'string');
if (value === undefined) {
Utils.assert('retrieval does not support multi-objects (or null objects)', this.length == 1);
Utils.assert('retrieval does not support multi-objects (or null objects)', this.length == 1);
return this[0].getAttribute(key);
}
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
elem.setAttribute(key, value);
}
}
} catch(e) {
Utils.log(e);
}
return this;
},
@ -481,18 +481,18 @@ iQ.fn = iQ.prototype = {
// Function: css
css: function(a, b) {
var properties = null;
if (typeof a === 'string') {
var key = a;
var key = a;
if (b === undefined) {
Utils.assert('retrieval does not support multi-objects (or null objects)', this.length == 1);
Utils.assert('retrieval does not support multi-objects (or null objects)', this.length == 1);
var substitutions = {
'MozTransform': '-moz-transform',
'zIndex': 'z-index'
};
return window.getComputedStyle(this[0], null).getPropertyValue(substitutions[key] || key);
return window.getComputedStyle(this[0], null).getPropertyValue(substitutions[key] || key);
}
properties = {};
properties[key] = b;
@ -508,79 +508,79 @@ iQ.fn = iQ.prototype = {
'width': true,
'height': true
};
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
for (var key in properties) {
var value = properties[key];
if (pixels[key] && typeof(value) != 'string')
if (pixels[key] && typeof(value) != 'string')
value += 'px';
if (key.indexOf('-') != -1)
elem.style.setProperty(key, value, '');
else
elem.style[key] = value;
}
}
return this;
return this;
},
// ----------
// Function: animate
// Uses CSS transitions to animate the element.
//
// Parameters:
// Uses CSS transitions to animate the element.
//
// Parameters:
// css - an object map of the CSS properties to change
// options - an object with various properites (see below)
//
// Possible "options" properties:
// Possible "options" properties:
// duration - how long to animate, in milliseconds
// easing - easing function to use. Possibilities include 'tabcandyBounce', 'easeInQuad'.
// Default is 'ease'.
// easing - easing function to use. Possibilities include 'tabcandyBounce', 'easeInQuad'.
// Default is 'ease'.
// complete - function to call once the animation is done, takes nothing in, but "this"
// is set to the element that was animated.
// is set to the element that was animated.
animate: function(css, options) {
try {
Utils.assert('does not yet support multi-objects (or null objects)', this.length == 1);
if (!options)
options = {};
var easings = {
tabcandyBounce: 'cubic-bezier(0.0, 0.63, .6, 1.29)',
tabcandyBounce: 'cubic-bezier(0.0, 0.63, .6, 1.29)',
easeInQuad: 'ease-in', // TODO: make it a real easeInQuad, or decide we don't care
fast: 'cubic-bezier(0.7,0,1,1)'
};
var duration = (options.duration || 400);
var easing = (easings[options.easing] || 'ease');
// The latest versions of Firefox do not animate from a non-explicitly set
// css properties. So for each element to be animated, go through and
// explicitly define 'em.
var rupper = /([A-Z])/g;
var rupper = /([A-Z])/g;
this.each(function(elem){
var cStyle = window.getComputedStyle(elem, null);
var cStyle = window.getComputedStyle(elem, null);
for (var prop in css){
prop = prop.replace( rupper, "-$1" ).toLowerCase();
iQ(elem).css(prop, cStyle.getPropertyValue(prop));
}
}
});
this.css({
'-moz-transition-property': 'all', // TODO: just animate the properties we're changing
'-moz-transition-duration': (duration / 1000) + 's',
'-moz-transition-property': 'all', // TODO: just animate the properties we're changing
'-moz-transition-duration': (duration / 1000) + 's',
'-moz-transition-timing-function': easing
});
this.css(css);
var self = this;
iQ.timeout(function() {
self.css({
'-moz-transition-property': 'none',
'-moz-transition-duration': '',
'-moz-transition-property': 'none',
'-moz-transition-duration': '',
'-moz-transition-timing-function': ''
});
@ -590,10 +590,10 @@ iQ.fn = iQ.prototype = {
} catch(e) {
Utils.log(e);
}
return this;
},
// ----------
// Function: fadeOut
fadeOut: function(callback) {
@ -608,14 +608,14 @@ iQ.fn = iQ.prototype = {
if (iQ.isFunction(callback))
callback.apply(this);
}
});
});
} catch(e) {
Utils.log(e);
}
return this;
},
// ----------
// Function: fadeIn
fadeIn: function() {
@ -625,14 +625,14 @@ iQ.fn = iQ.prototype = {
opacity: 1
}, {
duration: 400
});
});
} catch(e) {
Utils.log(e);
}
return this;
},
// ----------
// Function: hide
hide: function() {
@ -641,10 +641,10 @@ iQ.fn = iQ.prototype = {
} catch(e) {
Utils.log(e);
}
return this;
},
// ----------
// Function: show
show: function() {
@ -653,13 +653,13 @@ iQ.fn = iQ.prototype = {
} catch(e) {
Utils.log(e);
}
return this;
},
// ----------
// Function: bind
// Binds the given function to the given event type. Also wraps the function
// Binds the given function to the given event type. Also wraps the function
// in a try/catch block that does a Utils.log on any errors.
bind: function(type, func) {
Utils.assert('does not support eventData argument', iQ.isFunction(func));
@ -675,56 +675,56 @@ iQ.fn = iQ.prototype = {
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
if (!elem.iQEventData)
elem.iQEventData = {};
if (!elem.iQEventData[type])
elem.iQEventData[type] = [];
elem.iQEventData[type].push({
original: func,
original: func,
modified: handler
});
elem.addEventListener(type, handler, false);
}
return this;
return this;
},
// ----------
// Function: one
one: function(type, func) {
Utils.assert('does not support eventData argument', iQ.isFunction(func));
var handler = function(e) {
iQ(this).unbind(type, handler);
return func.apply(this, [e]);
};
return this.bind(type, handler);
},
// ----------
// Function: unbind
unbind: function(type, func) {
Utils.assert('Must provide a function', iQ.isFunction(func));
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
var handler = func;
if (elem.iQEventData && elem.iQEventData[type]) {
for (var a = 0, count = elem.iQEventData[type].length; a < count; a++) {
var pair = elem.iQEventData[type][a];
if (pair.original == func) {
handler = pair.modified;
handler = pair.modified;
elem.iQEventData[type].splice(a, 1);
break;
}
}
}
elem.removeEventListener(type, handler, false);
}
return this;
return this;
}
};
@ -798,13 +798,13 @@ iQ.extend({
// Variable: animationCount
// For internal use only
animationCount: 0,
// ----------
// Function: isAnimating
isAnimating: function() {
return (this.animationCount != 0);
},
// -----------
// Function: isFunction
isFunction: function( obj ) {
@ -826,20 +826,20 @@ iQ.extend({
if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
return false;
}
// Not own constructor property must be Object
if ( obj.constructor
&& !hasOwnProperty.call(obj, "constructor")
&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || hasOwnProperty.call( obj, key );
},
@ -851,7 +851,7 @@ iQ.extend({
}
return true;
},
// ----------
// Function: merge
merge: function( first, second ) {
@ -861,7 +861,7 @@ iQ.extend({
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
@ -877,7 +877,7 @@ iQ.extend({
// Function: timeout
// wraps setTimeout with try/catch
timeout: function(func, delay) {
setTimeout(function() {
setTimeout(function() {
try {
func();
} catch(e) {
@ -904,7 +904,7 @@ iQ.extend({
'blur',
'focus'
];
events.forEach(function(event) {
iQ.fn[event] = function(func) {
return this.bind(event, func);

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

@ -41,7 +41,7 @@
(function(){
// ----------
// ----------
// Function: _isIFrame
function _isIframe(doc){
var win = doc.defaultView;
@ -51,7 +51,7 @@ function _isIframe(doc){
// ##########
// Class: TabCanvas
// Takes care of the actual canvas for the tab thumbnail
var TabCanvas = function(tab, canvas){
var TabCanvas = function(tab, canvas){
this.init(tab, canvas);
};
@ -62,28 +62,28 @@ TabCanvas.prototype = {
this.tab = tab;
this.canvas = canvas;
this.window = window;
var $canvas = iQ(canvas).data("link", this);
var w = $canvas.width();
var h = $canvas.height();
canvas.width = w;
canvas.height = h;
var self = this;
this.paintIt = function(evt) {
this.paintIt = function(evt) {
// note that "window" is unreliable in this context, so we'd use self.window if needed
self.tab.mirror.triggerPaint();
/* self.window.Utils.log('paint it', self.tab.url); */
};
},
// ----------
// Function: attach
attach: function() {
this.tab.contentWindow.addEventListener("MozAfterPaint", this.paintIt, false);
},
// ----------
// Function: detach
detach: function() {
@ -93,25 +93,25 @@ TabCanvas.prototype = {
// ignore
}
},
// ----------
// Function: paint
paint: function(evt){
var ctx = this.canvas.getContext("2d");
var w = this.canvas.width;
var h = this.canvas.height;
if (!w || !h)
return;
var fromWin = this.tab.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();
@ -119,14 +119,14 @@ TabCanvas.prototype = {
try{
ctx.drawWindow( fromWin, fromWin.scrollX, fromWin.scrollY, w/scaler, h/scaler, "#fff" );
} catch(e){
Utils.error('paint', e);
Utils.error('paint', e);
}
ctx.restore();
},
// ----------
// Function: toImageData
// Function: toImageData
toImageData: function() {
return this.canvas.toDataURL("image/png", "");
}
@ -134,13 +134,13 @@ TabCanvas.prototype = {
// ##########
// Class: Mirror
// A single tab in the browser and its visual representation in the tab candy window.
// A single tab in the browser and its visual representation in the tab candy window.
// Note that it implements the <Subscribable> interface.
function Mirror(tab, manager) {
/* Utils.log('creating a mirror'); */
this.tab = tab;
this.manager = manager;
var $div = iQ('<div>')
.data("tab", this.tab)
.addClass('tab')
@ -150,7 +150,7 @@ function Mirror(tab, manager) {
"<span class='tab-title'>&nbsp;</span>"
)
.appendTo('body');
this.needsPaint = 0;
this.canvasSizeForced = false;
this.isShowingCachedData = false;
@ -162,43 +162,43 @@ function Mirror(tab, manager) {
var doc = this.tab.contentDocument;
if ( !_isIframe(doc) ) {
this.tabCanvas = new TabCanvas(this.tab, this.canvasEl);
this.tabCanvas = new TabCanvas(this.tab, this.canvasEl);
this.tabCanvas.attach();
this.triggerPaint();
}
/* Utils.log('applying mirror'); */
this.tab.mirror = this;
this.manager._customize(this);
/* Utils.log('done creating mirror'); */
}
Mirror.prototype = iQ.extend(new Subscribable(), {
Mirror.prototype = iQ.extend(new Subscribable(), {
// ----------
// Function: triggerPaint
// Forces the mirror in question to update its thumbnail.
// Forces the mirror in question to update its thumbnail.
triggerPaint: function() {
var date = new Date();
this.needsPaint = date.getTime();
},
// ----------
// Function: foreceCanvasSize
// Repaints the thumbnail with the given resolution, and forces it
// to stay that resolution until unforceCanvasSize is called.
// Repaints the thumbnail with the given resolution, and forces it
// to stay that resolution until unforceCanvasSize is called.
forceCanvasSize: function(w, h) {
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
// <TabMirror.resumePainting>; if you call forceCanvasSize multiple
// times, you just need a single unforce to clear them all.
// <TabMirror.resumePainting>; if you call forceCanvasSize multiple
// times, you just need a single unforce to clear them all.
unforceCanvasSize: function() {
this.canvasSizeForced = false;
},
@ -206,7 +206,7 @@ Mirror.prototype = iQ.extend(new Subscribable(), {
// ----------
// 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.
// be called at browser startup with the cached data avaliable.
showCachedData: function(tab, tabData) {
this.isShowingCachedData = true;
var mirror = tab.mirror;
@ -220,7 +220,7 @@ Mirror.prototype = iQ.extend(new Subscribable(), {
// ----------
// Function: hideCachedData
// Hides the cached data i.e. image and title and show the canvas.
// Hides the cached data i.e. image and title and show the canvas.
hideCachedData: function(tab) {
this.isShowingCachedData = false;
var mirror = tab.mirror;
@ -236,7 +236,7 @@ var TabMirror = function() {
if (window.Tabs) {
this.init();
}
else {
else {
var self = this;
TabsManager.addSubscriber(this, 'load', function() {
self.init();
@ -252,7 +252,7 @@ TabMirror.prototype = {
var self = this;
// When a tab is opened, create the mirror
Tabs.onOpen(function() {
Tabs.onOpen(function() {
var tab = this;
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
self.update(tab);
@ -275,7 +275,7 @@ TabMirror.prototype = {
}
});
// When a tab is closed, unlink.
// When a tab is closed, unlink.
Tabs.onClose( function(){
var tab = this;
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
@ -289,11 +289,11 @@ TabMirror.prototype = {
});
this.paintingPaused = 0;
this.heartbeatIndex = 0;
this.heartbeatIndex = 0;
this._fireNextHeartbeat();
},
// ----------
// ----------
// Function: _heartbeat
_heartbeat: function() {
try {
@ -304,9 +304,9 @@ TabMirror.prototype = {
this.heartbeatIndex++;
if (this.heartbeatIndex >= count)
this.heartbeatIndex = 0;
var tab = Tabs[this.heartbeatIndex];
var mirror = tab.mirror;
var mirror = tab.mirror;
if (mirror) {
var iconUrl = tab.raw.linkedBrowser.mIconURL;
if ( iconUrl == null ){
@ -316,8 +316,8 @@ TabMirror.prototype = {
var label = tab.raw.label;
var $name = iQ(mirror.nameEl);
var $canvas = iQ(mirror.canvasEl);
if (iconUrl != mirror.favEl.src) {
if (iconUrl != mirror.favEl.src) {
mirror.favEl.src = iconUrl;
mirror.triggerPaint();
}
@ -329,12 +329,12 @@ TabMirror.prototype = {
'urlChanged', {oldURL: oldURL, newURL: tab.url});
mirror.triggerPaint();
}
if (!mirror.isShowingCachedData && $name.text() != label) {
$name.text(label);
mirror.triggerPaint();
}
if (!mirror.canvasSizeForced) {
var w = $canvas.width();
var h = $canvas.height();
@ -344,10 +344,10 @@ TabMirror.prototype = {
mirror.triggerPaint();
}
}
if (mirror.needsPaint) {
mirror.tabCanvas.paint();
if (Utils.getMilliseconds() - mirror.needsPaint > 5000)
mirror.needsPaint = 0;
}
@ -356,33 +356,33 @@ TabMirror.prototype = {
} catch(e) {
Utils.error('heartbeat', e);
}
this._fireNextHeartbeat();
},
// ----------
// ----------
// Function: _fireNextHeartbeat
_fireNextHeartbeat: function() {
var self = this;
iQ.timeout(function() {
self._heartbeat();
}, 100);
},
// ----------
},
// ----------
// Function: _customize
_customize: function(func){
// pass
// This gets set by add-ons/extensions to MirrorTab
},
// ----------
// ----------
// Function: _createEl
_createEl: function(tab){
new Mirror(tab, this); // sets tab.mirror to itself
},
// ----------
// ----------
// Function: update
update: function(tab){
this.link(tab);
@ -390,20 +390,20 @@ TabMirror.prototype = {
if (tab.mirror && tab.mirror.tabCanvas)
tab.mirror.triggerPaint();
},
// ----------
// ----------
// Function: link
link: function(tab){
// Don't add duplicates
if (tab.mirror)
return false;
// Add the tab to the page
this._createEl(tab);
return true;
},
// ----------
// ----------
// Function: unlink
unlink: function(tab){
var mirror = tab.mirror;
@ -412,9 +412,9 @@ TabMirror.prototype = {
var tabCanvas = mirror.tabCanvas;
if (tabCanvas)
tabCanvas.detach();
iQ(mirror.el).remove();
tab.mirror = null;
}
}
@ -422,46 +422,46 @@ TabMirror.prototype = {
// ----------
window.TabMirror = {
_private: new TabMirror(),
_private: new TabMirror(),
// Function: customize
// Allows you to customize the tab representations as they are created.
//
// Parameters:
// func - a callback function that will be called every time a new
// tab or tabs are created. func should take in one parameter, a
// <Mirror> representing the tab in question.
// Allows you to customize the tab representations as they are created.
//
// Parameters:
// func - a callback function that will be called every time a new
// tab or tabs are created. func should take in one parameter, a
// <Mirror> representing the tab in question.
customize: function(func) {
// Apply the custom handlers to all existing elements
iQ('div.tab').each(function(elem) {
var tab = Tabs.tab(elem);
func(tab.mirror);
});
// Apply it to all future elements.
TabMirror.prototype._customize = func;
},
// Function: pausePainting
// Tells the TabMirror 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>.
// 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>.
pausePainting: function() {
this._private.paintingPaused++;
},
// Function: resumePainting
// Undoes a call to <pausePainting>. For instance, if you called
// 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 the TabMirror will start updating thumbnails again.
// three times before the TabMirror will start updating thumbnails again.
resumePainting: function() {
this._private.paintingPaused--;
},
// Function: isPaintingPaused
// Returns a boolean indicating whether painting
// is paused or not.
// is paused or not.
isPaintingPaused: function() {
return this._private.paintingPause > 0;
}

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

@ -47,7 +47,7 @@
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// **********
// Title: stacktrace.js
// Title: stacktrace.js
/**
*
@ -57,7 +57,7 @@
function printStackTrace(options) {
var ex = (options && options.e) ? options.e : null;
var guess = (options && options.guess) ? options.guess : false;
var p = new printStackTrace.implementation();
var result = p.run(ex);
return (guess) ? p.guessFunctions(result) : result;
@ -84,7 +84,7 @@ printStackTrace.implementation.prototype = {
return this[mode](ex);
}
},
mode: function() {
try {
(0)();
@ -101,7 +101,7 @@ printStackTrace.implementation.prototype = {
}
return (this._mode = 'other');
},
chrome: function(e) {
return e.stack.replace(/^.*?\n/, '').
replace(/^.*?\n/, '').
@ -111,19 +111,19 @@ printStackTrace.implementation.prototype = {
replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@').
split("\n");
},
firefox: function(e) {
return e.stack.replace(/^.*?\n/, '').
replace(/(?:\n@:0)?\s+$/m, '').
replace(/^\(/gm, '{anonymous}(').
split("\n");
},
// Opera 7.x and 8.x only!
opera: function(e) {
var lines = e.message.split("\n"), ANON = '{anonymous}',
var lines = e.message.split("\n"), ANON = '{anonymous}',
lineRE = /Line\s+(\d+).*?script\s+(http\S+)(?:.*?in\s+function\s+(\S+))?/i, i, j, len;
for (i = 4, j = 0, len = lines.length; i < len; i += 2) {
if (lineRE.test(lines[i])) {
lines[j++] = (RegExp.$3 ? RegExp.$3 + '()@' + RegExp.$2 + RegExp.$1 : ANON + '()@' + RegExp.$2 + ':' + RegExp.$1) +
@ -131,21 +131,21 @@ printStackTrace.implementation.prototype = {
lines[i + 1].replace(/^\s+/, '');
}
}
lines.splice(j, lines.length - j);
return lines;
},
// Safari, Opera 9+, IE, and others
other: function(curr) {
var ANON = "{anonymous}", fnRE = /function\s*([\w\-$]+)?\s*\(/i, stack = [], j = 0, fn, args;
var maxStackSize = 10;
while (curr && stack.length < maxStackSize) {
fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
args = Array.prototype.slice.call(curr['arguments']);
stack[j++] = fn + '(' + printStackTrace.implementation.prototype.stringifyArguments(args) + ')';
//Opera bug: if curr.caller does not exist, Opera returns curr (WTF)
if (curr === curr.caller && window.opera) {
//TODO: check for same arguments if possible
@ -155,7 +155,7 @@ printStackTrace.implementation.prototype = {
}
return stack;
},
stringifyArguments: function(args) {
for (var i = 0; i < args.length; ++i) {
var argument = args[i];
@ -169,9 +169,9 @@ printStackTrace.implementation.prototype = {
}
return args.join(',');
},
sourceCache: {},
ajax: function(url) {
var req = this.createXMLHTTPObject();
if (!req) {
@ -182,7 +182,7 @@ printStackTrace.implementation.prototype = {
req.send('');
return req.responseText;
},
createXMLHTTPObject: function() {
// Try XHR methods in order and store XHR factory
var xmlhttp, XMLHttpFactories = [
@ -205,14 +205,14 @@ printStackTrace.implementation.prototype = {
} catch (e) {}
}
},
getSource: function(url) {
if (!(url in this.sourceCache)) {
this.sourceCache[url] = this.ajax(url).split("\n");
}
return this.sourceCache[url];
},
guessFunctions: function(stack) {
for (var i = 0; i < stack.length; ++i) {
var reStack = /{anonymous}\(.*\)@(\w+:\/\/([-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/;
@ -227,7 +227,7 @@ printStackTrace.implementation.prototype = {
}
return stack;
},
guessFunctionName: function(url, lineNo) {
try {
return this.guessFunctionNameFromLines(lineNo, this.getSource(url));
@ -235,7 +235,7 @@ printStackTrace.implementation.prototype = {
return 'getSource failed with url: ' + url + ', exception: ' + e.toString();
}
},
guessFunctionNameFromLines: function(lineNo, source) {
var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/;
var reGuessFunction = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/;

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

@ -48,17 +48,17 @@ const Cr = Components.results;
// ##########
// Class: XULApp
// Singelton
// Singelton
var XULApp = {
appWindowType: "navigator:browser",
// ----------
// ----------
// Function: tabStripForWindow
tabStripForWindow: function(aWindow) {
return aWindow.document.getElementById("content").mStrip;
},
// ----------
// ----------
// Function: openTab
openTab: function(aUrl, aInBackground) {
var window = this.mostRecentAppWindow;
@ -68,7 +68,7 @@ var XULApp = {
tabbrowser.selectedTab = tab;
},
// ----------
// ----------
// Function: getBrowserFromContentWindow
getBrowserFromContentWindow: function(aMainWindow, aWindow) {
var browsers = aMainWindow.gBrowser.browsers;
@ -86,7 +86,7 @@ function Dictionary() {
var keys = [];
var values = [];
// ----------
// ----------
// Function: set
this.set = function set(key, value) {
var id = keys.indexOf(key);
@ -97,7 +97,7 @@ function Dictionary() {
values[id] = value;
};
// ----------
// ----------
// Function: get
this.get = function get(key, defaultValue) {
if (defaultValue === undefined)
@ -108,7 +108,7 @@ function Dictionary() {
return values[id];
};
// ----------
// ----------
// Function: remove
this.remove = function remove(key) {
var id = keys.indexOf(key);
@ -121,15 +121,15 @@ function Dictionary() {
var readOnlyKeys = new ImmutableArray(keys);
var readOnlyValues = new ImmutableArray(values);
// ----------
// ----------
// Variable: keys
this.__defineGetter__("keys", function() { return readOnlyKeys; });
// ----------
// ----------
// Variable: values
this.__defineGetter__("values", function() { return readOnlyValues; });
// ----------
// ----------
// Variable: length
this.__defineGetter__("length", function() { return keys.length; });
}
@ -148,7 +148,7 @@ function ImmutableArray(baseArray) {
};
});
// ----------
// ----------
// Function: toString
self.toString = function() { return "[ImmutableArray]"; };
@ -278,7 +278,7 @@ function EventListenerMixIn(options) {
// ##########
// Class: TabsManager
// Singelton for dealing with the actual tabs in the browser.
// Singelton for dealing with the actual tabs in the browser.
window.TabsManager = iQ.extend(new Subscribable(), {
// ----------
// Function: init
@ -290,16 +290,16 @@ window.TabsManager = iQ.extend(new Subscribable(), {
iQ.timeout(function() {
self.init();
}, 100);
return;
}
var trackedWindows = new Dictionary();
var trackedTabs = new Dictionary();
trackedWindows.set(chromeWindow,
new BrowserWindow(chromeWindow));
var windows = {
get focused() {
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
@ -311,9 +311,9 @@ window.TabsManager = iQ.extend(new Subscribable(), {
return null;
}
};
windows.__proto__ = trackedWindows.values;
var tabs = {
// ----------
get focused() {
@ -322,23 +322,23 @@ window.TabsManager = iQ.extend(new Subscribable(), {
return browserWindow.getFocusedTab();
return null;
},
// ----------
open: function open(url, inBackground) {
if (typeof(inBackground) == 'undefined')
inBackground = false;
var browserWindow = windows.focused;
// TODO: What to do if we have no focused window?
// make a new one?
var tab = browserWindow.addTab(url);
if (!inBackground)
browserWindow.selectedTab = tab; // TODO doesn't seem to be working
return tab;
},
// ----------
tab: function tab(value) {
// assuming value is a DOM element for the time being
@ -348,47 +348,47 @@ window.TabsManager = iQ.extend(new Subscribable(), {
if (result)
Utils.log('turns out the secondary strategy in Tabs.tab() is needed');
}
return result;
},
// ----------
toString: function toString() {
return "[Tabs]";
}
};
var tabsMixIns = new EventListenerMixIns(tabs);
tabsMixIns.add({name: "onReady"});
tabsMixIns.add({name: "onFocus"});
tabsMixIns.add({name: "onClose"});
tabsMixIns.add({name: "onOpen"});
tabsMixIns.add({name: "onMove"});
tabs.__proto__ = trackedTabs.values;
/* Utils.log(tabs); */
function newBrowserTab(tabbrowser, chromeTab) {
var browserTab = new BrowserTab(tabbrowser, chromeTab);
trackedTabs.set(chromeTab, browserTab);
return browserTab;
}
function unloadBrowserTab(chromeTab) {
var browserTab = trackedTabs.get(chromeTab);
trackedTabs.remove(chromeTab);
browserTab._unload();
}
function BrowserWindow(chromeWindow) {
var tabbrowser = chromeWindow.getBrowser();
for (var i = 0; i < tabbrowser.tabContainer.itemCount; i++)
newBrowserTab(tabbrowser,
tabbrowser.tabContainer.getItemAtIndex(i));
const EVENTS_TO_WATCH = ["TabOpen", "TabMove", "TabClose", "TabSelect"];
function onEvent(event) {
// TODO: For some reason, exceptions that are raised outside of this
// function get eaten, rather than logged, so we're adding our own
@ -396,7 +396,7 @@ window.TabsManager = iQ.extend(new Subscribable(), {
try {
// This is a XUL <tab> element of class tabbrowser-tab.
var chromeTab = event.originalTarget;
switch (event.type) {
case "TabSelect":
tabsMixIns.bubble("onFocus",
@ -428,23 +428,23 @@ window.TabsManager = iQ.extend(new Subscribable(), {
Utils.log(e);
}
}
EVENTS_TO_WATCH.forEach(
function(eventType) {
tabbrowser.tabContainer.addEventListener(eventType, onEvent, true);
});
this.addTab = function addTab(url) {
var chromeTab = tabbrowser.addTab(url);
// The TabOpen event has just been triggered, so we
// just need to fetch it from our dictionary now.
return trackedTabs.get(chromeTab);
};
this.getFocusedTab = function getFocusedTab() {
return trackedTabs.get(tabbrowser.selectedTab);
};
Extension.addUnloadMethod(
this,
function() {
@ -456,13 +456,13 @@ window.TabsManager = iQ.extend(new Subscribable(), {
unloadBrowserTab(tabbrowser.tabContainer.getItemAtIndex(i));
});
}
function BrowserTab(tabbrowser, chromeTab) {
var browser = chromeTab.linkedBrowser;
var mixIns = new EventListenerMixIns(this);
var self = this;
mixIns.add(
{name: "onReady",
observe: browser,
@ -485,20 +485,20 @@ window.TabsManager = iQ.extend(new Subscribable(), {
filter: function(event) {
// There's not really much to report here other
// than the Tab itself, but that's already the
// 'this' variable, so just return true for now.
// 'this' variable, so just return true for now.
return true;
}});
*/
this.__proto__ = {
get closed() !browser,
get url() browser && browser.currentURI ? browser.currentURI.spec : null,
get url() browser && browser.currentURI ? browser.currentURI.spec : null,
get favicon() chromeTab && chromeTab.image ? chromeTab.image : null,
get contentWindow() browser && browser.contentWindow ? browser.contentWindow : null,
get contentDocument() browser && browser.contentDocument ? browser.contentDocument : null,
get raw() chromeTab,
get raw() chromeTab,
get tabbrowser() tabbrowser,
isFocused: function() {
@ -509,16 +509,16 @@ window.TabsManager = iQ.extend(new Subscribable(), {
if (browser)
tabbrowser.selectedTab = chromeTab;
},
close: function close() {
if (browser)
tabbrowser.removeTab(chromeTab);
},
toString: function toString() {
return !browser ? "[Closed Browser Tab]" : "[Browser Tab]";
},
_unload: function _unload() {
mixIns.unload();
mixIns = null;
@ -528,15 +528,15 @@ window.TabsManager = iQ.extend(new Subscribable(), {
}
};
}
this.__defineGetter__("tabs", function() { return tabs; });
Extension.addUnloadMethod(
this,
function() {
tabsMixIns.unload();
});
window.Tabs = tabs;
window.Tabs.app = XULApp;
this._sendToSubscribers('load');

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

@ -51,17 +51,17 @@ var consoleService = Cc["@mozilla.org/consoleservice;1"]
// ##########
// Class: Point
// A simple point.
// A simple point.
//
// Constructor: Point
// If a is a Point, creates a copy of it. Otherwise, expects a to be x,
// and creates a Point with it along with y. If either a or y are omitted,
// 0 is used in their place.
// If a is a Point, creates a copy of it. Otherwise, expects a to be x,
// and creates a Point with it along with y. If either a or y are omitted,
// 0 is used in their place.
window.Point = function(a, y) {
if (isPoint(a)) {
// Variable: x
this.x = a.x;
// Variable: y
this.y = a.y;
} else {
@ -72,51 +72,51 @@ window.Point = function(a, y) {
// ----------
// Function: isPoint
// Returns true if the given object (p) looks like a <Point>.
// Note that this is not an actual method of <Point>, but a global routine.
// Returns true if the given object (p) looks like a <Point>.
// Note that this is not an actual method of <Point>, but a global routine.
window.isPoint = function(p) {
return (p && Utils.isNumber(p.x) && Utils.isNumber(p.y));
};
window.Point.prototype = {
// ----------
window.Point.prototype = {
// ----------
// Function: distance
// Returns the distance from this point to the given <Point>.
distance: function(point) {
// Returns the distance from this point to the given <Point>.
distance: function(point) {
var ax = Math.abs(this.x - point.x);
var ay = Math.abs(this.y - point.y);
return Math.sqrt((ax * ax) + (ay * ay));
},
// ----------
// ----------
// Function: plus
// Returns a new point with the result of adding this point to the given <Point>.
plus: function(point) {
// Returns a new point with the result of adding this point to the given <Point>.
plus: function(point) {
return new Point(this.x + point.x, this.y + point.y);
}
};
// ##########
// ##########
// Class: Rect
// A simple rectangle. Note that in addition to the left and width, it also has
// a right property; changing one affects the others appropriately. Same for the
// vertical properties.
// A simple rectangle. Note that in addition to the left and width, it also has
// a right property; changing one affects the others appropriately. Same for the
// vertical properties.
//
// Constructor: Rect
// If a is a Rect, creates a copy of it. Otherwise, expects a to be left,
// and creates a Rect with it along with top, width, and height.
// If a is a Rect, creates a copy of it. Otherwise, expects a to be left,
// and creates a Rect with it along with top, width, and height.
window.Rect = function(a, top, width, height) {
// Note: perhaps 'a' should really be called 'rectOrLeft'
if (isRect(a)) {
// Variable: left
this.left = a.left;
// Variable: top
this.top = a.top;
// Variable: width
this.width = a.width;
// Variable: height
this.height = a.height;
} else {
@ -129,10 +129,10 @@ window.Rect = function(a, top, width, height) {
// ----------
// Function: isRect
// Returns true if the given object (r) looks like a <Rect>.
// Note that this is not an actual method of <Rect>, but a global routine.
// Returns true if the given object (r) looks like a <Rect>.
// Note that this is not an actual method of <Rect>, but a global routine.
window.isRect = function(r) {
return (r
return (r
&& Utils.isNumber(r.left)
&& Utils.isNumber(r.top)
&& Utils.isNumber(r.width)
@ -145,7 +145,7 @@ window.Rect.prototype = {
get right() {
return this.left + this.width;
},
// ----------
set right(value) {
this.width = value - this.left;
@ -156,7 +156,7 @@ window.Rect.prototype = {
get bottom() {
return this.top + this.height;
},
// ----------
set bottom(value) {
this.height = value - this.top;
@ -168,7 +168,7 @@ window.Rect.prototype = {
get xRange() {
return new Range(this.left,this.right);
},
// ----------
// Variable: yRange
// Gives you a new <Range> for the vertical dimension.
@ -183,12 +183,12 @@ window.Rect.prototype = {
return (rect.right > this.left
&& rect.left < this.right
&& rect.bottom > this.top
&& rect.top < this.bottom);
&& rect.top < this.bottom);
},
// ----------
// Function: intersection
// Returns a new <Rect> with the intersection of this rectangle and the give <Rect>,
// Returns a new <Rect> with the intersection of this rectangle and the give <Rect>,
// or null if they don't intersect.
intersection: function(rect) {
var box = new Rect(Math.max(rect.left, this.left), Math.max(rect.top, this.top), 0, 0);
@ -196,15 +196,15 @@ window.Rect.prototype = {
box.bottom = Math.min(rect.bottom, this.bottom);
if (box.width > 0 && box.height > 0)
return box;
return null;
},
// ----------
// Function: containsPoint
// Returns a boolean denoting if the <Point> is inside of
// the bounding rect.
//
//
// Paramaters
// - A <Point>
containsPoint: function(point){
@ -213,7 +213,7 @@ window.Rect.prototype = {
&& point.y > this.top
&& point.y < this.bottom )
},
// ----------
// Function: contains
// Returns a boolean denoting if the <Rect> is contained inside
@ -227,35 +227,35 @@ window.Rect.prototype = {
&& rect.top > this.top
&& rect.bottom < this.bottom )
},
// ----------
// Function: center
// Returns a new <Point> with the center location of this rectangle.
center: function() {
return new Point(this.left + (this.width / 2), this.top + (this.height / 2));
},
// ----------
// Function: size
// Returns a new <Point> with the dimensions of this rectangle.
size: function() {
return new Point(this.width, this.height);
},
// ----------
// Function: position
// Returns a new <Point> with the top left of this rectangle.
// Returns a new <Point> with the top left of this rectangle.
position: function() {
return new Point(this.left, this.top);
},
// ----------
// Function: area
// Returns the area of this rectangle.
// Returns the area of this rectangle.
area: function() {
return this.width * this.height;
},
// ----------
// Function: inset
// Makes the rect smaller (if the arguments are positive) as if a margin is added all around
@ -265,16 +265,16 @@ window.Rect.prototype = {
// - A <Point> or two arguments: x and y
inset: function(a, b) {
if (typeof(a.x) != 'undefined' && typeof(a.y) != 'undefined') {
b = a.y;
b = a.y;
a = a.x;
}
this.left += a;
this.width -= a * 2;
this.top += b;
this.height -= b * 2;
},
// ----------
// Function: offset
// Moves (translates) the rect by the given vector.
@ -290,17 +290,17 @@ window.Rect.prototype = {
this.top += b;
}
},
// ----------
// Function: equals
// Returns true if this rectangle is identical to the given <Rect>.
// Returns true if this rectangle is identical to the given <Rect>.
equals: function(a) {
return (a.left == this.left
&& a.top == this.top
&& a.width == this.width
&& a.height == this.height);
},
// ----------
// Function: union
// Returns a new <Rect> with the union of this rectangle and the given <Rect>.
@ -309,11 +309,11 @@ window.Rect.prototype = {
var newTop = Math.min(a.top, this.top);
var newWidth = Math.max(a.right, this.right) - newLeft;
var newHeight = Math.max(a.bottom, this.bottom) - newTop;
var newRect = new Rect(newLeft, newTop, newWidth, newHeight);
var newRect = new Rect(newLeft, newTop, newWidth, newHeight);
return newRect;
},
// ----------
// Function: copy
// Copies the values of the given <Rect> into this rectangle.
@ -323,7 +323,7 @@ window.Rect.prototype = {
this.width = a.width;
this.height = a.height;
},
// ----------
// Function: css
// Returns an object with the dimensions of this rectangle, suitable for passing into iQ.fn.css.
@ -338,7 +338,7 @@ window.Rect.prototype = {
}
};
// ##########
// ##########
// Class: Range
// A physical interval, with a min and max.
//
@ -356,15 +356,15 @@ window.Range = function(min, max) {
// ----------
// Function: isRange
// Returns true if the given object (r) looks like a <Range>.
// Note that this is not an actual method of <Range>, but a global routine.
// Returns true if the given object (r) looks like a <Range>.
// Note that this is not an actual method of <Range>, but a global routine.
window.isRange = function(r) {
return (r
return (r
&& Utils.isNumber(r.min)
&& Utils.isNumber(r.max));
};
window.Range.prototype = {
window.Range.prototype = {
// Variable: extent
// Equivalent to max-min
get extent() {
@ -404,7 +404,7 @@ window.Range.prototype = {
// Paramaters
// - a number or <Range>
overlaps: function(value) {
return Utils.isNumber(value) ?
return Utils.isNumber(value) ?
this.contains(value) :
( value.min <= this.max && this.min <= value.max );
},
@ -412,7 +412,7 @@ window.Range.prototype = {
// ##########
// Class: Subscribable
// A mix-in for allowing objects to collect subscribers for custom events.
// A mix-in for allowing objects to collect subscribers for custom events.
window.Subscribable = function() {
this.subscribers = null;
};
@ -421,31 +421,31 @@ window.Subscribable.prototype = {
// ----------
// Function: addSubscriber
// The given callback will be called when the Subscribable fires the given event.
// The refObject is used to facilitate removal if necessary.
// The refObject is used to facilitate removal if necessary.
addSubscriber: function(refObject, eventName, callback) {
try {
Utils.assertThrow("refObject", refObject);
Utils.assertThrow("callback must be a function", iQ.isFunction(callback));
Utils.assertThrow("eventName must be a non-empty string",
Utils.assertThrow("eventName must be a non-empty string",
eventName && typeof(eventName) == "string");
if (!this.subscribers)
this.subscribers = {};
if (!this.subscribers[eventName])
this.subscribers[eventName] = [];
var subs = this.subscribers[eventName];
var existing = subs.filter(function(element) {
return element.refObject == refObject;
});
if (existing.length) {
Utils.assert('should only ever be one', existing.length == 1);
existing[0].callback = callback;
} else {
} else {
subs.push({
refObject: refObject,
refObject: refObject,
callback: callback
});
}
@ -453,19 +453,19 @@ window.Subscribable.prototype = {
Utils.log(e);
}
},
// ----------
// Function: removeSubscriber
// Removes the callback associated with refObject for the given event.
// Removes the callback associated with refObject for the given event.
removeSubscriber: function(refObject, eventName) {
try {
Utils.assertThrow("refObject", refObject);
Utils.assertThrow("eventName must be a non-empty string",
Utils.assertThrow("eventName must be a non-empty string",
eventName && typeof(eventName) == "string");
if (!this.subscribers || !this.subscribers[eventName])
return;
this.subscribers[eventName] = this.subscribers[eventName].filter(function(element) {
return element.refObject != refObject;
});
@ -473,21 +473,21 @@ window.Subscribable.prototype = {
Utils.log(e);
}
},
// ----------
// Function: _sendToSubscribers
// Internal routine. Used by the Subscribable to fire events.
_sendToSubscribers: function(eventName, eventInfo) {
try {
Utils.assertThrow("eventName must be a non-empty string",
Utils.assertThrow("eventName must be a non-empty string",
eventName && typeof(eventName) == "string");
if (!this.subscribers || !this.subscribers[eventName])
return;
var self = this;
var subsCopy = iQ.merge([], this.subscribers[eventName]);
subsCopy.forEach(function(object) {
subsCopy.forEach(function(object) {
object.callback(self, eventInfo);
});
} catch(e) {
@ -501,7 +501,7 @@ window.Subscribable.prototype = {
// Singelton with common utility functions.
var Utils = {
_isMac : null,
// ___ Windows and Tabs
// ----------
@ -511,7 +511,7 @@ var Utils = {
try {
var tabBrowser = this.getCurrentWindow().gBrowser;
Utils.assert('tabBrowser', tabBrowser);
var rawTab = tabBrowser.selectedTab;
for ( var i=0; i<Tabs.length; i++){
if (Tabs[i].raw == rawTab)
@ -520,13 +520,13 @@ var Utils = {
} catch(e) {
Utils.log(e);
}
return null;
},
// ----------
// Function: getCurrentWindow
// Returns the nsIDOMWindowInternal for the currently active window,
// Returns the nsIDOMWindowInternal for the currently active window,
// i.e. the window belonging to the active page's DOM "window" object.
getCurrentWindow: function() {
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
@ -540,37 +540,37 @@ var Utils = {
return browserWin;
}
}
return null;
},
// ___ Logging
// ----------
// Function: log
// Prints the given arguments to the JavaScript error console as a message.
// Pass as many arguments as you want, it'll print them all.
log: function() {
// Prints the given arguments to the JavaScript error console as a message.
// Pass as many arguments as you want, it'll print them all.
log: function() {
var text = this.expandArgumentsForLog(arguments);
consoleService.logStringMessage(text);
},
},
// ----------
// Function: error
// Prints the given arguments to the JavaScript error console as an error.
// Pass as many arguments as you want, it'll print them all.
// Prints the given arguments to the JavaScript error console as an error.
// Pass as many arguments as you want, it'll print them all.
// TODO: Does this still work?
error: function() {
error: function() {
var text = this.expandArgumentsForLog(arguments);
Cu.reportError('tabcandy error: ' + text);
},
},
// ----------
// Function: trace
// Prints the given arguments to the JavaScript error console as a message,
// along with a full stack trace.
// Pass as many arguments as you want, it'll print them all.
trace: function() {
// Prints the given arguments to the JavaScript error console as a message,
// along with a full stack trace.
// Pass as many arguments as you want, it'll print them all.
trace: function() {
var text = this.expandArgumentsForLog(arguments);
if (typeof(printStackTrace) != 'function')
this.log(text + ' trace: you need to include stacktrace.js');
@ -579,28 +579,28 @@ var Utils = {
calls.splice(0, 3); // Remove this call and the printStackTrace calls
this.log('trace: ' + text + '\n' + calls.join('\n'));
}
},
},
// ----------
// Function: assert
// Prints a stack trace along with label (as a console message) if condition is false.
// Prints a stack trace along with label (as a console message) if condition is false.
assert: function(label, condition) {
if (!condition) {
var text;
if (typeof(label) == 'undefined')
text = 'badly formed assert';
else
text = 'tabcandy assert: ' + label;
text = 'tabcandy assert: ' + label;
if (typeof(printStackTrace) == 'function') {
var calls = printStackTrace();
text += '\n' + calls[3];
}
this.trace(text);
}
},
// ----------
// Function: assertThrow
// Throws label as an exception if condition is false.
@ -610,31 +610,31 @@ var Utils = {
if (typeof(label) == 'undefined')
text = 'badly formed assert';
else
text = 'tabcandy assert: ' + label;
text = 'tabcandy assert: ' + label;
if (typeof(printStackTrace) == 'function') {
var calls = printStackTrace();
calls.splice(0, 3); // Remove this call and the printStackTrace calls
text += '\n' + calls.join('\n');
}
throw text;
throw text;
}
},
// ----------
// Function: expandObject
// Prints the given object to a string, including all of its properties.
// Prints the given object to a string, including all of its properties.
expandObject: function(obj) {
var s = obj + ' = {';
for (prop in obj) {
var value;
try {
value = obj[prop];
value = obj[prop];
} catch(e) {
value = '[!!error retrieving property]';
}
s += prop + ': ';
if (typeof(value) == 'string')
s += '\'' + value + '\'';
@ -646,11 +646,11 @@ var Utils = {
s += ", ";
}
return s + '}';
},
},
// ----------
// Function: expandArgumentsForLog
// Expands all of the given args (an array) into a single string.
// Expands all of the given args (an array) into a single string.
expandArgumentsForLog: function(args) {
var s = '';
var count = args.length;
@ -659,26 +659,26 @@ var Utils = {
var arg = args[a];
if (typeof(arg) == 'object')
arg = this.expandObject(arg);
s += arg;
if (a < count - 1)
s += '; ';
}
return s;
},
// ----------
// Funtion: testLogging
// Prints some test messages with the various logging methods.
// Prints some test messages with the various logging methods.
testLogging: function() {
this.log('beginning logging test');
this.log('beginning logging test');
this.error('this is an error');
this.trace('this is a trace');
this.log(1, null, {'foo': 'hello', 'bar': 2}, 'whatever');
this.log('ending logging test');
},
},
// ___ Misc
// ----------
@ -687,12 +687,12 @@ var Utils = {
isRightClick: function(event) {
if (event.which)
return (event.which == 3);
if (event.button)
if (event.button)
return (event.button == 2);
return false;
},
// ----------
// Function: getMilliseconds
// Returns the total milliseconds on the system clock right now.
@ -700,21 +700,21 @@ var Utils = {
var date = new Date();
return date.getTime();
},
// ----------
// Function: isDOMElement
// Returns true if the given object is a DOM element.
isDOMElement: function(object) {
return (object && typeof(object.nodeType) != 'undefined' ? true : false);
},
// ----------
// Function: isNumber
// Returns true if the argument is a valid number.
// Returns true if the argument is a valid number.
isNumber: function(n) {
return (typeof(n) == 'number' && !isNaN(n));
},
// ----------
// Function: copy
// Returns a copy of the argument. Note that this is a shallow copy; if the argument
@ -723,10 +723,10 @@ var Utils = {
if (value && typeof(value) == 'object') {
if (iQ.isArray(value))
return iQ.extend([], value);
return iQ.extend({}, value);
}
return value;
},
@ -740,7 +740,7 @@ var Utils = {
getService(Components.interfaces.nsIXULRuntime);
this._isMac = (xulRuntime.OS == "Darwin");
}
return this._isMac;
}
};
@ -749,7 +749,7 @@ window.Utils = Utils;
window.Math.tanh = function tanh(x){
var e = Math.exp(x);
return (e - 1/e) / (e + 1/e);
return (e - 1/e) / (e + 1/e);
}
})();

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

@ -3,13 +3,13 @@ html {
/* image-rendering: -moz-crisp-edges; */
}
body {
body {
font-family: Tahoma, sans-serif !important;
padding: 0px;
padding: 0px;
color: rgba(0,0,0,0.4);
font-size:12px;
line-height: 16px;
margin: 0 auto;
margin: 0 auto;
}
#content {
@ -42,7 +42,7 @@ body {
overflow: visible !important;
-moz-border-radius: 0.4em;
-moz-box-shadow: inset rgba(255, 255, 255, 0.6) 0 0 0 2px;
cursor: pointer;
cursor: pointer;
}
.tab canvas,
@ -54,7 +54,7 @@ body {
.thumb {
width: 100%;
height: 100%;
height: 100%;
}
.thumb-shadow {
@ -69,7 +69,7 @@ body {
position: absolute;
background-color: rgba(245,245,245,1);
-moz-border-radius-bottomright: 0.4em;
-moz-box-shadow:
-moz-box-shadow:
inset rgba(255, 255, 255, 0.6) 0 -2px 0px,
inset rgba(255, 255, 255, 0.6) -2px 0px 0px;
padding: 4px 6px 6px 4px;
@ -167,7 +167,7 @@ body {
border: 1px solid rgba(230,230,230,1);
background-color: rgba(248,248,248,1);
-moz-border-radius: 0.4em;
-moz-box-shadow:
-moz-box-shadow:
inset rgba(255, 255, 255, 0.6) 0 0 0 2px,
rgba(0,0,0, .2) 1px 1px 4px;
}
@ -177,11 +177,11 @@ body {
}
.overlay{
background-color: rgba(0,0,0,.7) !important;
-moz-box-shadow: 3px 3px 8px rgba(0,0,0,.5);
-moz-box-shadow: 3px 3px 8px rgba(0,0,0,.5);
-moz-border-radius: 0.4em;
/*
border: 1px solid rgba(230,230,230,1);
background-color: rgba(248,248,248,1);
@ -203,7 +203,7 @@ body {
border: 1px solid rgba(230,230,230,1);
background-color: rgba(248,248,248,1);
-moz-border-radius: 0.4em;
-moz-box-shadow:
-moz-box-shadow:
inset rgba(255, 255, 255, 0.6) 0 0 0 2px,
rgba(0,0,0, .2) 1px 1px 4px;
}
@ -344,7 +344,7 @@ input.name{
color: #999;
margin: 3px 0px 0px 3px;
padding: 1px;
background-image: url(chrome://browser/skin/tabcandy/edit-light.png);
background-image: url(chrome://browser/skin/tabcandy/edit-light.png);
padding-left: 20px;
}
@ -375,18 +375,18 @@ input.defaultName:hover{
}
.title-shield {
position:absolute;
position:absolute;
margin: 3px 0px 0px 3px;
padding: 1px;
left:0;
top:0;
width:100%;
height:100%;
z-index:10;
left:0;
top:0;
width:100%;
height:100%;
z-index:10;
}
.transparentBorder{
border: 1px solid transparent !important;
border: 1px solid transparent !important;
}
.stackExpander{
@ -404,7 +404,7 @@ input.defaultName:hover{
position: absolute;
bottom: 6px;
right: 6px;
opacity: .2;
opacity: .2;
}
.iq-resizable { }
@ -437,12 +437,12 @@ input.defaultName:hover{
text-align: center;
color: white;
background-color: #9E9E9E;
-moz-box-shadow: 0px 0px 4px rgba(0,0,0,.3), inset 0px 1px 0px rgba(255,255,255,.4);
-moz-box-shadow: 0px 0px 4px rgba(0,0,0,.3), inset 0px 1px 0px rgba(255,255,255,.4);
}
.bottomButton:hover{
cursor: pointer;
background-color: #A5A5A5;
background-color: #A5A5A5;
-moz-box-shadow: 0px 0px 5px rgba(0,0,0,.6), inset 0px 1px 0px rgba(255,255,255,.4);
}

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

@ -11,12 +11,12 @@
<body style="background-color: transparent !important;-moz-appearance: none !important;" transparent="true">
<div id="content">
<div id="feedback" class="bottomButton">give feedback</div>
<div id="feedback" class="bottomButton">give feedback</div>
<div id="reset" class="bottomButton">reset</div>
<div id="bg" />
</div>
<script type="text/javascript;version=1.8" src="tabcandy.js"></script>
</body>
</html>