Skip to content

Instantly share code, notes, and snippets.

@canadaduane
Created August 19, 2009 04:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save canadaduane/170167 to your computer and use it in GitHub Desktop.
Save canadaduane/170167 to your computer and use it in GitHub Desktop.
CmdUtils.CreateCommand({
names: ["eyes like lightning"],
arguments: [ {role: 'object', nountype: noun_arb_text, label: 'input'} ],
author: {name: "Duane Johnson", email: "duane.johnson@gmail.com"},
license: "GPL",
description: "Opens a speed-reading window above the currently selected text.",
help: "Select some text, and then use the eyes like lightning command to start reading it.",
preview: function(pblock, args) {
var t = args.object.text.substring(0, 20);
pblock.innerHTML = "Read <b>" + t + "</b>";
},
execute: function(args) {
var index = 0;
var text = args.object.text;
var words = [];
var window = CmdUtils.getWindowInsecure();
var phash = new persistentHash('eyeslikelightning');
var interval_multiplier = 50;
var wpm;
var set_wpm = function(value) {
wpm = parseInt(value);
phash.setString('wpm', value.toString());
return value;
};
// Get/Set default words-per-minute from persistent hash
set_wpm(parseInt(phash.getString('wpm') || 500));
var make_popup = function($) {
CmdUtils.injectCss(
'#ell-popup > div { margin: 5px auto; text-align: center; } ' +
'.ell-s{ font-size: 35px; height: 35px; } ' +
'.ell-m{ font-size: 35px; height: 35px; visibility: hidden; } ' +
'.ell-l{ font-size: 35px; height: 35px; visibility: hidden; } ' +
'#ell-control td { border: 1px dotted blue; } ' +
// The following base64 code was create with:
// ruby -e 'print [IO.read(File.join(Dir.pwd, ARGV[0]))].pack("m")' center.png > center.b64
'.ell-s{ background: url(data:image/png;base64,' +
'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAADO2lDQ1BJQ0Mg' +
'UHJvZmlsZQAAeAGFlEto1FAUhv+MKYK0gqi1FpTgQou0JT7QilDbabXWkXEY' +
'+9AiyDRzZxpNMzGZGR+ISEHc+VqKGx+IiyriQrpQcKULkULra1EEcaUiiEI3' +
'Usb/Ju1MKlYvJPlyzn/P64YAVQ9TjmNFNGDYzrvJrqh26PCAtngCVahBNbhS' +
'hue0JxL7faZWPuev6bdQpGWyScaK9R2Y+LRt9f1Lj2Lv6572+p75+nlvNS4T' +
'AopG64pswFslDwa8V/LJvJOn5ohkYyiVJjvkRrcn2UG+QV6aDfFgiNPCM4Cq' +
'NmpyhuMyTmQFuaVoZGXMUbJup02bPCXtac8Ypob9Rn7IWdDGlY8BrWuARS8r' +
'tgEPGL0LrFpfsTXUASv7gbEtFdvPpD8fpXbcy2zZ7IdTqqOs6UOp9HM9sPga' +
'MHO1VPp1q1Sauc0crOOZZRTcoq9lYcorIKg32M34yTlaiIOefFULcJNz7F8C' +
'xC4A1z8CGx4Ayx8DiRqgZwci59lucOXFKc4F6Mg5p10zO5TXNuv6dq2dRyu0' +
'bttobtRSlqX5Lk9zhSfcokg3Y9gqcM7+WsZ7tbB7D/LJ/iLnhLd7lpWRdKqT' +
's0Qz2/qSFp27yY3kexlzTze5gddUxt3TG7Cy0cx39wQc6bOtOM9FaiJ19mD8' +
'AJnxFdXJR+U8JI94xYMypm8/ltqXINfTnjyei0lNLfe2nRnq4RlJVqwzQx3x' +
'WX7tFpIy7zpq7jiW/82ztshzHIYFARM27zY0JNGFKJrgwEUOGXpMKkxapV/Q' +
'asLD8b8qLSTKuywquvCZez77e06gwN0yfh+icYw0liNo+jv9m/5Gv6nf0b9e' +
'qS80VDwj7lHTGL/8nXFlZlmNjBvUKOPLmoL4Bqttp9dCltZhXkFPXlnfFK4u' +
'Y1+pL3s0mUNcjE+HuhShTE0YZDzZtey+SLb4Jvx8c9kWmh61L84+qavkeqOO' +
'HZmsfnE2XA1r/7OrYNKyq/DkjZAuPGuhrlU3qd1qi7oDmrpLbVNb1U6+7VT3' +
'l3f0clYmTrJul9Wn2ION0/RWTroyWwT/Fn4x/C91CVu4pqHJf2jCzWVMS/iO' +
'4PYfd0j5L/wNAYUVDXxLOzsAAAAJcEhZcwAACxMAAAsTAQCanBgAAAGJSURB' +
'VDgRzZRPS8NAEMUnrRe1IiU5FIyQQimeKujH89KLX7CnIgULptCDIsVqTzb+' +
'ZnbzR5pGCh66MJnNzntvp5u3FTn2ETQ1mI0lkrZ05VtODdeWDfP3YCyv+3i1' +
'giYkMoAUE5EEcm4CmXySVSwlZnXCO4LZg1zT1Yi4kUwSiD2iQ+hYE0s2mNPp' +
'lJgEj/JiFf84qb5YZ1sTu0NsRG0I+Yr5peECWTFfED02PNM1OJtqp78EqQ98' +
'ZyOE7iH2iXJkEvISUruw9bZ8kd9YK860laP9ucUAEtaG5H5e28muphjFxp5r' +
'sEKQzrqsRETPfqaVGx56FO58nRM8tBRUa7iv2WFnd2YNeh7TMU5uK/ClYBP5' +
'gFopqKZ1Pluz6+pPDYdZG0e5fpSC3ADW9GstAS1ywN7sMEvjOK5BC0HvpZTu' +
'5lSeyM+GqHu4mmIUmzb5cIb7QzOt898HpDpjq9jEbktLZtU9g+qLzvFULFu5' +
'9QZPWDro6u0IelH14//8OahgPuwGHPj3lXOPN/8AwEKFiwLbAywAAAAASUVO' +
'RK5CYII=' +
') center 4px no-repeat; }' +
'</style>');
$('body').append($(
'<div id="ell-popup" title="Eyes Like Lightning">' +
'<div id="ell-l1" class="ell-l"></div>' +
'<div id="ell-l2" class="ell-m"></div>' +
'<div id="ell-l3" class="ell-s"></div>' +
'<div id="ell-l4" class="ell-m"></div>' +
'<div id="ell-l5" class="ell-l" style="margin: 5px auto 20px auto;"></div>' +
'<div id="ell-slider" style="width: 200px"></div>' +
'<div id="ell-info" style="">' +
'<span>WPM:</span>' +
'<span id="ell-wpm">' + wpm + '</span>' +
'</div>' +
'</div>'
));
var timer_handle;
var forward = function(new_wpm) {
set_wpm(new_wpm);
$('#ell-wpm').html(wpm);
var step_forward = function() {
$('#ell-l1').html($('#ell-l2').html());
$('#ell-l2').html($('#ell-l3').html());
$('#ell-l3').html($('#ell-l4').html());
$('#ell-l4').html($('#ell-l5').html());
var line = "", i = 0;
if (index < 0) index = 0;
if (words[index] == "~") {
line = "-";
} else {
for (i = 0; i < 3; i++) {
if (words[index + i] == "~") break;
if (index + i < words.length)
line += words[index + i] + " ";
if (line.length > 0)
break;
}
}
$('#ell-l5').html(line);
index += i + 1;
if (index >= words.length) index = words.length;
};
// Set the WPM display
var interval = 180000 / wpm;
// Reset the timer to a (possibly) new interval
if (timer_handle) window.clearInterval(timer_handle);
timer_handle = window.setInterval(step_forward, interval);
};
var paused = true;
var buttonpane = function() { return $('#ell-popup ~ .ui-dialog-buttonpane'); }
var set_pause = function(pval) {
var pane = buttonpane();
if (pval) {
pane.find('button:contains(Pause)').html('Continue');
if (timer_handle) window.clearInterval(timer_handle);
} else {
pane.find('button:contains(Continue)').html('Pause');
pane.find('button:contains(Start)').html('Pause');
forward(wpm);
}
paused = pval;
};
var restart = function() {
if (timer_handle) window.clearInterval(timer_handle);
$('#ell-l1').html('');
$('#ell-l2').html('');
$('#ell-l3').html('');
$('#ell-l4').html('');
$('#ell-l5').html('');
index = 0;
set_pause(true);
};
$("#ell-popup").dialog({
resizable: false,
autoOpen: true,
height: 420,
width: 600,
modal: true,
draggable: true,
buttons: {
'Close': function() {
$('#ell-popup').dialog('close');
},
'Start': function() {
paused = !paused;
set_pause(paused);
},
'Restart': restart,
'Preferences': function() {
}
},
close: function() {
if (timer_handle) window.clearInterval(timer_handle);
index = 0;
set_pause(false);
}
});
$('#ell-slider').slider({
animate: true,
value: parseInt(wpm / interval_multiplier),
slide: function(e, ui) {
if (!paused) {
forward(ui.value * interval_multiplier);
} else {
set_wpm(ui.value * interval_multiplier);
$('#ell-wpm').html(wpm);
}
}
});
}
CmdUtils.loadJQuery(function($) {
// Default to the entire document if nothing is selected
if (!text || text == "") { text = $('body').text(); }
// Double line-end characters denote new paragraph
words = text.replace(/\n\s*\n\s*/g, " ~ ").replace("-", "- ").split(/\s+/);
var css = "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css";
var js = "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js";
if ($('#ell-popup').length == 0) {
$('body').append('<link rel="stylesheet" href="' + css + '" type="text/css" />');
CmdUtils.injectJavascript(js, function() {
make_popup($);
});
reopen_dialog = function() { $('#ell-popup').dialog('open'); };
} else {
// For some reason, we need a closure here instead of a direct call to .dialog('open')...
reopen_dialog();
}
});
}
});
/*
* This represents a persistent hash for Firefox. It is a hash of
* hashes. The root hash has keys made of owners and each hash under
* each owner contains the key value pairs that the owner wishes.
*
* It utilizes the Mozilla FUEL libraries in FF3. The entire hash is
* stored as JSON within a preference in Firefox.
*
* This was specifically deisgned to allow Ubiquity commands to save
* values which would persist even after the browser has been
* restarted. In order to use this please add this code with the
* Ubiquity commands that would hypothetically use it.
*
* How the data is held:
* Extension->Preferences->Preference->Owner->Key->Value
*
* author: Jonathan Micklos (jonathan.micklos@gmail.com)
*
* param: This is the UID for an owner to store key value pairs in
* the hash. For an example, in Ubiquity, each command could
* be an owner with it's own hash of key value pairs to own.
* owner => key => value
*
*/
function persistentHash(owner) {
//You will need to change this for any given extension
var extensionKey = "ubiquity@labs.mozilla.com";
//We do not want to make a new preference for each key-value.
//In addition, we do not want to give users the ability to
//overwrite preferences the extension may already use.
var primaryKey = "persistentHash";
/*
* Check for Sanity
*/
function isSane(){
//Check to make sure the extension key exists.
if(!Application.extensions.has(extensionKey)) {
displayMessage("ERROR: Cannot find extension " + extensionKey);
return false;
}
return true;
}
function getBaseHash() {
//Check for sanity
if(!isSane()) return null;
//See if the owner exists in the preferences
if(!Application.extensions.get(extensionKey).prefs.has(primaryKey)) return new Array();
var res = Application.extensions.get(extensionKey).prefs.get(primaryKey).value;
//if the JSON is an empty string, give them a new array
if(res == '') return new Array();
//if all is good, get the JSON
return eval('(' + Application.extensions.get(extensionKey).prefs.get(primaryKey).value + ')' );
}
function getHash() {
var baseHash = getBaseHash();
if(typeof baseHash[owner] == "undefined") return new Array();
return baseHash[owner];
}
function setHash(hash) {
//Check for sanity
if(!isSane()) return;
var baseHash = getBaseHash();
baseHash[owner] = hash;
var res = "{";
for (var baseKey in baseHash) {
var tempRes = "";
hash = baseHash[baseKey];
//escape double quotes
baseKey = baseKey.replace('"','\\"');
for(var key in hash) {
var value = hash[key];
//escape double quotes
key = key.replace('"','\\"');
value = value.replace('"','\\"');
tempRes += '"' + key + '":"' + value + '",';
}
if(tempRes!="") {
res += '"' + baseKey + '":{' + tempRes + "},";
}
}
res += "}";
if(res == "{}") res = "";
//Set the newly created JSON in the preference
Application.extensions.get(extensionKey).prefs.setValue(primaryKey,res);
}
/*
* Check to see if a key is set in the hash.
*/
this.isSet = function (key) {
var hash = getHash();
if(hash == null) return false;
return !(typeof hash[key] == "undefined");
};
/*
* Get a value from the hash
*/
this.getString = function (key) {
if(!this.isSet(key)) return null;
return getHash()[key];
};
/*
* Set a value in the hash
*/
this.setString = function (key, value) {
if(!isSane() || !(typeof key == "string") || !(typeof value == "string")) return;
var hash = getHash();
hash[key] = value;
setHash(hash);
};
/*
* Get a copy of the hash.
*/
this.getHashCopy = function () {
return getHash();
};
/*
* Clear the hash out.
*/
this.clearHash = function () {
setHash(new Array());
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment