зеркало из https://github.com/mozilla/gecko-dev.git
rm trailing whitespace
This commit is contained in:
Родитель
2be7d1674c
Коммит
061c70e020
|
@ -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'> </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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче