Skip to content
This repository has been archived by the owner on Aug 23, 2023. It is now read-only.

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nobuf committed Sep 21, 2011
0 parents commit 09a1ac1
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 0 deletions.
31 changes: 31 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Keyboard Shortcuts for Facebook #

This Chrome Extension provides Gmail like keyboard shortcuts for Facebook.

## Download ##

http://zuzara.com/pub/keyboard-shortcuts-for-facebook-0.1.crx

## Usage ##

Simply open facebook.com then type:

-`j`: down one item on your News Feed

-`k`: up

-`u`: jump to the top

## License ##

This extension is released under the MIT License.

## Thanks! ##

http://findicons.com/icon/17061/keyboard?id=17061
https://github.com/marquete/kibo
http://jquery.com/

## Feedback ##

http://twitter.com/zuzara
Binary file added icon128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions jquery-1.6.4.min.js

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions kibo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
var Kibo = function(element) {
this.element = element || window.document;
this.initialize();
};

Kibo.KEY_NAMES_BY_CODE = {
8: 'backspace', 9: 'tab', 13: 'enter',
16: 'shift', 17: 'ctrl', 18: 'alt',
20: 'caps_lock',
27: 'esc',
32: 'space',
33: 'page_up', 34: 'page_down',
35: 'end', 36: 'home',
37: 'left', 38: 'up', 39: 'right', 40: 'down',
45: 'insert', 46: 'delete',
48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8', 57: '9',
65: 'a', 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', 90: 'z',
112: 'f1', 113: 'f2', 114: 'f3', 115: 'f4', 116: 'f5', 117: 'f6', 118: 'f7', 119: 'f8', 120: 'f9', 121: 'f10', 122: 'f11', 123: 'f12',
144: 'num_lock'
};

Kibo.KEY_CODES_BY_NAME = {};
for(var key in Kibo.KEY_NAMES_BY_CODE)
if(Object.prototype.hasOwnProperty.call(Kibo.KEY_NAMES_BY_CODE, key))
Kibo.KEY_CODES_BY_NAME[Kibo.KEY_NAMES_BY_CODE[key]] = +key;

Kibo.MODIFIERS = ['shift', 'ctrl', 'alt'];

Kibo.WILDCARD_TYPES = ['arrow', 'number', 'letter', 'f'];

Kibo.WILDCARDS = {
arrow: [37, 38, 39, 40],
number: [48, 49, 50, 51, 52, 53, 54, 55, 56, 57],
letter: [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90],
f: [112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123]
};

Kibo.assert = function(expression, exception) {
exception = exception || {};
exception.name = exception.name || 'Exception raised';
exception.message = exception.message || 'an error has occurred.';

try {
if(!expression)
throw(exception);
} catch(error) {
if((typeof console !== 'undefined') && console.log)
console.log(error.name + ': ' + error.message);
else
window.alert(error.name + ': ' + error.message);
}
};

Kibo.registerEvent = (function() {
if(document.addEventListener) {
return function(element, eventName, func) {
element.addEventListener(eventName, func, false);
};
}
else if(document.attachEvent) {
return function(element, eventName, func) {
element.attachEvent('on' + eventName, func);
};
}
})();

Kibo.unregisterEvent = (function() {
if(document.removeEventListener) {
return function(element, eventName, func) {
element.removeEventListener(eventName, func, false);
};
}
else if(document.detachEvent) {
return function(element, eventName, func) {
element.detachEvent('on' + eventName, func);
};
}
})();

Kibo.isArray = function(what) {
return !!(what && what.splice);
};

Kibo.isString = function(what) {
return typeof what === 'string';
};

Kibo.arrayIncludes = (function() {
if(Array.prototype.indexOf) {
return function(haystack, needle) {
return haystack.indexOf(needle) !== -1;
};
}
else {
return function(haystack, needle) {
for(var i = 0; i < haystack.length; i++)
if(haystack[i] === needle)
return true;
return false;
};
}
})();

