diff --git a/extensions/firefox/.gitignore b/extensions/firefox/.gitignore
new file mode 100644
index 0000000..110662c
--- /dev/null
+++ b/extensions/firefox/.gitignore
@@ -0,0 +1 @@
+package.json.backup
diff --git a/extensions/firefox/README.md b/extensions/firefox/README.md
new file mode 100644
index 0000000..9a1b66a
--- /dev/null
+++ b/extensions/firefox/README.md
@@ -0,0 +1,5 @@
+This is the imageindexer add-on. It contains:
+
+* A program (lib/main.js).
+* A few tests.
+* Some meager documentation.
diff --git a/extensions/firefox/data/style-upload.js b/extensions/firefox/data/style-upload.js
new file mode 100644
index 0000000..fb4f71e
--- /dev/null
+++ b/extensions/firefox/data/style-upload.js
@@ -0,0 +1,16 @@
+self.port.on('show', function(img_width, img_height) {
+ //create the css style sheet...we'll style the upload form using this style
+ //sheet
+ var style = document.createElement('style');
+ style.type = 'text/css';
+
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ style.innerHTML = 'body {margin: 0px; padding: 0px}';
+ style.innerHTML = style.innerHTML + 'li { display: inline; list-style-type: none; padding-right: 20px; padding: 0.5em 1em;}';
+ style.innerHTML = style.innerHTML + '#label_list {display: inline; padding-left:0px}';
+ style.innerHTML = style.innerHTML + '#filedrag {width: ' + img_width + 'px; height: ' + img_height + 'px; border: 1px solid;}';
+ style.innerHTML = style.innerHTML + '#image {display: inline-block}';
+ style.innerHTML = style.innerHTML + '#fileselect {display: none}';
+ style.innerHTML = style.innerHTML + '#submitbutton {float: left}';
+});
diff --git a/extensions/firefox/data/tag-and-save.html b/extensions/firefox/data/tag-and-save.html
new file mode 100644
index 0000000..0075ad9
--- /dev/null
+++ b/extensions/firefox/data/tag-and-save.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/firefox/data/tag-and-save.js b/extensions/firefox/data/tag-and-save.js
new file mode 100644
index 0000000..a5f02ff
--- /dev/null
+++ b/extensions/firefox/data/tag-and-save.js
@@ -0,0 +1,3 @@
+self.port.on("show", function(arg) {
+ document.getElementById('tgt_image').src = arg;
+});
diff --git a/extensions/firefox/doc/main.md b/extensions/firefox/doc/main.md
new file mode 100644
index 0000000..4dff065
--- /dev/null
+++ b/extensions/firefox/doc/main.md
@@ -0,0 +1,2 @@
+The main module is a program that creates a widget. When a user clicks on
+the widget, the program loads the mozilla.org website in a new tab.
diff --git a/extensions/firefox/lib/main.js b/extensions/firefox/lib/main.js
new file mode 100644
index 0000000..048af00
--- /dev/null
+++ b/extensions/firefox/lib/main.js
@@ -0,0 +1,51 @@
+const widgets = require("widget");
+const tabs = require("tabs");
+const cm = require("context-menu");
+const data = require("self").data;
+
+var width = 360;
+var height = 180;
+
+var thumb_width = width / 2;
+var thumb_height = height - 60;
+
+var baseURL = 'http://localhost:3000/upload';
+function createLabelousPanel(url) {
+ console.log('Creating a panel with url: ' + url);
+ var panel = require("panel").Panel({
+ width: width,
+ height: height,
+ contentURL: url,
+ contentScriptFile: data.url('style-upload.js')
+ });
+ panel.on("show", function() {
+ panel.port.emit("show", thumb_width, thumb_height);
+ });
+ return panel;
+}
+
+var widgetPanel = createLabelousPanel(baseURL);
+var widget = widgets.Widget({
+ id: "labelous-widget",
+ label: "Labelo.us",
+ contentURL: "http://www.mozilla.org/favicon.ico",
+ panel: createLabelousPanel(baseURL)
+});
+
+cm.Item({
+ label: "Send to labelo.us...",
+ context: cm.SelectorContext("img"),
+ contentScript: 'self.on("click", function (node, data) {' +
+ ' self.postMessage(node.src);' +
+ '});',
+ onMessage: function (imgSrc) {
+ openTagAndSave(imgSrc);
+ }
+});
+
+openTagAndSave = function(imageSrc) {
+
+ var panel = createLabelousPanel(baseURL + "?url=" + imageSrc);
+ panel.show();
+}
+console.log("The add-on is running.");
diff --git a/extensions/firefox/package.json b/extensions/firefox/package.json
new file mode 100644
index 0000000..6662d47
--- /dev/null
+++ b/extensions/firefox/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "imageindexer",
+ "license": "MPL 2.0",
+ "author": "",
+ "version": "0.1",
+ "fullName": "imageindexer",
+ "id": "jid1-dMw3JDjmiByCzA",
+ "description": "a basic add-on"
+}
diff --git a/extensions/firefox/test/test-main.js b/extensions/firefox/test/test-main.js
new file mode 100644
index 0000000..98d630b
--- /dev/null
+++ b/extensions/firefox/test/test-main.js
@@ -0,0 +1,32 @@
+const main = require("main");
+
+exports.test_test_run = function(test) {
+ test.pass("Unit test running!");
+};
+
+exports.test_id = function(test) {
+ test.assert(require("self").id.length > 0);
+};
+
+exports.test_url = function(test) {
+ require("request").Request({
+ url: "http://www.mozilla.org/",
+ onComplete: function(response) {
+ test.assertEqual(response.statusText, "OK");
+ test.done();
+ }
+ }).get();
+ test.waitUntilDone(20000);
+};
+
+exports.test_open_tab = function(test) {
+ const tabs = require("tabs");
+ tabs.open({
+ url: "http://www.mozilla.org/",
+ onReady: function(tab) {
+ test.assertEqual(tab.url, "http://www.mozilla.org/");
+ test.done();
+ }
+ });
+ test.waitUntilDone(20000);
+};
diff --git a/server/app.js b/server/app.js
index 2f7538a..4c84510 100644
--- a/server/app.js
+++ b/server/app.js
@@ -30,6 +30,7 @@ app.configure('production', function(){
// Routes
app.get('/', routes.index);
+app.get('/upload', routes.upload);
app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
diff --git a/server/public/javascript/dragdrop.js b/server/public/javascript/dragdrop.js
new file mode 100644
index 0000000..e2d4a39
--- /dev/null
+++ b/server/public/javascript/dragdrop.js
@@ -0,0 +1,119 @@
+/*
+ * Javascript classes to install and support HTML5 Image support
+ * This support includes:
+ * Image select w/ preview
+ * Drag and drop w/ preview
+ *
+ */
+function InstallHTML5ImageDragDrop(drag_div_id, image_id) {
+
+ var imagediv = $("#" + image_id);
+ var filedrag = $("#" + drag_div_id);
+
+ if (!window.File || !window.FileList || !window.FileReader || !imagediv || !filedrag) {
+ return;
+ }
+
+ // is XHR2 available?
+ var xhr = new XMLHttpRequest();
+ if (xhr.upload) {
+ var _this = this;
+ // file drop
+ filedrag.on("dragover", FileDragHover);
+ filedrag.on("dragleave", FileDragHover);
+ filedrag.on("drop", function(e) {
+ FileSelectHandler(e, function(e, file) {
+ OnImageDrop(e, file, imagediv);
+ });
+ });
+ //filedrag.style.display = "block";
+ // remove submit button
+ // submitbutton.style.display = "none";
+ }
+}
+
+function InstallHTML5ImageSelect(select_input_id, image_id, click_div_id) {
+ var imagediv = $("#" + image_id);
+ var fileselect = $("#" + select_input_id);
+
+ if (!window.File || !window.FileList || !window.FileReader || !imagediv || !fileselect) {
+ return;
+ }
+
+
+ // file select
+ fileselect.on("change", function(e) {
+ FileSelectHandler(e, function(e, file) {
+ OnImageDrop(e, file, imagediv);
+ });
+ });
+
+ if (click_div_id) {
+ var clickdiv = $("#" + click_div_id);
+ clickdiv.on("click", function(e) {
+ fileselect.click();
+ });
+ }
+}
+
+function OnImageDrop(e, file, image) {
+ // Render thumbnail.
+ this.image.attr("src", e.target.result);
+// var span = document.createElement('span');
+// span.innerHTML = ['
'].join('');
+// document.getElementById('list').insertBefore(span, null);
+
+}
+
+/*** Generic File Handler methods ***/
+
+//
+// output information
+function Output(msg) {
+ var m = $("#messages");
+ m.html(msg + m.html());
+}
+
+// file drag hover
+function FileDragHover(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ e.target.className = (e.type == "dragover" ? "hover" : "");
+}
+
+// file selection
+function FileSelectHandler(e, file_load_func) {
+ e = e.originalEvent || e;
+ // cancel event and hover styling
+ FileDragHover(e);
+ // fetch FileList object
+
+ var files = e.target.files || e.dataTransfer.files;
+ // process all File objects
+ for (var i = 0,
+ f; f = files[i];
+ i++) {
+ var reader = new FileReader();
+
+ // Closure to capture the file information.
+ reader.onload = (function(theFile) {
+ return function(e) {
+ file_load_func(e, theFile);
+ };
+ })(f);
+
+ // Read in the image file as a data URL.
+ reader.readAsDataURL(f);
+
+ }
+}
+
+function ParseFile(file) {
+ Output(
+ "File information: " + file.name +
+ " type: " + file.type +
+ " size: " + file.size +
+ " bytes
"
+ );
+}
diff --git a/server/public/javascript/style-upload.js b/server/public/javascript/style-upload.js
new file mode 100644
index 0000000..5e93730
--- /dev/null
+++ b/server/public/javascript/style-upload.js
@@ -0,0 +1,16 @@
+function styleUploadForm(img_width, img_height) {
+ //create the css style sheet...we'll style the upload form using this style
+ //sheet
+ var style = document.createElement('style');
+ style.type = 'text/css';
+
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ style.innerHTML = 'body {margin: 0px; padding: 0px}';
+ style.innerHTML = style.innerHTML + 'li { display: inline; list-style-type: none; padding-right: 20px; padding: 0.5em 1em;}';
+ style.innerHTML = style.innerHTML + '#label_list {display: inline; padding-left:0px}';
+ style.innerHTML = style.innerHTML + '#filedrag {width: ' + img_width + 'px; height: ' + img_height + 'px; border: 1px solid;}';
+ style.innerHTML = style.innerHTML + '#image {display: inline-block}';
+ style.innerHTML = style.innerHTML + '#fileselect {display: none}';
+ style.innerHTML = style.innerHTML + '#submitbutton {float: left}';
+}
diff --git a/server/public/javascript/upload.js b/server/public/javascript/upload.js
new file mode 100644
index 0000000..7ce0f58
--- /dev/null
+++ b/server/public/javascript/upload.js
@@ -0,0 +1,40 @@
+
+ function getUrlVars()
+ {
+ var vars = [], hash;
+ var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+ for(var i = 0; i < hashes.length; i++)
+ {
+ hash = hashes[i].split('=');
+ vars.push(hash[0]);
+ vars[hash[0]] = hash[1];
+ }
+ return vars;
+ }
+
+ function PresetUrl(image_id) {
+ var vars = getUrlVars();
+ $('#' + image_id).attr("src", vars['url']);
+ }
+
+ function label_input_keypress(e) {
+ var input = $('#label_input');
+ var code = e.keyCode || e.charCode;
+ if (code == 13 || code == 32 || code == 33 || code == 44 || code == 46 || code == 63) {
+ var label_text = input.val();
+ if (label_text != '') {
+ add_label(label_text);
+ input.val('');
+ }
+ e.preventDefault();
+ }
+ }
+
+ function add_label(label_text) {
+ var label = $('');
+ label.on("click", function(e) {
+ label.remove();
+ });
+ label.text(label_text);
+ $('#label_list').append(label);
+ }
diff --git a/server/routes/index.js b/server/routes/index.js
index fd69215..f9b9ff8 100644
--- a/server/routes/index.js
+++ b/server/routes/index.js
@@ -5,4 +5,9 @@
exports.index = function(req, res){
res.render('index', { title: 'Express' })
-};
\ No newline at end of file
+};
+
+exports.upload = function(req, res) {
+ console.log(req.query);
+ res.render('upload', { title: 'Express' })
+}
diff --git a/server/views/index.jade b/server/views/index.jade
index c9c35fa..28707f7 100644
--- a/server/views/index.jade
+++ b/server/views/index.jade
@@ -1,2 +1,20 @@
-h1= title
-p Welcome to #{title}
\ No newline at end of file
+#upload
+ form(action="/upload", method="POST")
+ #filedrag(style='width:200px;height:200px')
+ img#tgt_image
+ input(type="file", id="fileselect", name="fileselect[]", multiple="multiple")
+
+ ul#label_list
+ input#label_input(type='text')
+ script(type='text/javascript')
+ $('#label_input').on('keypress', function(e) {
+ label_input_keypress(e);
+ });
+ //TODO: pull url out of page params
+
+ #submitbutton
+ input(type="submit")
+ button(id="cancelButton") Cancel
+
+ #messages
+
diff --git a/server/views/layout.jade b/server/views/layout.jade
index 1a36941..af43530 100644
--- a/server/views/layout.jade
+++ b/server/views/layout.jade
@@ -3,4 +3,8 @@ html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
- body!= body
\ No newline at end of file
+ script(type='text/javascript', src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js')
+ script(type='text/javascript', src='javascript/upload.js')
+ script(type='text/javascript', src='javascript/dragdrop.js')
+ script(type='text/javascript', src='javascript/style-upload.js')
+ body!= body
diff --git a/server/views/upload.jade b/server/views/upload.jade
new file mode 100644
index 0000000..85454f3
--- /dev/null
+++ b/server/views/upload.jade
@@ -0,0 +1,30 @@
+#upload
+ form(action="/upload", method="POST")
+ #main_form
+ #image
+ #filedrag
+ img#tgt_image
+ input(type="file", id="fileselect", name="fileselect[]", multiple="multiple")
+
+ #label
+ ul#label_list
+ input#label_input(type='text')
+
+
+ #buttons
+ #submitbutton
+ input(type="submit")
+ button(id="cancelButton") Cancel
+
+ #messages
+
+ script(type='text/javascript')
+ InstallHTML5ImageDragDrop('filedrag', 'tgt_image');
+ InstallHTML5ImageSelect ('fileselect', 'tgt_image', 'filedrag');
+
+ $('#label_input').on('keypress', function(e) {
+ label_input_keypress(e);
+ });
+
+ $(document).ready(function() {PresetUrl('tgt_image');});
+ styleUploadForm(32, 24);