First commit.

This commit is contained in:
aza@70-7-150-98.pools.spcsdns.net 2010-02-24 01:47:55 -08:00
commit f90716db0f
13 changed files with 1507 additions and 0 deletions

BIN
browser/base/content/tabcandy/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,191 @@
(function(){
$.expr[':'].icontains = function(obj, index, meta, stack){
return (obj.textContent || obj.innerText || jQuery(obj).text() || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0;
};
Navbar = {
get el(){
var win = Utils.activeWindow;
var navbar = win.gBrowser.ownerDocument.getElementById("navigator-toolbox");
return navbar;
},
show: function(){ this.el.collapsed = false; },
hide: function(){ this.el.collapsed = true;}
}
var Tabbar = {
get el(){ return window.Tabs[0].raw.parentNode; },
hide: function(){ this.el.collapsed = true },
show: function(){ this.el.collapsed = false }
}
var Page = {
init: function(){
var isDragging = false;
var zIndex = 100;
function mod($div){
$div.draggable({
start:function(){ isDragging = true; },
stop: function(){
isDragging = false;
$(this).css({zIndex: zIndex});
zIndex += 1;
},
zIndex: 999,
}).mouseup(function(e){
if( e.target.className == "close" ){
$(this).find("canvas").data("link").tab.close(); }
else {
if( !isDragging ){
Navbar.show();
$(this).find("canvas").data("link").tab.focus();
} else {
$(this).find("canvas").data("link").tab.raw.pos = $(this).position();
}
}
});
$("<div class='close'>x</div>").appendTo($div)
}
window.TabMirror.customize(mod);
Utils.homeTab.raw.maxWidth = 60;
Utils.homeTab.raw.minWidth = 60;
Tabs.onClose(function(){
Utils.homeTab.focus();
return false;
})
$("#tabbar").toggle(
function(){Tabbar.hide()},
function(){Tabbar.show()}
)
Page.initSearch();
},
initSearch: function(){
$search = $(".search input");
$search.val("").focus();
$search.keydown(function(evt){
if( evt.which == 13 ){
Navbar.show();
if ($(".tab:not(.unhighlight)").length == 1) {
$(".tab:not(.unhighlight)").find("canvas").data("link").tab.focus();
} else {
Tabs.open( "http://google.com/search?q=" + $search.val() ).focus();
}
$search.val("")
$(".tab .name").parent().removeClass("unhighlight");
}
});
$search.keyup(function(evt){
var $found = $(".tab .name:not(:icontains(" + $search.val() + "))").parent();
if( $search.val().length > 1 ){
$found.addClass("unhighlight");
$(".tab .name:icontains(" + $search.val() + ")").parent().removeClass("unhighlight");
}
else {
$(".tab .name").parent().removeClass("unhighlight");
}
console.log( $found.length );
if ( $found.length == 1 ) {
$found.animate({top:0, left:0})
}
});
Utils.homeTab.onFocus(function(){
$search.val("").focus();
Navbar.hide();
});
$(window).blur(function(){
Navbar.show();
})
}
}
function ArrangeClass(name, func){ this.init(name, func); };
ArrangeClass.prototype = {
init: function(name, func){
this.$el = this._create(name);
this.arrange = func;
if(func) this.$el.click(func);
},
_create: function(name){
return $("<a href='#'/>").text(name).appendTo("#actions");
}
}
var anim = new ArrangeClass("Anim", function(){
if( $("canvas:visible").eq(9).height() < 300 )
$("canvas:visible").eq(9).data("link").animate({height:500}, 500);
else
$("canvas:visible").eq(9).data("link").animate({height:120}, 500);
$("canvas:visible").eq(9).css({zIndex:99999});
})
var grid = new ArrangeClass("Grid", function(){
var x = 10;
var y = 100;
$(".tab:visible").each(function(i){
$el = $(this);
var oldPos = $el.find("canvas").data("link").tab.raw.pos;
if( oldPos ){
$el.css({top:oldPos.top, left:oldPos.left});
return;
}
$el.css({top: y,left: x});
x += $el.width() + 10;
if( x > window.innerWidth - $el.width() ){
x = 10;
y += $el.height() + 30;
}
});
});
var Arrange = {
init: function(){
grid.arrange();
}
}
function UIClass(){ this.init(); };
UIClass.prototype = {
navbar: Navbar,
tabbar: Tabbar,
init: function(){
Page.init();
Arrange.init();
}
}
var UI = new UIClass();
window.UI = UI;
window.aza = ArrangeClass
})();

View File

@ -0,0 +1,218 @@
(function(){
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
function _isIframe(doc){
var win = doc.defaultView;
return win.parent != win;
}
var TabCanvas = function(tab, canvas){ this.init(tab, canvas) }
TabCanvas.prototype = {
init: function(tab, canvas){
this.tab = tab;
this.canvas = canvas;
this.window = window;
this.RATE_LIMIT = 250; // To refresh the thumbnail any faster than this. In ms.
this.lastDraw = null;
$(canvas).data("link", this);
var w = $(canvas).width();
var h = $(canvas).height();
$(canvas).attr({width:w, height:h});
this.paint(null);
var self = this;
var paintIt = function(evt){self.onPaint(evt) };
// Don't mirror chrome tabs.
if( window.location.protocol == "chrome:" ) return;
tab.contentWindow.addEventListener("MozAfterPaint", paintIt, false);
$(window).unload(function(){
tab.contentWindow.removeEventListener("MozAfterPaint", paintIt, false);
})
},
paint: function(evt){
var $ = this.window.$;
if( $ == null ) return;
var $canvas = $(this.canvas);
var ctx = this.canvas.getContext("2d");
var w = $canvas.width();
var h = $canvas.height();
var fromWin = this.tab.contentWindow;
if( fromWin == null || fromWin.location.protocol == "chrome:") return;
var scaler = w/fromWin.innerWidth;
// TODO: Potentially only redraw the dirty rect? (Is it worth it?)
var now = new Date();
if( this.lastDraw == null || now - this.lastDraw > this.RATE_LIMIT ){
var startTime = new Date();
ctx.save();
ctx.scale(scaler, scaler);
ctx.drawWindow( fromWin, fromWin.scrollX, fromWin.scrollY, w/scaler, h/scaler, "#fff" );
ctx.restore();
var elapsed = (new Date()) - startTime;
Utils.logger.log( this.window.location.host + " " + elapsed );
this.lastDraw = new Date();
}
ctx.restore();
},
onPaint: function(evt){
this.paint(evt);
},
animate: function(options, duration){
var self = this;
if( duration == null ) duration = 0;
var $canvas = $(this.canvas);
var w = $canvas.width();
var h = $canvas.height();
var newW = (w/h)*options.height;
var newH = options.height;
$canvas.width(w);
$canvas.height(h);
$canvas.animate({width:newW, height:newH}, duration, function(){
$canvas.attr("width", newW);
$canvas.attr("height", newH);
self.paint(null);
} );
this.paint(null);
}
}
var TabMirror = function( ){ this.init() }
TabMirror.prototype = {
init: function(){
var self = this;
// When a tab is updated, update the mirror
Tabs.onReady( function(evt){
self.update(evt.tab);
});
// When a tab is closed, unlink.
Tabs.onClose( function(){
self.unlink(this);
});
// For each tab, create the link.
Tabs.forEach(function(tab){
self.link(tab);
});
},
_getEl: function(tab){
mirror = null;
$(".tab").each(function(){
if( $(this).data("tab") == tab ){
mirror = this;
return;
}
});
return mirror;
},
_customize: function(func){
// pass
// This gets set by add-ons/extensions to MirrorTab
},
_createEl: function(tab){
var div = $("<div class='tab'><span class='name'>&nbsp;</span><img class='fav'/><canvas class='thumb'/></div>")
.data("tab", tab)
.appendTo("body");
if( tab.url.match("chrome:") ){
div.hide();
}
this._customize(div);
function updateAttributes(){
var iconUrl = tab.raw.linkedBrowser.mIconURL;
var label = tab.raw.label;
$fav = $('.fav', div)
$name = $('.name', div);
if(iconUrl != $fav.attr("src")) $fav.attr("src", iconUrl);
if( $name.text() != label ) $name.text(label);
}
var timer = setInterval( updateAttributes, 500 );
div.data("timer", timer);
this._updateEl(tab);
},
_updateEl: function(tab){
var el = this._getEl(tab);
new TabCanvas(tab, $('.thumb', el).get(0) );
},
update: function(tab){
var doc = tab.contentDocument;
this.link(tab);
if( !_isIframe(doc) ){
this._updateEl(tab);
}
},
link: function(tab){
// Don't add duplicates
var dup = this._getEl(tab)
if( dup ) return false;
/*// Don't do anything that starts with a chrome URL
if( tab.contentWindow.location.protocol == "chrome:" ){
return false;
}*/
// Add the tab to the page
this._createEl(tab);
return true;
},
unlink: function(tab){
$(".tab").each(function(){
if( $(this).data("tab") == tab ){
clearInterval( $(this).data("timer") );
$(this).remove();
}
});
}
}
new TabMirror()
window.TabMirror = {}
window.TabMirror.customize = function(func){
// Apply the custom handlers to all existing elements
// TODO: Make this modular: so that it only exists in one place.
// No breaking DRY!
func($("div.tab"));
// Apply it to all future elements.
TabMirror.prototype._customize = func;
};
})();

View File

@ -0,0 +1,551 @@
(function(){
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
var XULApp = {
appWindowType: "navigator:browser",
tabStripForWindow: function(aWindow) {
return aWindow.document.getElementById("content").mStrip;
},
openTab: function(aUrl, aInBackground) {
var window = this.mostRecentAppWindow;
var tabbrowser = window.getBrowser();
var tab = tabbrowser.addTab(aUrl);
if (!aInBackground)
tabbrowser.selectedTab = tab;
},
getBrowserFromContentWindow: function(aMainWindow, aWindow) {
var browsers = aMainWindow.gBrowser.browsers;
for (var i = 0; i < browsers.length; i++) {
if (browsers[i].contentWindow == aWindow)
return browsers[i];
}
return null;
}
};
function Dictionary() {
var keys = [];
var values = [];
this.set = function set(key, value) {
var id = keys.indexOf(key);
if (id == -1) {
keys.push(key);
values.push(value);
} else
values[id] = value;
};
this.get = function get(key, defaultValue) {
if (defaultValue === undefined)
defaultValue = null;
var id = keys.indexOf(key);
if (id == -1)
return defaultValue;
return values[id];
};
this.remove = function remove(key) {
var id = keys.indexOf(key);
if (id == -1)
throw new Error("object not in dictionary: " + key);
keys.splice(id, 1);
values.splice(id, 1);
};
var readOnlyKeys = new ImmutableArray(keys);
var readOnlyValues = new ImmutableArray(values);
this.__defineGetter__("keys", function() { return readOnlyKeys; });
this.__defineGetter__("values", function() { return readOnlyValues; });
this.__defineGetter__("length", function() { return keys.length; });
}
function ImmutableArray(baseArray) {
var self = this;
var UNSUPPORTED_MUTATOR_METHODS = ["pop", "push", "reverse", "shift",
"sort", "splice", "unshift"];
UNSUPPORTED_MUTATOR_METHODS.forEach(
function(methodName) {
self[methodName] = function() {
throw new Error("Mutator method '" + methodName + "()' is " +
"unsupported on this object.");
};
});
self.toString = function() { return "[ImmutableArray]"; };
self.__proto__ = baseArray;
}
function WindowWatcher() {
var self = this;
var observer = {
observe: function(window, event) {
if (event == "domwindowopened") {
if (self.onWindowOpened)
self.onWindowOpened(window);
} else
if (self.onWindowClosed)
self.onWindowClosed(window);
}
};
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher);
ww.registerNotification(observer);
Extension.addUnloadMethod(
this,
function() {
ww.unregisterNotification(observer);
});
}
// When this object is instantiated, the given onLoad() is called for
// all browser windows, and subsequently for all newly-opened browser
// windows. When a browser window closes, onUnload() is called.
// onUnload() is also called once for each browser window when the
// extension is unloaded.
function BrowserWatcher(options) {
var pendingHandlers = [];
function makeSafeFunc(func) {
function safeFunc(window) {
try {
func(window);
} catch (e) {
Utils.logger.log(e);
}
};
return safeFunc;
}
function addUnloader(chromeWindow, func) {
function onUnload() {
chromeWindow.removeEventListener("unload", onUnload, false);
pendingHandlers.splice(pendingHandlers.indexOf(onUnload), 1);
func(chromeWindow);
}
pendingHandlers.push(onUnload);
chromeWindow.addEventListener("unload", onUnload, false);
}
function loadAndBind(chromeWindow) {
if (options.onLoad)
(makeSafeFunc(options.onLoad))(chromeWindow);
if (options.onUnload)
addUnloader(chromeWindow, makeSafeFunc(options.onUnload));
}
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var enumerator = wm.getEnumerator(XULApp.appWindowType);
while (enumerator.hasMoreElements()) {
var chromeWindow = enumerator.getNext();
if (chromeWindow.gIsDoneLoading)
loadAndBind(chromeWindow);
else
onWindowOpened(chromeWindow);
}
function onWindowOpened(chromeWindow) {
function removeListener() {
chromeWindow.removeEventListener("load", onLoad, false);
pendingHandlers.splice(pendingHandlers.indexOf(removeListener), 1);
}
function onLoad() {
removeListener();
var type = chromeWindow.document.documentElement
.getAttribute("windowtype");
if (type == XULApp.appWindowType)
loadAndBind(chromeWindow);
}
chromeWindow.addEventListener("load", onLoad, false);
pendingHandlers.push(removeListener);
}
var ww = new WindowWatcher();
ww.onWindowOpened = onWindowOpened;
Extension.addUnloadMethod(
this,
function() {
ww.unload();
var handlers = pendingHandlers.slice();
handlers.forEach(function(handler) { handler(); });
});
}
var Extension = {
// === {{{Extension.addUnloadMethod()}}} ===
//
// This attaches a given method called 'unload' to the given object.
// The method is also tied to the Extension page's lifetime, so if
// the unload method isn't called before the page is unloaded, it is
// called at that time. This helps ensure both that memory leaks
// don't propagate past Extension page reloads, and it can also help
// developers find objects that aren't being properly cleaned up
// before the page is unloaded.
addUnloadMethod: function addUnloadMethod(obj, unloader) {
function unloadWrapper() {
window.removeEventListener("unload", unloadWrapper, true);
unloader.apply(obj, arguments);
}
window.addEventListener("unload", unloadWrapper, true);
obj.unload = unloadWrapper;
}
};
function EventListenerMixIns(mixInto) {
var mixIns = {};
this.add = function add(options) {
if (mixIns) {
if (options.name in mixIns)
Utils.logging.log("mixIn for", options.name, "already exists.");
options.mixInto = mixInto;
mixIns[options.name] = new EventListenerMixIn(options);
}
};
this.bubble = function bubble(name, target, event) {
if (mixIns)
mixIns[name].trigger(target, event);
};
Extension.addUnloadMethod(
this,
function() {
for (name in mixIns) {
mixIns[name].unload();
delete mixIns[name];
}
mixIns = null;
});
}
function EventListenerMixIn(options) {
var listeners = [];
function onEvent(event, target) {
if (listeners) {
if (options.filter)
event = options.filter.call(this, event);
if (event) {
if (!target)
target = options.mixInto;
var listenersCopy = listeners.slice();
for (var i = 0; i < listenersCopy.length; i++)
try {
listenersCopy[i].call(target, event);
} catch (e) {
Utils.logger.log(e);
}
if (options.bubbleTo)
options.bubbleTo.bubble(options.name, target, event);
}
}
};
options.mixInto[options.name] = function bind(cb) {
if (typeof(cb) != "function")
Utils.logging.log("Callback must be a function.");
if (listeners)
listeners.push(cb);
};
options.mixInto[options.name].unbind = function unbind(cb) {
if (listeners) {
var index = listeners.indexOf(cb);
if (index != -1)
listeners.splice(index, 1);
}
};
this.trigger = function trigger(target, event) {
onEvent(event, target);
};
if (options.observe)
options.observe.addEventListener(options.eventName,
onEvent,
options.useCapture);
Extension.addUnloadMethod(
this,
function() {
listeners = null;
if (options.observe)
options.observe.removeEventListener(options.eventName,
onEvent,
options.useCapture);
});
}
function Tabs() {
var trackedWindows = new Dictionary();
var trackedTabs = new Dictionary();
var windows = {
get focused() {
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var chromeWindow = wm.getMostRecentWindow("navigator:browser");
if (chromeWindow)
return trackedWindows.get(chromeWindow);
return null;
}
};
windows.__proto__ = trackedWindows.values;
var tabs = {
get focused() {
var browserWindow = windows.focused;
if (browserWindow)
return browserWindow.getFocusedTab();
return null;
},
open: function open(url) {
var browserWindow = windows.focused;
// TODO: What to do if we have no focused window?
// make a new one?
return browserWindow.addTab(url);
},
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"});
tabs.__proto__ = trackedTabs.values;
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
// error logging here.
try {
// This is a XUL <tab> element of class tabbrowser-tab.
var chromeTab = event.originalTarget;
switch (event.type) {
case "TabSelect":
break;
case "TabOpen":
newBrowserTab(tabbrowser, chromeTab);
tabsMixIns.bubble("onOpen",
trackedTabs.get(chromeTab),
true);
break;
case "TabMove":
break;
case "TabClose":
tabsMixIns.bubble("onClose",
trackedTabs.get(chromeTab),
true);
unloadBrowserTab(chromeTab);
break;
}
} catch (e) {
Utils.logger.log(e);
}
}
EVENTS_TO_WATCH.forEach(
function(eventType) {
tabbrowser.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() {
EVENTS_TO_WATCH.forEach(
function(eventType) {
tabbrowser.removeEventListener(eventType, onEvent, true);
});
for (var i = 0; i < tabbrowser.tabContainer.itemCount; i++)
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,
eventName: "DOMContentLoaded",
useCapture: true,
bubbleTo: tabsMixIns,
filter: function(event) {
// Return the document that just loaded.
event.tab = self;
return event;
}});
mixIns.add(
{name: "onFocus",
observe: chromeTab,
eventName: "TabSelect",
useCapture: true,
bubbleTo: tabsMixIns,
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.
return true;
}});
this.__proto__ = {
get isClosed() { return (browser == null); },
get url() {
if (browser && browser.currentURI)
return browser.currentURI.spec;
return null;
},
get favicon() {
if (chromeTab && chromeTab.image) {
return chromeTab.image;
}
return null;
},
get contentWindow() {
if (browser && browser.contentWindow)
return browser.contentWindow;
return null;
},
get contentDocument() {
if (browser && browser.contentDocument)
return browser.contentDocument;
return null;
},
get raw() { return chromeTab; },
focus: function focus() {
if (browser)
tabbrowser.selectedTab = chromeTab;
},
close: function close() {
if (browser)
browser.contentWindow.close();
},
toString: function toString() {
if (!browser)
return "[Closed Browser Tab]";
else
return "[Browser Tab]";
},
_unload: function _unload() {
mixIns.unload();
mixIns = null;
tabbrowser = null;
chromeTab = null;
browser = null;
}
};
}
var browserWatcher = new BrowserWatcher(
{onLoad: function(chromeWindow) {
var trackedWindow = trackedWindows.get(chromeWindow);
if (!trackedWindow)
trackedWindows.set(chromeWindow,
new BrowserWindow(chromeWindow));
},
onUnload: function(chromeWindow) {
var browserWindow = trackedWindows.get(chromeWindow);
trackedWindows.remove(chromeWindow);
browserWindow.unload();
}
});
this.__defineGetter__("tabs", function() { return tabs; });
Extension.addUnloadMethod(
this,
function() {
tabsMixIns.unload();
browserWatcher.unload();
});
}
window.Tabs = new Tabs().tabs;
})();