Kibo.trimString = function(string) {
return string.replace(/^\s+|\s+$/g, '');
};

Kibo.neatString = function(string) {
return Kibo.trimString(string).replace(/\s+/g, ' ');
};

Kibo.capitalize = function(string) {
return string.toLowerCase().replace(/^./, function(match) { return match.toUpperCase(); });
};

Kibo.isModifier = function(key) {
return Kibo.arrayIncludes(Kibo.MODIFIERS, key);
};

Kibo.prototype.initialize = function() {
var i, that = this;

this.lastKeyCode = -1;
this.lastModifiers = {};
for(i = 0; i < Kibo.MODIFIERS.length; i++)
this.lastModifiers[Kibo.MODIFIERS[i]] = false;

this.keysDown = { any: [] };
this.keysUp = { any: [] };
for(i = 0; i < Kibo.WILDCARD_TYPES.length; i++) {
this.keysDown['any ' + Kibo.WILDCARD_TYPES[i]] = [];
this.keysUp['any ' + Kibo.WILDCARD_TYPES[i]] = [];
}

this.downHandler = this.handler('down');
this.upHandler = this.handler('up');

Kibo.registerEvent(this.element, 'keydown', this.downHandler);
Kibo.registerEvent(this.element, 'keyup', this.upHandler);
Kibo.registerEvent(window, 'unload', function unloader() {
Kibo.unregisterEvent(that.element, 'keydown', that.downHandler);
Kibo.unregisterEvent(that.element, 'keyup', that.upHandler);
Kibo.unregisterEvent(window, 'unload', unloader);
});
};

Kibo.prototype.matchingKeys = function(registeredKeys) {
var i, j, keyCombination, match, result = [];
for(registeredKey in registeredKeys) {
if(Object.prototype.hasOwnProperty.call(registeredKeys, registeredKey)) {
keyCombination = Kibo.trimString(registeredKey).split(' ');
if(keyCombination.length && keyCombination[0] !== 'any') {
match = true;
for(j = 0; j < keyCombination.length; j++)
match = match && (Kibo.isModifier(keyCombination[j]) ? this.lastKey(keyCombination[j]) : (this.lastKey() === keyCombination[j]));
if(match)
result.push(registeredKey);
}
}
}
return result;
};

Kibo.prototype.handler = function(upOrDown) {
var that = this;
return function(e) {
var i, j, matchingKeys, registeredKeys;

e = e || window.event;

that.lastKeyCode = e.keyCode;
for(i = 0; i < Kibo.MODIFIERS.length; i++)
that.lastModifiers[Kibo.MODIFIERS[i]] = e[Kibo.MODIFIERS[i] + 'Key'];
if(Kibo.arrayIncludes(Kibo.MODIFIERS, Kibo.keyName(that.lastKeyCode)))
that.lastModifiers[Kibo.keyName(that.lastKeyCode)] = true;

registeredKeys = that['keys' + Kibo.capitalize(upOrDown)];
matchingKeys = that.matchingKeys(registeredKeys);

for(i = 0; i < registeredKeys.any.length; i++)
if((registeredKeys.any[i](e) === false) && e.preventDefault)
e.preventDefault;

for(i = 0; i < Kibo.WILDCARD_TYPES.length; i++)
if(Kibo.arrayIncludes(Kibo.WILDCARDS[Kibo.WILDCARD_TYPES[i]], that.lastKeyCode))
for(j = 0; j < registeredKeys['any ' + Kibo.WILDCARD_TYPES[i]].length; j++)
if((registeredKeys['any ' + Kibo.WILDCARD_TYPES[i]][j](e) === false) && e.preventDefault)
e.preventDefault();

for(i = 0; i < matchingKeys.length; i++)
for(j = 0; j < registeredKeys[matchingKeys[i]].length; j++)
if((registeredKeys[matchingKeys[i]][j](e) === false) && e.preventDefault)
e.preventDefault();
};
};

