Ver código fonte

restructured the project to allow for future expansion and cross browser compatibility

master
mort 8 anos atrás
pai
commit
e8a687c736
9 arquivos alterados com 577 adições e 9 exclusões
  1. 1
    1
      .gitignore
  2. 32
    0
      build.sh
  3. 34
    0
      firefox/bridge.js
  4. 8
    0
      firefox/build.sh
  5. 494
    0
      firefox/data/onload.js
  6. 0
    0
      firefox/index.js
  7. 0
    0
      firefox/package.json
  8. 0
    0
      firefox/test/test-index.js
  9. 8
    8
      script.js

+ 1
- 1
.gitignore Ver arquivo

@@ -1 +1 @@
@mouseless-*.xpi
*.xpi

+ 32
- 0
build.sh Ver arquivo

@@ -0,0 +1,32 @@
#!/bin/sh

TARGET="$1"

if [ ! -d "$TARGET" ]; then
if [ "$TARGET" = "" ]; then
echo "Usage: $0 <target>"
else
echo "Target not found: $TARGET"
fi
echo "Targets available:"

for F in *; do
if [ -d "$F" ]; then
echo "* $F"
fi
done

exit 1
fi

cd "$TARGET"

# Create complete script file
SCRIPT=$(cat bridge.js ../script.js)

# Run target's build script
mkdir -p build
echo "$SCRIPT" | ./build.sh "mouseless-$TARGET"