View File

@ -0,0 +1,48 @@
(function(){
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// Get this in a way where we can load the page automatically
// where it doesn't need to be focused...
var homeWindow = Cc["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher)
.activeWindow;
var Utils = {
get activeWindow(){
var win = Cc["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher)
.activeWindow;
if( win != null ) return win;
else return homeWindow;
},
get activeTab(){
var tabBrowser = this.activeWindow.gBrowser;
return tabBrowser.selectedTab;
},
get homeTab(){
for( var i=0; i<Tabs.length; i++){
if(Tabs[i].contentWindow.location.host == "tabcandy"){
return Tabs[i];
}
}
return null;
},
get logger(){
return homeWindow.Firebug.Console
}
}
window.Utils = Utils;
})();

298
browser/base/content/tabcandy/jquery-ui.js vendored Executable file

File diff suppressed because one or more lines are too long

19
browser/base/content/tabcandy/jquery.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
var tabcandy = {
onLoad: function() {
// initialization code
this.initialized = true;
this.strings = document.getElementById("tabcandy-strings");
},
onMenuItemCommand: function(e) {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
promptService.alert(window, this.strings.getString("helloMessageTitle"),
this.strings.getString("helloMessage"));
},
};
window.addEventListener("load", function(e) { tabcandy.onLoad(e); }, false);

View File

@ -0,0 +1,50 @@
/*
* Pixastic - JavaScript Image Processing Library
* Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
* MIT License [http://www.nihilogic.dk/licenses/mit-license.txt]
*/
var Pixastic=(function(){function addEvent(el,event,handler){if(el.addEventListener)
el.addEventListener(event,handler,false);else if(el.attachEvent)
el.attachEvent("on"+event,handler);}
function onready(handler){var handlerDone=false;var execHandler=function(){if(!handlerDone){handlerDone=true;handler();}}
document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");var script=document.getElementById("__onload_ie_sumbox__");script.onreadystatechange=function(){if(script.readyState=="complete"){script.parentNode.removeChild(script);execHandler();}}
if(document.addEventListener)
document.addEventListener("DOMContentLoaded",execHandler,false);addEvent(window,"load",execHandler);}
function init(){if(!Pixastic.parseOnLoad)return;var imgEls=getElementsByClass("pixastic",null,"img");var canvasEls=getElementsByClass("pixastic",null,"canvas");var elements=imgEls.concat(canvasEls);for(var i=0;i<elements.length;i++){(function(){var el=elements[i];var actions=[];var classes=el.className.split(" ");for(var c=0;c<classes.length;c++){var cls=classes[c];if(cls.substring(0,9)=="pixastic-"){var actionName=cls.substring(9);if(actionName!="")
actions.push(actionName);}}
if(actions.length){if(el.tagName=="IMG"){var dataImg=new Image();dataImg.src=el.src;if(dataImg.complete){for(var a=0;a<actions.length;a++){var res=Pixastic.applyAction(el,el,actions[a],null);if(res)
el=res;}}else{dataImg.onload=function(){for(var a=0;a<actions.length;a++){var res=Pixastic.applyAction(el,el,actions[a],null)
if(res)
el=res;}}}}else{setTimeout(function(){for(var a=0;a<actions.length;a++){var res=Pixastic.applyAction(el,el,actions[a],null);if(res)
el=res;}},1);}}})();}}
onready(init);function getElementsByClass(searchClass,node,tag){var classElements=new Array();if(node==null)
node=document;if(tag==null)
tag='*';var els=node.getElementsByTagName(tag);var elsLen=els.length;var pattern=new RegExp("(^|\\s)"+searchClass+"(\\s|$)");for(i=0,j=0;i<elsLen;i++){if(pattern.test(els[i].className)){classElements[j]=els[i];j++;}}
return classElements;}
var debugElement;function writeDebug(text,level){if(!Pixastic.debug)return;try{switch(level){case"warn":console.warn("Pixastic:",text);break;case"error":console.error("Pixastic:",text);break;default:console.log("Pixastic:",text);}}catch(e){}
if(!debugElement){}}
return{parseOnLoad:false,debug:false,applyAction:function(img,dataImg,actionName,options){options=options||{};var imageIsCanvas=(img.tagName=="CANVAS");if(imageIsCanvas&&Pixastic.Client.isIE()){if(Pixastic.debug)writeDebug("Tried to process a canvas element but browser is IE.");return false;}
var canvas,ctx;if(Pixastic.Client.hasCanvas()){canvas=document.createElement("canvas");ctx=canvas.getContext("2d");}
var w=parseInt(img.offsetWidth);var h=parseInt(img.offsetHeight);if(actionName.indexOf("(")>-1){var tmp=actionName;actionName=tmp.substr(0,tmp.indexOf("("));var arg=tmp.match(/\((.*?)\)/);if(arg[1]){arg=arg[1].split(";");for(var a=0;a<arg.length;a++){thisArg=arg[a].split("=");if(thisArg.length==2){if(thisArg[0]=="rect"){var rectVal=thisArg[1].split(",");options[thisArg[0]]={left:parseInt(rectVal[0],10)||0,top:parseInt(rectVal[1],10)||0,width:parseInt(rectVal[2],10)||0,height:parseInt(rectVal[3],10)||0}}else{options[thisArg[0]]=thisArg[1];}}}}}
if(!options.rect){options.rect={left:0,top:0,width:w,height:h};}
var validAction=false;if(Pixastic.Actions[actionName]&&typeof Pixastic.Actions[actionName].process=="function"){validAction=true;}
if(!validAction){if(Pixastic.debug)writeDebug("Invalid action \""+actionName+"\". Maybe file not included?");return false;}
if(!Pixastic.Actions[actionName].checkSupport()){if(Pixastic.debug)writeDebug("Action \""+actionName+"\" not supported by this browser.");return false;}
if(Pixastic.Client.hasCanvas()){canvas.width=w;canvas.height=h;canvas.style.width=w+"px";canvas.style.height=h+"px";ctx.drawImage(dataImg,0,0,w,h);}
var params={image:img,canvas:canvas,width:w,height:h,useData:true,options:options}
var res=Pixastic.Actions[actionName].process(params);if(!res){return false;}
if(Pixastic.Client.hasCanvas()){if(params.useData){if(Pixastic.Client.hasCanvasImageData()){canvas.getContext("2d").putImageData(params.canvasData,options.rect.left,options.rect.top);canvas.getContext("2d").fillRect(0,0,0,0);}}
canvas.title=img.title;canvas.imgsrc=img.imgsrc;if(!imageIsCanvas)canvas.alt=img.alt;if(!imageIsCanvas)canvas.imgsrc=img.src;canvas.className=img.className;if(img.getAttribute("style"))
canvas.setAttribute("style",img.getAttribute("style"));canvas.cssText=img.cssText;canvas.name=img.name;canvas.tabIndex=img.tabIndex;canvas.id=img.id;if(img.parentNode&&img.parentNode.replaceChild){img.parentNode.replaceChild(canvas,img);}
return canvas;}
return img;},prepareData:function(params,getCopy){var ctx=params.canvas.getContext("2d");var rect=params.options.rect;var dataDesc=ctx.getImageData(rect.left,rect.top,rect.width,rect.height);var data=dataDesc.data;if(!getCopy)params.canvasData=dataDesc;return data;},process:function(img,actionName,options,callback)
{if(img.tagName=="IMG"){var dataImg=new Image();dataImg.src=img.src;if(dataImg.complete){var res=Pixastic.applyAction(img,dataImg,actionName,options);if(callback)callback(res);return res;}else{dataImg.onload=function(){var res=Pixastic.applyAction(img,dataImg,actionName,options)
if(callback)callback(res);}}}
if(img.tagName=="CANVAS"){var res=Pixastic.applyAction(img,img,actionName,options);if(callback)callback(res);return res;}},Client:{hasCanvas:(function(){var c=document.createElement("canvas");var val=false;try{val=!!((typeof c.getContext=="function")&&c.getContext("2d"));}catch(e){}
return function(){return val;}})(),hasCanvasImageData:(function(){var c=document.createElement("canvas");var val=false;var ctx;try{if(typeof c.getContext=="function"&&(ctx=c.getContext("2d"))){val=(typeof ctx.getImageData=="function");}}catch(e){}
return function(){return val;}})(),isIE:function(){return!!document.all&&!!window.attachEvent&&!window.opera;}},Actions:{}}})();if(typeof jQuery!="undefined"&&jQuery&&jQuery.fn){jQuery.fn.pixastic=function(action,options){var newElements=[];this.each(function(){if(this.tagName=="IMG"&&!this.complete){return;}
var res=Pixastic.process(this,action,options);if(res){newElements.push(res);}});if(newElements.length>0)
return jQuery(newElements);else
return this;};};Pixastic.Actions.desaturate={process:function(params){var useAverage=!!params.options.average;if(Pixastic.Client.hasCanvasImageData()){var data=Pixastic.prepareData(params);var rect=params.options.rect;var w=rect.width;var h=rect.height;var w4=w*4;var y=h;do{var offsetY=(y-1)*w4;var x=w;do{var offset=offsetY+(x-1)*4;var brightness=useAverage?(data[offset]+data[offset+1]+data[offset+2])/3:(data[offset]*0.3+data[offset+1]*0.59+data[offset+2]*0.11);data[offset]=data[offset+1]=data[offset+2]=brightness;}while(--x);}while(--y);return true;}else if(Pixastic.Client.isIE()){params.image.style.filter+=" gray";return true;}},checkSupport:function(){return(Pixastic.Client.hasCanvasImageData()||Pixastic.Client.isIE());}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
content/.DS_Store vendored Normal file

Binary file not shown.

BIN
content/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

117
content/tab.html Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>Switch</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<link rel="icon" href="chrome://abouttab/content/tabcandy.png"/>
<style media="screen" type="text/css">
html, body {
margin: 0;
padding: 0;
font-family: Geneva;
}
.tab{
position: absolute;
display: block;
float:left;
margin: 10px;
padding: 0;
background-color: rgba(255,255,255,.8);
}
.fav{
position: absolute;
width: 16px;
height: 16px;
background-color: rgba(255,255,255,.8);
-moz-border-radius: 0 0 5px 0;
padding: 3px;
-moz-box-shadow: 1px 1px 3px rgba(0,0,0,.2);
}
.thumb{
width: 160px;
height: 120px;
background-color: #ccc;
-moz-box-shadow: 1px 1px 10px rgba(0,0,0,.3);
}
.thumb:hover{
-moz-box-shadow: 1px 1px 10px rgba(0,0,0,.5);
}
.name{
font-size: 9px;
display:block;
width:160px;
white-space: nowrap;
overflow: hidden;
}
.name:before{
display:inline-block;
height:12px;
width:20px;
content:" ";
position: absolute;
right:0px;
background: -moz-linear-gradient(0deg, rgba(255,255,255,0), white);
}
.close{
position: absolute;
top:12px; right:0;
margin: 1px;
width:12px; height:12px;
background-color: rgba(0,0,0,.6);
font-size: 10px;
text-align: center;
line-height:13px;
color: #DDD;
cursor: pointer;
-moz-border-radius: 10px;
-moz-box-shadow: inset 1px 1px 0px rgba(0,0,0,.5), inset -1px -1px 0px rgba(255,255,255,.5);
text-shadow: 1px 1px 1px rgba(0,0,0,.5);
font-family: Helvetica;
}
.search{width:100%; margin-top: 30px; text-align: center; margin-bottom: 30px;}
.search input{ width: 300px; font-size: 16pt;}
#actions{
position: absolute;
top: 5px;
right: 5px;
font-size: 11px;
}
.unhighlight{
opacity: .1;
z-index: -100;
}
</style>
</head>
<body>
<div class="search">
<input type="text"/>
</div>
<div id="actions">
<a id="tabbar" href="#">Toggle Tab Bar</a>
</div>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/jquery.js"></script>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/jquery-ui.js"></script>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/utils.js"></script>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/tabs.js"></script>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/mirror.js"></script>
<script type="text/javascript;version=1.8" src="chrome://tabcandy/content/js/ui.js"></script>
</body>
</html>