Kibo.prototype.registerKeys = function(upOrDown, newKeys, func) {
var i, registeredKeys = this['keys' + Kibo.capitalize(upOrDown)];

if(!Kibo.isArray(newKeys))
newKeys = [newKeys];

for(i = 0; i < newKeys.length; i++) {
Kibo.assert(
Kibo.isString(newKeys[i]),
{ name: 'Type error', message: 'expected string or array of strings.' }
);

newKeys[i] = Kibo.neatString(newKeys[i]);

if(Kibo.isArray(registeredKeys[newKeys[i]]))
registeredKeys[newKeys[i]].push(func);
else
registeredKeys[newKeys[i]] = [func];
}

return this;
};

Kibo.prototype.unregisterKeys = function(upOrDown, newKeys, func) {
var i, j, registeredKeys = this['keys' + Kibo.capitalize(upOrDown)];

if(!Kibo.isArray(newKeys))
newKeys = [newKeys];

for(i = 0; i < newKeys.length; i++) {
Kibo.assert(
Kibo.isString(newKeys[i]),
{ name: 'Type error', message: 'expected string or array of strings.' }
);

newKeys[i] = Kibo.neatString(newKeys[i]);

if(Kibo.isArray(registeredKeys[newKeys[i]]))
for(j = 0; j < registeredKeys[newKeys[i]].length; j++) {
if(String(registeredKeys[newKeys[i]][j]) === String(func)) {
registeredKeys[newKeys[i]].splice(j, 1);
break;
}
}
}

return this;
};

Kibo.prototype.down = function(keys, func) {
return this.registerKeys('down', keys, func);
};

Kibo.prototype.up = function(keys, func) {
return this.registerKeys('up', keys, func);
};

Kibo.keyName = function(keyCode) {
return Kibo.KEY_NAMES_BY_CODE[keyCode + ''];
};

Kibo.keyCode = function(keyName) {
return +Kibo.KEY_CODES_BY_NAME[keyName];
};

Kibo.prototype.lastKey = function(modifier) {
if(!modifier)
return Kibo.keyName(this.lastKeyCode);

Kibo.assert(
Kibo.arrayIncludes(Kibo.MODIFIERS, modifier),
{ name: 'Modifier error', message: 'invalid modifier ' + modifier + ' (valid modifiers are: ' + Kibo.MODIFIERS.join(', ') + ').' }
);

return this.lastModifiers[modifier];
};

19 changes: 19 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "Keyboard Shortcuts for Facebook",
"version": "0.1",
"description": "Provide keyboard shortcuts for Facebook",
"icons": { "16": "icon128.png",
"48": "icon128.png",
"128": "icon128.png"
},
"browser_action": {
"default_title": "Keyboard Shortcuts for Facebook",
"default_icon": "icon128.png"
},
"content_scripts": [
{
"matches": ["http://www.facebook.com/*", "https://www.facebook.com/*"],
"js": ["jquery-1.6.4.min.js", "kibo.js", "script.js"]
}
]
}
39 changes: 39 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

$(document).ready(function(){
var k = new Kibo();
var cur = -1;
var blueBarHeight = $('#blueBar').height(); // floated bar
var isFocus = function(){
return $('input,textarea').is(':focus');
};
var doScroll = function(){
var $li = $('#home_stream li.uiUnifiedStory:eq(' + cur + ')');
if (!$li) {
cur = 0;
return;
}
$(window).scrollTop($li.offset().top-blueBarHeight);
};
k.up('j', function(){
if (isFocus()) {
return true;
}
cur++;
doScroll();
}).up('k', function(){
if (isFocus()) {
return true;
}
if (cur <= 0) {
return;
}
cur--;
doScroll();
}).up('u', function(){
if (isFocus()) {
return true;
}
cur = 0;
doScroll();
});
});

0 comments on commit 09a1ac1

Please sign in to comment.