mv build/* ..
cd ..

+ 34
- 0
firefox/bridge.js Ver arquivo

@@ -0,0 +1,34 @@
var bridge = {
onConf: function(cb) {
self.port.on("conf", function(c) {
cb(c);
});
},
onKeys: function(cb) {
self.port.on("keys", function(k) {
cb(k);
});
},

changeTabLeft: function() {
self.port.emit("change_tab_left");
},
changeTabRight: function() {
self.port.emit("change_tab_right");
},

moveTabLeft: function() {
self.port.emit("move_tab_left");
},
moveTabRight: function() {
self.port.emit("move_tab_right");
},

openTab: function(href) {
self.port.emit("tab_open", href);
},

setClipboard: function(txt) {
self.port.emit("clipboard_set", txt);
}
}

+ 8
- 0
firefox/build.sh Ver arquivo

@@ -0,0 +1,8 @@
#!/bin/sh

cat - > data/onload.js
rm -f *.xpi

jpm xpi

mv *.xpi "build/${1}.xpi"

+ 494
- 0
firefox/data/onload.js Ver arquivo

@@ -0,0 +1,494 @@
var bridge = {
onConf: function(cb) {
self.port.on("conf", function(c) {
cb(c);
});
},
onKeys: function(cb) {
self.port.on("keys", function(k) {
cb(k);
});
},

changeTabLeft: function() {
self.port.emit("change_tab_left");
},
changeTabRight: function() {
self.port.emit("change_tab_right");
},

moveTabLeft: function() {
self.port.emit("move_tab_left");
},
moveTabRight: function() {
self.port.emit("move_tab_right");
},

openTab: function(href) {
self.port.emit("tab_open", href);
},

setClipboard: function(txt) {
self.port.emit("clipboard_set", txt);
}
}
var conf = {
scroll_speed: 0.3,
scroll_speed_fast: 1.1,
scroll_friction: 0.8,
chars: "SANOTEHUCP",
input_whitelist: ["checkbox", "radio", "hidden", "submit", "reset", "button", "file", "image"],
location_change_check_timeout: 2000
}

var keys = {};

bridge.onConf(function(c) {
for (var i in c) {
conf[i] = c[i];
}
});

bridge.onKeys(function(k) {
keys = k;
});

function isMatch(k, evt) {
if ((k.code === evt.key)
&& (!!k.ctrlKey == evt.ctrlKey)
&& (!!k.shiftKey == evt.shiftKey)
&& (!!k.altKey == evt.altKey)
&& (!!k.metaKey == evt.metaKey)) {
return true;
}

return false;
}

//There's a lot we don't want to do if we're not on an actual webpage, but on
//the "speed dial"-ish pages.
var onWebPage = (document.body !== undefined);

function createKey(n) {
var str = "";
var base = conf.chars.length;

if (n == 0)
return conf.chars[0];

while (n > 0) {
str += conf.chars[n % base];
n = Math.floor(n / base);
}

return str;
}

function getElemPos(elem) {
var curtop = 0;
var curleft = 0;

do {
curtop += elem.offsetTop;
curleft += elem.offsetLeft;
} while (elem = elem.offsetParent);

return {top: curtop, left: curleft};
}

var blobList = {
blobs: {},
container: null,
overview: null,

visible: false,
needLoadBlobs: true,

currentKey: "",

createContainer: function() {
var container = document.createElement("div");
container.style = [
"pointer-events: none",
"display: none",
"position: absolute;",
"top: 0px",
"left: 0px",
"z-index: 2147483647",
"box-sizing: content-box",
""
].join(" !important;");
document.body.appendChild(container);
blobList.container = container;
},

createOverview: function() {
var overview = document.createElement("div");
overview.style = [
"position: fixed",
"top: 0px",
"left: 0px",
"background-color: white",
"border-bottom: 2px solid black",
"border-right: 2px solid black",
"color: black",
"font: 12px sans-serif",
"padding: 3px",
"height: 15px",
"line-height: 15px",
"z-index: 2147483647",
"box-sizing: content-box",
""
].join(" !important;");
blobList.container.appendChild(overview);
blobList.overview = overview;
},

init: function() {
if (!onWebPage)
return;

blobList.createContainer();

window.addEventListener("scroll", function() {
blobList.needLoadBlobs = true;
});
},

currentIndex: 0,
loadBlobs: function() {
if (!onWebPage)
return;

var linkElems = document.querySelectorAll("a, button, input, textarea");

//Remove old container contents
blobList.container.innerHTML = "";
blobList.createOverview();

//Remove old blobs
blobList.blobs = {};

var i = 0;
var nRealBlobs = 0;
function addBlob() {
var linkElem = linkElems[i];

if (i++ >= linkElems.length)
return false;

if (linkElem === undefined)
return true;

//We don't want hidden elements
if ((linkElem === undefined)
|| (linkElem.style.display == "none")
|| (linkElem.style.visibility == "hidden")) {
return true;
}

//Get element's absolute position
var pos = getElemPos(linkElem);
//Lots of things which don't really exist have an X and Y value of 0
if (pos.top == 0 && pos.left == 0)
return true;

//We don't need to get things far above our current scroll position
if (pos.top < (window.scrollY - 100))
return true;

//We don't need things below our scroll position either
if (pos.top - 100 > (window.scrollY + window.innerHeight))
return true;

//Create the blob's key
key = createKey(nRealBlobs);
nRealBlobs += 1;

var blobElem = document.createElement("div");
blobElem.innerHTML = key.toUpperCase();
blobElem.style = [
"position: absolute",
"background-color: yellow",
"border: 1px solid black",
"border-radius: 10px",
"padding-left: 3px",
"padding-right: 3px",
"color: black",
"font: 12px sans-serif",
"top: "+pos.top+"px",
"left: "+pos.left+"px",
"line-height: 12px",
"font-size: 12px",
""
].join(" !important;");
blobList.container.appendChild(blobElem);

blobList.blobs[key] = {
blobElem: blobElem,
linkElem: linkElem
}

return true;
}

while (addBlob()) {};

},

showBlobs: function() {
blobList.visible = true;
blobList.container.style.display = "block";
},

hideBlobs: function() {
blobList.currentKey = "";
blobList.visible = false;
blobList.container.style.display = "none";
},

click: function() {
if (!blobList.visible)
return;

var blob = blobList.blobs[blobList.currentKey];
if (!blob)
return;

blob.linkElem.click();
blob.linkElem.focus();
blobList.hideBlobs();
},

clickNewTab: function() {
if (!blobList.visible)
return;

var blob = blobList.blobs[blobList.currentKey];
if (!blob)
return;

if (blob.linkElem.tagName == "A" && blob.linkElem.href) {
bridge.openTab(blob.linkElem.href);
} else {
blob.linkElem.click();
blob.linkElem.focus();
}

blobList.hideBlobs();
},

clickClipboard: function() {
if (!blobList.visible)
return;

var blob = blobList.blobs[blobList.currentKey];
if (!blob)
return;

if (!blob.linkElem.href)
return;

bridge.setClipboard(blob.linkElem.href);

blobList.hideBlobs();
},

appendKey: function(c) {
blobList.currentKey += c;
blobList.overview.innerHTML = blobList.currentKey;
},

backspace: function() {
blobList.currentKey = blobList.currentKey.substring(0, blobList.currentKey.length - 1);
blobList.overview.innerHTML = blobList.currentKey;
}
}
blobList.init();

//Reload blobs whenever the URL changes
var currentUrl = location.href;
setInterval(function() {
if (currentUrl !== location.href) {
blobList.loadBlobs();
}
currentUrl = location.href;
}, conf.location_change_check_timeout);

var pressedKeys = [];

function inArray(arr, val) {
return (arr.indexOf(val) !== -1);
}

function isValidElem(elem) {
var tag = elem.tagName.toLowerCase();

if (tag === "textarea")
return false;

if (tag === "select")
return false;

if (elem.contentEditable.toLowerCase() === "true")
return false;

if ((tag === "input")
&& (!inArray(conf.input_whitelist, elem.type.toLowerCase()))) {
return false;
}

return true;
}

window.addEventListener("keydown", function(evt) {
if (/about:.+/.test(location.href))
return;

var active = document.activeElement;

//We don't want to do anything if the user is tpying in an input field,
//unless the key is to deselect an input field
if (!isValidElem(active)) {
if (isMatch(keys.elem_deselect, evt)) {
active.blur();
blobList.hideBlobs();
return;
} else {
return;
}
}

//User is typing a key to a blob
if (blobList.visible) {

//Hide blobs if appropriate
if (isMatch(keys.blobs_hide, evt)) {
blobList.hideBlobs();
return;
}

//Backspace if appropriate
if (isMatch(keys.blobs_backspace, evt)) {
blobList.backspace();
return;
}

var c = evt.key;
if (conf.chars.indexOf(c) !== -1) {
blobList.appendKey(c);
evt.preventDefault();
evt.stopPropagation();
return false;
}
}

//Handle other key presses

//Deselect element
if (onWebPage && isMatch(keys.elem_deselect, evt)) {
blobList.hideBlobs();
active.blur();

//Show/hide/reload blobs
} else if (onWebPage && !blobList.visible && isMatch(keys.blobs_show, evt)) {
blobList.loadBlobs();
blobList.needLoadBlobs = false;
blobList.showBlobs();
} else if (onWebPage && blobList.visible && isMatch(keys.blobs_hide, evt)) {
blobList.hideBlobs();

//Simulate clicks
} else if (onWebPage && blobList.visible && isMatch(keys.blobs_click, evt)) {
blobList.click();
} else if (onWebPage && blobList.visible && isMatch(keys.blobs_click_new_tab, evt)) {
blobList.clickNewTab();
} else if (onWebPage && blobList.visible && isMatch(keys.blobs_click_clipboard, evt)) {
blobList.clickClipboard();

//Scrolling
} else if (onWebPage && isMatch(keys.scroll_up, evt)) {
scroll.start(-conf.scroll_speed);
} else if (onWebPage && isMatch(keys.scroll_down, evt)) {
scroll.start(conf.scroll_speed);
} else if (onWebPage && isMatch(keys.scroll_up_fast, evt)) {
scroll.start(-conf.scroll_speed_fast);
} else if (onWebPage && isMatch(keys.scroll_down_fast, evt)) {
scroll.start(conf.scroll_speed_fast);

//Back and forwards
} else if (isMatch(keys.history_back, evt)) {
history.back();
} else if (isMatch(keys.history_forward, evt)) {
history.forward();

//Change tab
} else if (isMatch(keys.change_tab_left, evt)) {
bridge.changeTabLeft();
} else if (isMatch(keys.change_tab_right, evt)) {
bridge.changeTabRight();

//Move tab
} else if (isMatch(keys.move_tab_left, evt)) {
bridge.moveTabLeft();
} else if (isMatch(keys.move_tab_right, evt)) {
bridge.moveTabRight();

//We don't want to stop the event from propagating
//if it hasn't matched anything yet
} else {
return true;
}

evt.preventDefault();
evt.stopPropagation();
return false;
}, true);

window.addEventListener("keyup", function(evt) {
if ((isMatch(keys.scroll_up, evt))
|| (isMatch(keys.scroll_down, evt))
|| (isMatch(keys.scroll_up_fast, evt))
|| (isMatch(keys.scroll_down_fast, evt))) {
scroll.stop();
}
}, true);

var scroll = {
start: function(acceleration) {
scroll.acceleration = acceleration;

if (scroll.raf == null)
scroll.update();
},

stop: function() {
scroll.acceleration = 0;
},

update: function() {
var tdiff = scroll.endTime - scroll.startTime;
if (tdiff < 100) {
scroll.velocity += scroll.acceleration;
window.scrollBy(0, scroll.velocity * tdiff);
scroll.velocity *= conf.scroll_friction;
}

if (tdiff < 100 && scroll.velocity > -0.1 && scroll.velocity < 0.1) {
scroll.velocity = 0;
cancelAnimationFrame(scroll.raf);
scroll.raf = null;
} else {
scroll.startTime = scroll.endTime;
scroll.endTime = new Date().getTime();
scroll.raf = requestAnimationFrame(scroll.update);
}
},

raf: null,
acceleration: 0,
velocity: 0,
startDate: 0,
endDate: 0
}

index.js → firefox/index.js Ver arquivo


package.json → firefox/package.json Ver arquivo


test/test-index.js → firefox/test/test-index.js Ver arquivo


data/onload.js → script.js Ver arquivo

@@ -9,13 +9,13 @@ var conf = {

var keys = {};

self.port.on("conf", function(c) {
bridge.onConf(function(c) {
for (var i in c) {
conf[i] = c[i];
}
});

self.port.on("keys", function(k) {
bridge.onKeys(function(k) {
keys = k;
});

@@ -236,7 +236,7 @@ var blobList = {
return;

if (blob.linkElem.tagName == "A" && blob.linkElem.href) {
self.port.emit("tab_open", blob.linkElem.href);
bridge.openTab(blob.linkElem.href);
} else {
blob.linkElem.click();
blob.linkElem.focus();
@@ -256,7 +256,7 @@ var blobList = {
if (!blob.linkElem.href)
return;

self.port.emit("clipboard_set", blob.linkElem.href);
bridge.setClipboard(blob.linkElem.href);

blobList.hideBlobs();
},
@@ -391,15 +391,15 @@ window.addEventListener("keydown", function(evt) {

//Change tab
} else if (isMatch(keys.change_tab_left, evt)) {
self.port.emit("change_tab_left");
bridge.changeTabLeft();
} else if (isMatch(keys.change_tab_right, evt)) {
self.port.emit("change_tab_right");
bridge.changeTabRight();

//Move tab
} else if (isMatch(keys.move_tab_left, evt)) {
self.port.emit("move_tab_left");
bridge.moveTabLeft();
} else if (isMatch(keys.move_tab_right, evt)) {
self.port.emit("move_tab_right");
bridge.moveTabRight();

//We don't want to stop the event from propagating
//if it hasn't matched anything yet

Carregando…
Cancelar
Salvar