diff --git a/.gitignore b/.gitignore index 4b21df6..aede27a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.DS_Store *.tmp *.log -firefox/*.xpi +firefox/src/*.xpi +buffer.update.rdf +firefox/dist/* diff --git a/.gitmodules b/.gitmodules index fa42744..c732727 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "firefox/data/shared"] - path = firefox/data/shared +[submodule "firefox/src/data/shared"] + path = firefox/src/data/shared url = git@github.com:bufferapp/buffer-extension-shared.git diff --git a/README.md b/README.md new file mode 100644 index 0000000..54114c8 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +buffer-firefox +============== + +Legacy repository for Buffer's Firefox extension. Our Firefox extension now uses +the [WebExtensions API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions) +and shares the same codebase as Chrome ([bufferapp/buffer-chrome](https://github.com/bufferapp/buffer-chrome)). diff --git a/firefox/data/firefox/buffer-firefox-data-wrapper.js b/firefox/data/firefox/buffer-firefox-data-wrapper.js deleted file mode 100644 index c2d2514..0000000 --- a/firefox/data/firefox/buffer-firefox-data-wrapper.js +++ /dev/null @@ -1,16 +0,0 @@ -var DataWrapper = function () { - var config = {}; - config.endpoint = { - http: 'http://static.bufferapp.com/images/extensions/', - https: 'https://d389zggrogs7qo.cloudfront.net/images/extensions/', - } - return function (file) { - file = file.replace(/data\/shared\//i, ''); - return (document.location.protocol === "http:" ? config.endpoint.http : config.endpoint.https) + file; - }; -}; - -if( ! xt ) var xt = {}; -xt.data = { - get: DataWrapper() -}; \ No newline at end of file diff --git a/firefox/data/firefox/buffer-firefox-port-wrapper.js b/firefox/data/firefox/buffer-firefox-port-wrapper.js deleted file mode 100644 index a6027bc..0000000 --- a/firefox/data/firefox/buffer-firefox-port-wrapper.js +++ /dev/null @@ -1,2 +0,0 @@ -if( !xt ) var xt = {}; -xt.port = self.port; \ No newline at end of file diff --git a/firefox/data/firefox/buffer-firefox.js b/firefox/data/firefox/buffer-firefox.js deleted file mode 100644 index a8ec54d..0000000 --- a/firefox/data/firefox/buffer-firefox.js +++ /dev/null @@ -1,6 +0,0 @@ -// Buffer for Firefox -;(function() { - self.port.on("buffer_click", function(postData) { - bufferData(self.port, postData); - }); -}()); \ No newline at end of file diff --git a/firefox/data/firefox/menu/buffer-image.js b/firefox/data/firefox/menu/buffer-image.js deleted file mode 100644 index 794de25..0000000 --- a/firefox/data/firefox/menu/buffer-image.js +++ /dev/null @@ -1,3 +0,0 @@ -self.on("click", function (node, data) { - self.postMessage(node.src); -}) \ No newline at end of file diff --git a/firefox/data/firefox/menu/buffer-page.js b/firefox/data/firefox/menu/buffer-page.js deleted file mode 100644 index ced611f..0000000 --- a/firefox/data/firefox/menu/buffer-page.js +++ /dev/null @@ -1,4 +0,0 @@ -// Buffer Page -self.on("click", function () { - self.postMessage("buffer_click"); -}) \ No newline at end of file diff --git a/firefox/data/shared b/firefox/data/shared deleted file mode 160000 index 25574b6..0000000 --- a/firefox/data/shared +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 25574b6da886d91abcc3b682b320861ccec12880 diff --git a/firefox/lib/main.js b/firefox/lib/main.js deleted file mode 100644 index deb677a..0000000 --- a/firefox/lib/main.js +++ /dev/null @@ -1,333 +0,0 @@ -/* - -Buffer for Firefox - -Authors: Joel Gascoigne Tom Ashworth - joel@bufferapp.com tom.a@bufferapp.com - -*/ - -// Plugin APIs -var widgets = require("widget"); -var tabs = require("tabs"); -var self = require("self"); -var pageMod = require("page-mod"); -var selection = require("selection"); -var ss = require("simple-storage"); -var { Hotkey } = require('hotkeys'); -var cm = require("context-menu"); -var {Cc, Ci} = require('chrome'); -var mediator = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator); - -// Configuration -var config = {}; -config.plugin = { - label: "Buffer This Page", - icon: { - static: self.data.url('firefox/img/buffer-icon.png'), - hover: self.data.url('firefox/img/buffer-icon-hover.png'), - loading: self.data.url('firefox/img/buffer-icon-loading.png'), - small: self.data.url('firefox/img/buffer-icon-small.png'), - small_loading: self.data.url('firefox/img/buffer-icon-small-loading.png') - }, - guide: 'http://bufferapp.com/guides/firefox/installed', - version: "2.1.8", - menu: { - page: { - label: "Buffer This Page", - scripts: [self.data.url('firefox/menu/buffer-page.js')] - }, - selection: { - label: "Buffer Selected Text" - }, - image: { - label: "Buffer This Image", - scripts: [self.data.url('firefox/menu/buffer-image.js')] - }, - }, - overlay: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('shared/libs/postmessage.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-scraper.js'), - self.data.url('shared/buffer-overlay.js'), - self.data.url('firefox/buffer-firefox.js') - ] - }, - twitter: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-twitter.js') - ] - }, - hn: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-hn.js') - ] - }, - reader: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-google-reader.js') - ] - }, - reddit: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-reddit.js') - ] - }, - facebook: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('firefox/buffer-firefox-data-wrapper.js'), - self.data.url('shared/embeds/buffer-facebook.js') - ] - }, - hotkey: { - scripts: [ - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('shared/embeds/buffer-hotkey.js') - ] - }, - scraper: { - scripts: [ - self.data.url('shared/libs/jquery-1.7.2.min.js'), - self.data.url('firefox/buffer-firefox-port-wrapper.js'), - self.data.url('shared/embeds/buffer-overlay-scraper.js') - ] - } -}; - -/** - * Workers - */ -var overlayWorker, scraperWorker; - -var listenForDataRequest = function (worker) { - worker.port.on("buffer_get_data", function (file) { - worker.port.emit("buffer_data_url", self.data.url(file)); - }); -}; -var listenForDetailsRequest = function (worker) { - - console.log("listenForDetailsRequest"); - - if( ! overlayWorker ) return; - - scraperWorker = worker; - - overlayWorker.port.on("buffer_details", function (data) { - console.log("buffer_details", data); - scraperWorker.port.emit("buffer_details", data); - }); - - scraperWorker.port.on("buffer_details_request", function () { - console.log("buffer_details_request recieved by main"); - overlayWorker.port.emit("buffer_details_request") - }); - -}; -// Overlay -var attachOverlay = function (data, cb) { - - if( typeof data === 'function' ) cb = data; - if( ! data ) data = {}; - if( ! cb ) cb = function () {}; - if( ! data.embed ) data.embed = {}; - - console.log("Setting up overlayWorker"); - - var worker = tabs.activeTab.attach({ - contentScriptFile: config.plugin.overlay.scripts - }); - - overlayWorker = worker; - - listenForDataRequest(worker); - - worker.port.on('buffer_done', function (overlayData) { - worker.destroy(); - cb(overlayData); - }); - - // Pass statistic data - data.version = config.plugin.version; - if( data.embed.placement ) data.placement = data.embed.placement; - - // Inform overlay that click has occurred - worker.port.emit("buffer_click", data); -}; - -// Show guide on first run -if( ! ss.storage.run ) { - ss.storage.run = true; - tabs.open({ - url: config.plugin.guide - }); -} - -// Buffer this page - -var button = widgets.Widget({ - id: 'buffer-button', - label: config.plugin.label, - contentURL: config.plugin.icon.static, - onMouseover: function () { - if( this.contentURL !== config.plugin.icon.loading) { - this.contentURL = config.plugin.icon.hover; - } - }, - onMouseout: function () { - if( this.contentURL !== config.plugin.icon.loading) { - this.contentURL = config.plugin.icon.static; - } - } -}) -button.on('click', function () { - prev = config.plugin.icon.loading; - button.contentURL = config.plugin.icon.loading; - attachOverlay({placement: 'toolbar'}, function() { - button.contentURL = config.plugin.icon.static; - }); -}) - -// Context menu -var menu = {} -menu.page = cm.Item({ - label: config.plugin.menu.page.label, - image: config.plugin.icon.static, - context: cm.PageContext(), - contentScriptFile: config.plugin.menu.page.scripts, - contentScriptWhen: 'start', - onMessage: function (data) { - if(data == 'buffer_click') { - attachOverlay({placement: 'menu-page'}); - } - } -}); -menu.selection = cm.Item({ - label: config.plugin.menu.selection.label, - image: config.plugin.icon.static, - context: cm.SelectionContext(), - contentScriptFile: config.plugin.menu.page.scripts, - contentScriptWhen: 'start', - onMessage: function (data) { - if(data == 'buffer_click') { - attachOverlay({placement: 'menu-selection'}); - } - } -}); - -var embedHandler = function (worker, scraper) { - - listenForDataRequest(worker); - - if( scraper ) { - scraperWorker = worker; - listenForDetailsRequest(worker); - } - - worker.port.on('buffer_click', function (embed) { - // Buffer a tweet - attachOverlay({embed: embed}, function (overlaydata) { - if( !!overlaydata.sent ) { - // Buffer was sent - worker.port.emit("buffer_embed_clear"); - } - }); - }); -}; - -// Navigation bar icon -// exports.main is called when extension is installed or re-enabled -exports.main = function(options, callbacks) { - // this document is an XUL document - var document = mediator.getMostRecentWindow('navigator:browser').document; - var navBar = document.getElementById('nav-bar'); - if (!navBar) { - return; - } - var btn = document.createElement('toolbarbutton'); - btn.setAttribute('id', 'buffer-button'); - btn.setAttribute('type', 'button'); - // the toolbarbutton-1 class makes it look like a traditional button - btn.setAttribute('class', 'toolbarbutton-1'); - btn.setAttribute('width', 'auto'); - btn.setAttribute('image', config.plugin.icon.small); - // this text will be shown when the toolbar is set to text or text and icons - btn.setAttribute('label', config.plugin.label); - btn.addEventListener('click', function() { - // Go go go - attachOverlay({placement: 'toolbar'}); - }, false) - navBar.appendChild(btn); -}; - -// exports.onUnload is called when Firefox starts and when the extension is disabled or uninstalled -exports.onUnload = function(reason) { - // this document is an XUL document - var document = mediator.getMostRecentWindow('navigator:browser').document; - var navBar = document.getElementById('nav-bar'); - var btn = document.getElementById('buffer-button'); - if (navBar && btn) { - navBar.removeChild(btn); - } -}; - -// Embeds -pageMod.PageMod({ - include: '*', - contentScriptFile: config.plugin.hotkey.scripts, - onAttach: embedHandler -}); - -pageMod.PageMod({ - include: '*.bufferapp.com', - contentScriptFile: config.plugin.scraper.scripts, - onAttach: function(worker) { - embedHandler(worker, true); - } -}); - -pageMod.PageMod({ - include: '*.twitter.com', - contentScriptFile: config.plugin.twitter.scripts, - onAttach: embedHandler -}); - -pageMod.PageMod({ - include: '*.facebook.com', - contentScriptFile: config.plugin.facebook.scripts, - onAttach: embedHandler -}); - -pageMod.PageMod({ - include: '*.google.com', - contentScriptFile: config.plugin.reader.scripts, - onAttach: embedHandler -}); - -pageMod.PageMod({ - include: '*.reddit.com', - contentScriptFile: config.plugin.reddit.scripts, - onAttach: embedHandler -}); - -pageMod.PageMod({ - include: ['*.ycombinator.com', '*.ycombinator.org'], - contentScriptFile: config.plugin.hn.scripts, - onAttach: embedHandler -}); \ No newline at end of file diff --git a/firefox/package.json b/firefox/package.json deleted file mode 100644 index e7cfbf3..0000000 --- a/firefox/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "Easily add great articles, pictures and videos to your Buffer and we automagically share them for you through the day!", - "license": "MPL 1.1/GPL 2.0/LGPL 2.1", - "author": "Buffer", - "version": "2.2", - "fullName": "Buffer for Firefox", - "id": "jid1-zUyU7TGKwejAyA", - "name": "buffer", - "homepage": "http://bufferapp.com/guides/firefox", - "icon": "data/shared/img/Icon.png" -} \ No newline at end of file diff --git a/firefox/README.md b/firefox/src/README.md similarity index 100% rename from firefox/README.md rename to firefox/src/README.md diff --git a/firefox/doc/main.md b/firefox/src/chrome.manifest similarity index 100% rename from firefox/doc/main.md rename to firefox/src/chrome.manifest diff --git a/firefox/src/data/firefox/buffer-firefox-data-wrapper.js b/firefox/src/data/firefox/buffer-firefox-data-wrapper.js new file mode 100644 index 0000000..fa7cbc3 --- /dev/null +++ b/firefox/src/data/firefox/buffer-firefox-data-wrapper.js @@ -0,0 +1,45 @@ +/* globals self */ +/** + * Currently all static files referenced in a firefox extension must be added + * to the images/extensions folder in the buffer-web repo. + * In the future, possibly refactor this so we can pass the proper file url + * as in: http://stackoverflow.com/questions/11551467/how-to-reference-a-file-in-the-data-directory-of-a-firefox-extension + */ + +var DataWrapper = function () { + var config = {}; + config.endpoint = { + http: 'http://static.bufferapp.com/images/extensions/', + https: 'https://d389zggrogs7qo.cloudfront.net/images/extensions/', + }; + + // Keep reference to all handlers so we can remove them + var handlers = {}; + + return function (file, callback) { + + // If not async method, use the CDN + if (typeof callback !== 'function') { + file = file.replace(/data\/shared\//i, ''); + var protocol = document.location.protocol.replace(':', ''); + return config.endpoint[protocol] + file; + } + + file = file.replace(/data\//i, ''); + var key = file + Math.floor(Math.random()* 1000); + + handlers[key] = function(url) { + callback(url); + self.port.removeListener('buffer_file_url', handlers[key]); + }; + + self.port.on('buffer_file_url', handlers[key]); + self.port.emit('buffer_get_file', file); + + }; +}; + +if( ! xt ) var xt = {}; +xt.data = { + get: DataWrapper() +}; diff --git a/firefox/src/data/firefox/buffer-firefox-popup-content-script.js b/firefox/src/data/firefox/buffer-firefox-popup-content-script.js new file mode 100644 index 0000000..d82b230 --- /dev/null +++ b/firefox/src/data/firefox/buffer-firefox-popup-content-script.js @@ -0,0 +1,15 @@ +// Piggyback on window.close to make sure the window gets closed, +// even if open from privileged code (which is prevented by Firefox). +// unsafeWindow is a reference to the window object in the page +// script, and cloneInto is used to pass objects to that less- +// privileged scope. +;(function() { + var originalClose = unsafeWindow.close.bind(unsafeWindow); + var close = function() { + var didWindowClose = originalClose(); + + if (!didWindowClose) self.port.emit("buffer_close_popup"); + }; + + unsafeWindow.close = cloneInto(close, unsafeWindow, { cloneFunctions: true }); +})(); diff --git a/firefox/src/data/firefox/buffer-firefox-port-wrapper.js b/firefox/src/data/firefox/buffer-firefox-port-wrapper.js new file mode 100644 index 0000000..52a899a --- /dev/null +++ b/firefox/src/data/firefox/buffer-firefox-port-wrapper.js @@ -0,0 +1,7 @@ +if( !xt ) var xt = {}; +xt.port = self.port; + + +xt.port.on('buffer_options', function (options) { + xt.options = options; +}); \ No newline at end of file diff --git a/firefox/src/data/firefox/buffer-firefox.js b/firefox/src/data/firefox/buffer-firefox.js new file mode 100644 index 0000000..7b43a60 --- /dev/null +++ b/firefox/src/data/firefox/buffer-firefox.js @@ -0,0 +1,41 @@ +/* globals self, bufferpm, bufferData */ +// Buffer for Firefox +;(function() { + // In most cases we'll want to simply open the overlay when a Buffer button + // is clicked. In some specific cases, we'll want to provide a more tailored + // experience, e.g. retweeting a tweet when we're on a tweet's permalink page + // and the Buffer toolbar button is clicked + self.port.on("buffer_click", function(postData) { + var isTweetPermalinkPage = /twitter\.com\/[^/]+\/status\/\d+/.test(window.location.href); + var $retweetButton = $('.permalink-tweet .ProfileTweet-action--buffer'); + + var shouldTriggerRetweetButtonClick = ( + isTweetPermalinkPage && + postData.placement === 'toolbar' && + $retweetButton.length > 0 + ); + + if (shouldTriggerRetweetButtonClick) { + $retweetButton.click(); + } else { + // bufferData is a method in buffer-overlay that creates + // the overlay and gives it data. + bufferData(self.port, postData); + } + }); + + self.port.on("buffer_message_bind", function(postData) { + // Bind close listener + // Listen for when the overlay has closed itself + bufferpm.bind("buffermessage", function(overlaydata) { + var temp = document.getElementById('buffer_overlay'); + document.body.removeChild(temp); + bufferpm.unbind("buffermessage"); + setTimeout(function () { + self.port.emit('buffer_done', overlaydata) + }, 0); + window.focus(); + }); + }); + +}()); diff --git a/firefox/data/firefox/img/buffer-icon-hover.png b/firefox/src/data/firefox/img/buffer-icon-hover.png similarity index 100% rename from firefox/data/firefox/img/buffer-icon-hover.png rename to firefox/src/data/firefox/img/buffer-icon-hover.png diff --git a/firefox/data/firefox/img/buffer-icon-loading.png b/firefox/src/data/firefox/img/buffer-icon-loading.png similarity index 100% rename from firefox/data/firefox/img/buffer-icon-loading.png rename to firefox/src/data/firefox/img/buffer-icon-loading.png diff --git a/firefox/data/firefox/img/buffer-icon-small-loading.png b/firefox/src/data/firefox/img/buffer-icon-small-loading.png similarity index 100% rename from firefox/data/firefox/img/buffer-icon-small-loading.png rename to firefox/src/data/firefox/img/buffer-icon-small-loading.png diff --git a/firefox/data/firefox/img/buffer-icon-small.png b/firefox/src/data/firefox/img/buffer-icon-small.png similarity index 100% rename from firefox/data/firefox/img/buffer-icon-small.png rename to firefox/src/data/firefox/img/buffer-icon-small.png diff --git a/firefox/data/firefox/img/buffer-icon.png b/firefox/src/data/firefox/img/buffer-icon.png similarity index 100% rename from firefox/data/firefox/img/buffer-icon.png rename to firefox/src/data/firefox/img/buffer-icon.png diff --git a/firefox/src/data/firefox/menu/buffer-image.js b/firefox/src/data/firefox/menu/buffer-image.js new file mode 100644 index 0000000..662e482 --- /dev/null +++ b/firefox/src/data/firefox/menu/buffer-image.js @@ -0,0 +1,6 @@ +self.on("click", function (node, data) { + self.postMessage({ + nodeSrc: node.src, + documentUrl: document.URL + }); +}) diff --git a/firefox/src/data/firefox/menu/buffer-page.js b/firefox/src/data/firefox/menu/buffer-page.js new file mode 100644 index 0000000..03fb047 --- /dev/null +++ b/firefox/src/data/firefox/menu/buffer-page.js @@ -0,0 +1,7 @@ +// Buffer Page +self.on("click", function () { + self.postMessage({ + action: "buffer_click", + documentUrl: document.URL + }); +}) diff --git a/firefox/src/data/icons/icon-128.png b/firefox/src/data/icons/icon-128.png new file mode 100644 index 0000000..8bbe1dc Binary files /dev/null and b/firefox/src/data/icons/icon-128.png differ diff --git a/firefox/src/data/icons/icon-16.png b/firefox/src/data/icons/icon-16.png new file mode 100644 index 0000000..b3beef6 Binary files /dev/null and b/firefox/src/data/icons/icon-16.png differ diff --git a/firefox/src/data/icons/icon-32.png b/firefox/src/data/icons/icon-32.png new file mode 100644 index 0000000..536e316 Binary files /dev/null and b/firefox/src/data/icons/icon-32.png differ diff --git a/firefox/src/data/icons/icon-64.png b/firefox/src/data/icons/icon-64.png new file mode 100644 index 0000000..62acf7b Binary files /dev/null and b/firefox/src/data/icons/icon-64.png differ diff --git a/firefox/src/data/shared b/firefox/src/data/shared new file mode 160000 index 0000000..f8e9b7c --- /dev/null +++ b/firefox/src/data/shared @@ -0,0 +1 @@ +Subproject commit f8e9b7c0d1d7f64b402991c3d9d80354d5207849 diff --git a/firefox/src/lib/bufferSrc.js b/firefox/src/lib/bufferSrc.js new file mode 100644 index 0000000..aa5ac6d --- /dev/null +++ b/firefox/src/lib/bufferSrc.js @@ -0,0 +1,241 @@ +var doc; +var win; + +// Build that overlay! +// Triggered by code working from the button up... +var bufferOverlay = function(data, config, doneCallback) { + + + if( ! doneCallback ) doneCallback = function () {}; + if( ! config ) return; + + // Put together a query string for the iframe + var buildSrc = function() { + var src = config.overlay.endpoint; + if( data.local ) src = config.overlay.localendpoint; + + // Add button attributes + var first = true, count = 0; + for(var i=0, l=config.attributes.length; i < l; i++) { + var a = config.attributes[i]; + if( ! data[a.name] ) continue; + if( first ) { src += '?'; first = false; } + count += 1; + if( count > 1 ) src += '&'; + src += a.name + '=' + a.encode(data[a.name]); + } + + return src; + }; + + var src = buildSrc(); + win.open(src, null, 'width=850,height=600'); + + +}; + +// bufferData is triggered by the buffer_click listener in +// the buffer-browser-embed file, where it's passed a port +// to communicate with the extension and data sent from the +// background page. +exports.bufferData = function (port, postData, window) { + + + win = window; + doc = window.document; + + if (win.top !== win) { + return; + } + + var config = {}; + config.local = false; + config.googleReader = false; + var segments = win.location.pathname.split('/'); + if( win.location.host.indexOf("google") != -1 && segments[1] == "reader" ) config.googleReader = true; + + // Specification for gathering data for the overlay + config.attributes = [ + { + name: "url", + get: function (cb) { + if( ! config.googleReader ) { + cb(win.location.href); + } else { + var href = $("#current-entry .entry-container a.entry-title-link").attr('href'); + if( ! href ) href = $('.entry').first().find(".entry-container a.entry-title-link").attr('href'); + cb(href); + } + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "text", + get: function (cb) { + if( config.googleReader ) { + var text = $("#current-entry .entry-container a.entry-title-link").text(); + if( ! text ) text = $('.entry').first().find(".entry-container a.entry-title-link").text(); + cb(text); + } else if(doc.getSelection() != false) { + cb('"' + doc.getSelection().toString() + '"'); + } else { + cb(doc.title); + } + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "retweeted_tweet_id", + get: function (cb) { + cb(postData.retweeted_tweet_id); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "retweeted_user_id", + get: function (cb) { + cb(postData.retweeted_user_id); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "retweeted_user_name", + get: function (cb) { + cb(postData.retweeted_user_name); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "retweeted_user_display_name", + get: function (cb) { + cb(postData.retweeted_user_display_name); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "picture", + get: function (cb) { + cb(postData.image); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "embed", + get: function (cb) { + cb(postData.embed); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "local", + get: function (cb) { + cb(config.local); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "version", + get: function (cb) { + cb(postData.version); + }, + encode: function (val) { + return encodeURIComponent(val); + } + }, + { + name: "placement", + get: function (cb) { + if( postData.placement ) cb(postData.placement); + else if( config.googleReader ) cb('google-reader-general'); + else cb('general'); + }, + encode: function (val) { + return encodeURIComponent(val); + } + } + ]; + config.overlay = { + endpoint: (config.local ? 'http:' : doc.location.protocol) + '//buffer.com/add/', + localendpoint: (config.local ? 'http:' : doc.location.protocol) + '//local.buffer.com/add/', + getCSS: function () { return "border:none;height:100%;width:100%;position:fixed!important;z-index:99999999;top:0;left:0;display:block!important;max-width:100%!important;max-height:100%!important;padding:0!important;"; } + }; + + // Method for handling the async firing of the cb + var executeAfter = function(done, count, data, cb) { + if(done === count) { + cb(data) + } + }; + + // Asynchronously gather data about the page and from embedded sources, + // like Twitter or Facebook. Currently the async is a bit over the top, + // and not used, but if we need aysnc down the line, it's there. + var getData = function (cb) { + var count = config.attributes.length; + var done = 0; + var data = {}; + for(var i=0; i < count; i++) { + // Wrapped in a self-executing function to ensure we don't overwrite ā€˜a’ + // and that the correct ā€˜i’ is used + (function (i) { + var a = config.attributes[i]; + a.get(function(d) { + done += 1; + data[a.name] = d; + executeAfter(done, count, data, cb); + }); + }(i)); + } + }; + + // Transform the data somewhat, and then create an overlay. + // When it's done, fire buffer_done back to the extension + var createOverlay = function (data) { + if( data.embed ) { + if( typeof data.embed === "object" ) { + for( var i in data.embed ) { + if( data.embed.hasOwnProperty(i) ) { + data[i] = data.embed[i]; + } + } + if( data.embed.text && !data.embed.url ) { + data.url = null; + } + data.embed = null; + } else { + data.text = data.embed; + data.url = null; + data.embed = null; + } + } + bufferOverlay(data, config, function (overlaydata) { + port.emit("buffer_done", overlaydata); + }); + }; + + // It all starts here. + // createOverlay is the callback that should fire after getData has + // gathered all the neccessaries + getData(createOverlay); + port.emit('buffer_message_bind') + +}; + diff --git a/firefox/src/lib/config.js b/firefox/src/lib/config.js new file mode 100644 index 0000000..41ee07a --- /dev/null +++ b/firefox/src/lib/config.js @@ -0,0 +1,160 @@ +/* jshint node:true, esnext:true */ +/** + * Master configuration for extension + */ + +var self = require('sdk/self'); + +exports.plugin = { + label: 'Buffer This Page', + icon: { + static: self.data.url('firefox/img/buffer-icon.png'), + hover: self.data.url('firefox/img/buffer-icon-hover.png'), + loading: self.data.url('firefox/img/buffer-icon-loading.png'), + small: self.data.url('firefox/img/buffer-icon-small.png'), + small_loading: self.data.url('firefox/img/buffer-icon-small-loading.png') + }, + guide: 'http://buffer.com/guides/firefox/installed', + browser: 'firefox', + version: self.version, + menu: { + page: { + label: 'Buffer This Page', + scripts: [self.data.url('firefox/menu/buffer-page.js')] + }, + selection: { + label: 'Buffer Selected Text' + }, + image: { + label: 'Buffer This Image', + scripts: [self.data.url('firefox/menu/buffer-image.js')] + }, + pablo_image: { + label: 'Open Image With Pablo', + scripts: [self.data.url('firefox/menu/buffer-image.js')] + } + }, + overlay: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('shared/libs/postmessage.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-scraper.js'), + self.data.url('shared/buffer-overlay.js'), + self.data.url('firefox/buffer-firefox.js') + ], + styles: [ + self.data.url('shared/buffer-overlay.css') + ] + }, + popup: { + scripts: [ + self.data.url('firefox/buffer-firefox-popup-content-script.js') + ] + }, + twitter: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-twitter.js') + ], + styles: [ + self.data.url('shared/embeds/buffer-twitter.css') + ] + }, + tweetdeck: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-tweetdeck.js') + ], + styles: [ + self.data.url('shared/embeds/buffer-tweetdeck.css') + ] + }, + pinterest: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-pinterest.js') + ], + styles: [ + self.data.url('shared/embeds/buffer-pinterest.css') + ] + }, + hn: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-hn.js') + ] + }, + reddit: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-reddit.js') + ] + }, + facebook: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-facebook.js') + ], + styles: [ + self.data.url('shared/embeds/buffer-facebook.css') + ] + }, + quora: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-quora.js') + ] + }, + tpccheck: { + scripts: [ + self.data.url('shared/libs/postmessage.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('shared/embeds/buffer-tpc-check.js') + ] + }, + hotkey: { + scripts: [ + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('shared/libs/keymaster.js'), + self.data.url('shared/embeds/buffer-hotkey.js') + ] + }, + hoverButton: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('firefox/buffer-firefox-data-wrapper.js'), + self.data.url('shared/embeds/buffer-hover-button.js') + ] + }, + scraper: { + scripts: [ + self.data.url('shared/libs/jquery-2.1.1.min.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('shared/embeds/buffer-overlay-scraper.js') + ] + }, + bufferapp: { + scripts: [ + self.data.url('shared/buffer-install-check.js'), + self.data.url('firefox/buffer-firefox-port-wrapper.js'), + self.data.url('shared/buffer-extension-settings.js') + ] + } +}; diff --git a/firefox/src/lib/legacy.js b/firefox/src/lib/legacy.js new file mode 100644 index 0000000..1c78621 --- /dev/null +++ b/firefox/src/lib/legacy.js @@ -0,0 +1,92 @@ +/* jshint node:true, esnext:true */ +/** + * Legacy code for FF 28 and lower + */ + +var config = require('./config'); + +const BUFFER_BUTTON_ID = 'buffer-button'; + +var getMediator = function() { + var { Cc, Ci } = require('chrome'); + return Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator); +}; + +var getMostRecentWindow = function(mediator) { + return mediator.getMostRecentWindow('navigator:browser'); +}; + +var addNavBarButton = exports.addNavBarButton = function(onButtonClick) { + + var mediator = getMediator(); + var browserWindow = getMostRecentWindow(mediator); + + var widgets = require("sdk/widget"); + + var button = widgets.Widget({ + id: BUFFER_BUTTON_ID, + label: config.plugin.label, + contentURL: config.plugin.icon.static + }); + + button.on('click', function () { + onButtonClick(); + }); + + var document = browserWindow.document; + var navBar = document.getElementById('nav-bar'); + if (!navBar) { + return; + } + var btn = document.createElement('toolbarbutton'); + btn.setAttribute('id', BUFFER_BUTTON_ID); + btn.setAttribute('type', 'button'); + // the toolbarbutton-1 class makes it look like a traditional button + btn.setAttribute('class', 'toolbarbutton-1'); + btn.setAttribute('image', config.plugin.icon.small); + // this text will be shown when the toolbar is set to text or text and icons + btn.setAttribute('label', config.plugin.label); + btn.addEventListener('click', function() { + // Go go go + onButtonClick(); + }, false); + navBar.appendChild(btn); + + // Add listeners + mediator.addListener(windowListener); + +}; + +var removeNavBarButton = exports.removeNavBarButton = function() { + + var mediator = getMediator(); + var browserWindow = getMostRecentWindow(mediator); + var doc = browserWindow.document; + if (!doc) return; + var navBar = doc.getElementById('nav-bar'); + var btn = doc.getElementById(BUFFER_BUTTON_ID); + if (navBar && btn) { + navBar.removeChild(btn); + } + mediator.removeListener(windowListener); + +}; + +// handle new windows +var windowListener = { + onOpenWindow: function(aWindow) { + var { Ci } = require('chrome'); + // Wait for the window to finish loading + var domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); + addNavBarButton(domWindow); + domWindow.addEventListener("load", function() { + domWindow.removeEventListener("load", arguments.callee, false); + addNavBarButton(domWindow); + }, false); + }, + onCloseWindow: function(aWindow) { + removeNavBarButton(aWindow); + }, + onWindowTitleChange: function(aWindow, aTitle) { } +}; diff --git a/firefox/src/lib/main.js b/firefox/src/lib/main.js new file mode 100644 index 0000000..c9d7a06 --- /dev/null +++ b/firefox/src/lib/main.js @@ -0,0 +1,415 @@ +/* jshint node:true, esnext:true */ +/* + * Two files are appended at the end of main.js at build time: data/shared/buffermetrics-bg-shim.js and data/shared/buffermetrics.js + * This allows to reuse buffermetrics.js throughout buffer-web and extensions and still work with Firefox's module system. + * isFirefox = true; is a global shared with those scripts. + */ +var isFirefox = true; + +/* globals _bmq */ +/* + +Buffer for Firefox + +Authors: Joel Gascoigne Tom Ashworth + joel@bufferapp.com tom.a@bufferapp.com + +*/ + +// Plugin APIs +var system = require('sdk/system'); +var buttons = require('sdk/ui/button/action'); +var tabs = require('sdk/tabs'); +var tabsUtils = require('sdk/tabs/utils'); +var self = require('sdk/self'); +var pageMod = require('sdk/page-mod'); +var ss = require('sdk/simple-storage'); +var cm = require('sdk/context-menu'); + +var selection = require('sdk/selection'); +var config = require('./config'); +var bufferSrc = require('./bufferSrc'); +var prefs = require('./prefs'); +var legacy = require('./legacy'); + +var tpc_disabled = false; +var extensionUserData = ss.storage.extensionUserData; + +const FIREFOX_VERSION = parseInt(system.version.split('.')[0]); +const BUFFER_BUTTON_ID = 'buffer-button'; + + +/** + * Workers + */ +var overlayWorker; +var scraperWorker; + +var listenForDataRequest = function (worker) { + worker.port.on("buffer_get_data", function (file) { + worker.port.emit("buffer_data_url", self.data.url(file)); + }); + + worker.port.emit("buffer_options", prefs.buildOptions()); +}; + +var listenForDetailsRequest = function (worker) { + + if( ! overlayWorker ) return; + + scraperWorker = worker; + + overlayWorker.port.on("buffer_details", function (data) { + scraperWorker.port.emit("buffer_details", data); + }); + + scraperWorker.port.on("buffer_details_request", function () { + overlayWorker.port.emit("buffer_details_request"); + }); + +}; + +/** + * Attach the iframe overlay + */ +var attachOverlay = function (data, cb) { + + if( typeof data === 'function' ) cb = data; + if( ! data ) data = {}; + if( ! cb ) cb = function () {}; + if( ! data.embed ) data.embed = {}; + + var worker = tabs.activeTab.attach({ + contentScriptFile: config.plugin.overlay.scripts + }); + + overlayWorker = worker; + + listenForDataRequest(worker); + + worker.port.on('buffer_done', function (overlayData) { + worker.destroy(); + cb(overlayData); + }); + + // Pass statistic data + data.version = config.plugin.version; + if( data.embed.placement ) data.placement = data.embed.placement; + + var windows = tabsUtils.getAllTabContentWindows(); + var window = windows[tabs.activeTab.index]; + + if(tpc_disabled) { + //trigger the popup instead of the iframe + bufferSrc.bufferData(worker.port, data, window); + } + else { + worker.port.emit('buffer_click', data); + } + + // Listen to overlay asking to open a popup from privileged code + // to bypass CSP on some sites + worker.port.on('buffer_open_popup', function(options) { + var url = options.src; + var isSmallPopup = !!options.isSmallPopup; + + if (isSmallPopup) { + window.open(url, null, 'width=850,height=600'); + } else { + tabs.open({ + url: url, + inNewWindow: true, + + onLoad: function(tab) { + var worker = tab.attach({ + contentScriptFile: config.plugin.popup.scripts + }); + + worker.port.on("buffer_close_popup", function() { + tab.close(); + }) + } + }); + } + }); + + // Map content script _bmq calls to the real _bmq here + worker.port.on('buffer_tracking', function(payload) { + _bmq[payload.methodName].apply(_bmq, payload.args); + }); + + // Send cached user data to overlay when it opens up + if (extensionUserData) { + worker.port.on('buffer_overlay_open', function() { + worker.port.emit('buffer_user_data', extensionUserData); + }); + } + + // Listen for user data from buffer-overlay, and cache it here + worker.port.on('buffer_user_data', function(userData) { + extensionUserData = userData; + ss.storage.extensionUserData = extensionUserData; + worker.port.emit('buffer_user_data', extensionUserData); + }); +}; + +// Show guide on first run +if( ! ss.storage.run ) { + ss.storage.run = true; + tabs.open({ + url: config.plugin.guide + }); +} + +/** + * Context menu + */ +var menu = {}; +menu.page = cm.Item({ + label: config.plugin.menu.page.label, + image: config.plugin.icon.static, + context: cm.PageContext(), + contentScriptFile: config.plugin.menu.page.scripts, + contentScriptWhen: 'start', + onMessage: function (data) { + if(data.action == 'buffer_click') { + attachOverlay({placement: 'menu-page'}); + } + } +}); +menu.selection = cm.Item({ + label: config.plugin.menu.selection.label, + image: config.plugin.icon.static, + context: cm.SelectionContext(), + contentScriptFile: config.plugin.menu.page.scripts, + contentScriptWhen: 'start', + onMessage: function (data) { + if(data.action == 'buffer_click') { + attachOverlay({placement: 'menu-selection'}); + } + } +}); +menu.pablo = cm.Item({ + label: 'Create Image With Pablo', + image: config.plugin.icon.static, + context: cm.SelectionContext(), + contentScriptFile: config.plugin.menu.page.scripts, + contentScriptWhen: 'start', + onMessage: function (data) { + if(data.action == 'buffer_click') { + tabs.open('https://buffer.com/pablo?text=' + encodeURIComponent(selection.text) + '&source_url=' + encodeURIComponent(data.documentUrl)); + } + } +}); + +menu.image = cm.Item({ + label: config.plugin.menu.image.label, + image: config.plugin.icon.static, + context: cm.SelectorContext('img'), + contentScriptFile: config.plugin.menu.image.scripts, + contentScriptWhen: 'start', + onMessage: function (data) { + attachOverlay({placement: 'menu-image', image: data.nodeSrc}); + } +}); + +menu.pablo_image = cm.Item({ + label: config.plugin.menu.pablo_image.label, + image: config.plugin.icon.static, + context: cm.SelectorContext('img'), + contentScriptFile: config.plugin.menu.image.scripts, + contentScriptWhen: 'start', + onMessage: function(data) { + tabs.open('https://buffer.com/pablo?image=' + encodeURIComponent(data.nodeSrc) + '&source_url=' + encodeURIComponent(data.documentUrl)); + } +}); + + +var tpcEmbedHandler = function(worker) { + worker.port.on('buffer_tpc_disabled', function() { + tpc_disabled = true; + }); +}; + +var embedHandler = function (worker, scraper) { + + listenForDataRequest(worker); + + // Firefox get file async + worker.port.on('buffer_get_file', function (file) { + worker.port.emit('buffer_file_url', self.data.url(file)); + }); + + if( scraper ) { + scraperWorker = worker; + listenForDetailsRequest(worker); + } + + worker.port.on('buffer_click', function (embed) { + // Buffer a tweet + attachOverlay({embed: embed}, function (overlaydata) { + if( !!overlaydata.sent ) { + // Buffer was sent + worker.port.emit("buffer_embed_clear"); + } + }); + }); +}; + + +var addNavBarButton = function() { + + if (FIREFOX_VERSION >= 29) { + + var button = buttons.ActionButton({ + id: BUFFER_BUTTON_ID, + label: 'Buffer ' + FIREFOX_VERSION, + icon: { + '16': './icons/icon-16.png', + '32': './icons/icon-32.png', + '64': './icons/icon-64.png' + }, + onClick: function() { + attachOverlay({ placement: 'toolbar' }); + } + }); + + } else { + + legacy.addNavBarButton(function onButtonClick() { + attachOverlay({ placement: 'toolbar' }); + }); + + } +}; + + +addNavBarButton(); + +// exports.onUnload is called when Firefox starts and when the extension is disabled or uninstalled +exports.onUnload = function(reason) { + if (FIREFOX_VERSION < 29) { + legacy.addNavBarButton(); + } +}; + + +var settingsHandler = function(worker) { + + worker.port.on('buffer_open_settings', function() { + tabs.open('about:addons'); + }); + +}; + +// Injecting scripts breaks Firefox's XML file viewer +var excludeXMLPattern = /.*\.xml/; + +// Embeds +pageMod.PageMod({ + include: '*', + exclude: [excludeXMLPattern], + attachTo: ["existing", "top"], + contentScriptFile: config.plugin.hotkey.scripts, + contentScriptWhen: "ready", + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*', + exclude: [excludeXMLPattern], + attachTo: ["existing", "top"], + contentScriptFile: config.plugin.hoverButton.scripts, + contentScriptWhen: "ready", + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*', + exclude: [excludeXMLPattern], + attachTo: ["existing", "top"], + contentScriptFile: config.plugin.tpccheck.scripts, + contentScriptWhen: "ready", + onAttach: tpcEmbedHandler +}); + +pageMod.PageMod({ + include: '*', + exclude: [excludeXMLPattern], + attachTo: ['existing', 'top'], + contentStyleFile: config.plugin.overlay.styles +}); + +//NOTE - Scraper is currently disabled - MAR 2015 +pageMod.PageMod({ + include: ['*.buffer.com', '*.bufferapp.com'], + contentScriptFile: config.plugin.scraper.scripts, + contentScriptWhen: "ready", + onAttach: function(worker) { + embedHandler(worker, true); + } +}); + +pageMod.PageMod({ + include: '*.twitter.com', + exclude: ['*.tweetdeck.twitter.com'], + contentScriptFile: config.plugin.twitter.scripts, + contentScriptWhen: "ready", + contentStyleFile: config.plugin.twitter.styles, + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*.tweetdeck.twitter.com', + contentScriptFile: config.plugin.tweetdeck.scripts, + contentScriptWhen: "ready", + contentStyleFile: config.plugin.tweetdeck.styles, + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*.pinterest.com', + contentScriptFile: config.plugin.pinterest.scripts, + contentScriptWhen: "ready", + contentStyleFile: config.plugin.pinterest.styles, + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*.facebook.com', + contentScriptFile: config.plugin.facebook.scripts, + contentScriptWhen: "ready", + contentStyleFile: config.plugin.facebook.styles, + attachTo: ['existing', 'top'], //Attach to existing tabs + no frames (top document) + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*.quora.com', + contentScriptFile: config.plugin.quora.scripts, + contentScriptWhen: 'ready', + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: '*.reddit.com', + contentScriptFile: config.plugin.reddit.scripts, + contentScriptWhen: "ready", + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: ['*.ycombinator.com', '*.ycombinator.org'], + contentScriptFile: config.plugin.hn.scripts, + contentScriptWhen: "ready", + onAttach: embedHandler +}); + +pageMod.PageMod({ + include: ['*.buffer.com', '*.bufferapp.com'], + contentScriptFile: config.plugin.bufferapp.scripts, + contentScriptWhen: "ready", + contentScript: 'bufferMarkOurSite("' + config.plugin.version + '")', + contentStyleFile: [ self.data.url('shared/buffer-extension-detection.css') ], + onAttach: settingsHandler +}); diff --git a/firefox/src/lib/prefs.js b/firefox/src/lib/prefs.js new file mode 100644 index 0000000..f630c19 --- /dev/null +++ b/firefox/src/lib/prefs.js @@ -0,0 +1,98 @@ +/* jshint node:true, esnext:true */ +/** + * Reading the user preferences + */ + +var simplePrefs = require('sdk/simple-prefs'); + +/** + * Turns the preferences object into something useful for the content scripts + */ +exports.buildOptions = function () { + + var prefs = [ + { + name: 'twitter', + title: 'Twitter Integration', + type: 'bool', + value: simplePrefs.prefs.twitter + }, + { + name: 'tweetdeck', + title: 'Tweetdeck Integration', + type: 'bool', + value: simplePrefs.prefs.tweetdeck + }, + { + name: 'facebook', + title: 'Facebook Integration', + type: 'bool', + value: simplePrefs.prefs.facebook + }, + { + name: 'quora', + title: 'Quora Integration', + type: 'bool', + value: simplePrefs.prefs.quora + }, + { + name: 'reddit', + title: 'Reddit Integration', + type: 'bool', + value: simplePrefs.prefs.reddit + }, + { + name: 'hacker', + title: 'Hacker News Integration', + type: 'bool', + value: simplePrefs.prefs.hacker + }, + { + name: 'pinterest', + title: 'Pinterest Integration', + type: 'bool', + value: simplePrefs.prefs.pinterest + }, + { + name: 'key-combo', + title: 'Keyboard Shortcut', + type: 'string', + value: simplePrefs.prefs['key-combo'] + }, + { + name: 'key-enable', + title: 'Enable Keyboard Shortcut?', + type: 'bool', + value: simplePrefs.prefs['key-enable'] + }, + { + name: 'image-overlays', + title: 'Buffer "Share Image" Button', + type: 'bool', + value: simplePrefs.prefs['image-overlays'] + } + ]; + var options = {}; + var pref; + + + // Use "false" if false, and use the item name if true. + // This follows how it was original done in the chrome extension + + prefs.forEach(function(pref) { + + if ( pref.name == 'key-combo' ) { + options['buffer.op.key-combo'] = simplePrefs.prefs['key-combo']; + } else { + if ( simplePrefs.prefs[pref.name] === false ) { + options['buffer.op.' + pref.name] = 'false'; + } else { + options['buffer.op.' + pref.name] = pref.name; + } + } + + }); + + return options; + +}; diff --git a/firefox/src/package.json b/firefox/src/package.json new file mode 100644 index 0000000..a964118 --- /dev/null +++ b/firefox/src/package.json @@ -0,0 +1,77 @@ +{ + "description": "Easily add great articles, pictures and videos to your Buffer and we automagically share them for you through the day!", + "license": "MPL 1.1/GPL 2.0/LGPL 2.1", + "author": "Buffer", + "version": "2.13.37", + "title": "Buffer", + "id": "jid1-zUyU7TGKwejAyA@jetpack", + "name": "buffer", + "homepage": "https://buffer.com/guides/firefox", + "icon": "resource://jid1-zUyU7TGKwejAyA-at-jetpack/data/shared/img/Icon.png", + "main": "lib/main.js", + "permissions": { + "private-browsing": true + }, + "preferences": [ + { + "name": "twitter", + "title": "Twitter Integration", + "type": "bool", + "value": true + }, + { + "name": "tweetdeck", + "title": "Tweetdeck Integration", + "type": "bool", + "value": true + }, + { + "name": "facebook", + "title": "Facebook Integration", + "type": "bool", + "value": true + }, + { + "name": "quora", + "title": "Quora Integration", + "type": "bool", + "value": true + }, + { + "name": "reddit", + "title": "Reddit Integration", + "type": "bool", + "value": true + }, + { + "name": "hacker", + "title": "Hacker News Integration", + "type": "bool", + "value": true + }, + { + "name": "pinterest", + "title": "Pinterest Integration", + "type": "bool", + "value": true + }, + { + "name": "key-combo", + "title": "Keyboard Shortcut", + "type": "string", + "value": "alt+b" + }, + { + "name": "key-enable", + "title": "Enable Keyboard Shortcut?", + "type": "bool", + "value": true + }, + { + "name": "image-overlays", + "title": "Buffer \"Share Image\" Button", + "type": "bool", + "value": true + } + ] +} \ No newline at end of file diff --git a/firefox/test/test-main.js b/firefox/src/test/test-main.js similarity index 65% rename from firefox/test/test-main.js rename to firefox/src/test/test-main.js index 09826e0..a6866f3 100644 --- a/firefox/test/test-main.js +++ b/firefox/src/test/test-main.js @@ -1,5 +1,5 @@ -const main = require("main"); +const main = require("../lib/main"); exports.test_test_run = function(test) { test.pass("Unit test running!"); -}; \ No newline at end of file +}; diff --git a/releases/buffer-2.11.2-addon-edition.xpi b/releases/buffer-2.11.2-addon-edition.xpi new file mode 100644 index 0000000..d91ab4e Binary files /dev/null and b/releases/buffer-2.11.2-addon-edition.xpi differ diff --git a/releases/buffer-2.11.2.xpi b/releases/buffer-2.11.2.xpi new file mode 100644 index 0000000..47c22aa Binary files /dev/null and b/releases/buffer-2.11.2.xpi differ diff --git a/releases/buffer-2.12.0-addon-edition.xpi b/releases/buffer-2.12.0-addon-edition.xpi new file mode 100644 index 0000000..e201c4a Binary files /dev/null and b/releases/buffer-2.12.0-addon-edition.xpi differ diff --git a/releases/buffer-2.12.0.xpi b/releases/buffer-2.12.0.xpi new file mode 100644 index 0000000..94743cf Binary files /dev/null and b/releases/buffer-2.12.0.xpi differ diff --git a/releases/buffer-2.12.1-addon-edition.xpi b/releases/buffer-2.12.1-addon-edition.xpi new file mode 100644 index 0000000..5c23fa9 Binary files /dev/null and b/releases/buffer-2.12.1-addon-edition.xpi differ diff --git a/releases/buffer-2.12.1.xpi b/releases/buffer-2.12.1.xpi new file mode 100644 index 0000000..9504a8e Binary files /dev/null and b/releases/buffer-2.12.1.xpi differ diff --git a/releases/buffer-2.12.2-addon-edition.xpi b/releases/buffer-2.12.2-addon-edition.xpi new file mode 100644 index 0000000..67b2807 Binary files /dev/null and b/releases/buffer-2.12.2-addon-edition.xpi differ diff --git a/releases/buffer-2.12.2.xpi b/releases/buffer-2.12.2.xpi new file mode 100644 index 0000000..5debcd7 Binary files /dev/null and b/releases/buffer-2.12.2.xpi differ diff --git a/releases/buffer-2.12.3-addon-edition.xpi b/releases/buffer-2.12.3-addon-edition.xpi new file mode 100644 index 0000000..7f60aeb Binary files /dev/null and b/releases/buffer-2.12.3-addon-edition.xpi differ diff --git a/releases/buffer-2.12.3.xpi b/releases/buffer-2.12.3.xpi new file mode 100644 index 0000000..ddcfc1f Binary files /dev/null and b/releases/buffer-2.12.3.xpi differ diff --git a/releases/buffer-2.12.5-addon-edition.xpi b/releases/buffer-2.12.5-addon-edition.xpi new file mode 100644 index 0000000..29cfd20 Binary files /dev/null and b/releases/buffer-2.12.5-addon-edition.xpi differ diff --git a/releases/buffer-2.12.5.xpi b/releases/buffer-2.12.5.xpi new file mode 100644 index 0000000..cae061a Binary files /dev/null and b/releases/buffer-2.12.5.xpi differ diff --git a/releases/buffer-2.12.6-addon-edition.xpi b/releases/buffer-2.12.6-addon-edition.xpi new file mode 100644 index 0000000..1126843 Binary files /dev/null and b/releases/buffer-2.12.6-addon-edition.xpi differ diff --git a/releases/buffer-2.12.7-addon-edition.xpi b/releases/buffer-2.12.7-addon-edition.xpi new file mode 100644 index 0000000..795cb44 Binary files /dev/null and b/releases/buffer-2.12.7-addon-edition.xpi differ diff --git a/releases/buffer-2.12.7.xpi b/releases/buffer-2.12.7.xpi new file mode 100644 index 0000000..fede173 Binary files /dev/null and b/releases/buffer-2.12.7.xpi differ diff --git a/releases/buffer-2.12.8-addon-edition.xpi b/releases/buffer-2.12.8-addon-edition.xpi new file mode 100644 index 0000000..52ee4ef Binary files /dev/null and b/releases/buffer-2.12.8-addon-edition.xpi differ diff --git a/releases/buffer-2.12.8.xpi b/releases/buffer-2.12.8.xpi new file mode 100644 index 0000000..e6e8cae Binary files /dev/null and b/releases/buffer-2.12.8.xpi differ diff --git a/releases/buffer-2.12.9-addon-edition.xpi b/releases/buffer-2.12.9-addon-edition.xpi new file mode 100644 index 0000000..d38da15 Binary files /dev/null and b/releases/buffer-2.12.9-addon-edition.xpi differ diff --git a/releases/buffer-2.12.9.xpi b/releases/buffer-2.12.9.xpi new file mode 100644 index 0000000..25bee50 Binary files /dev/null and b/releases/buffer-2.12.9.xpi differ diff --git a/releases/buffer-2.13.1-addon-edition.xpi b/releases/buffer-2.13.1-addon-edition.xpi new file mode 100644 index 0000000..2c469ae Binary files /dev/null and b/releases/buffer-2.13.1-addon-edition.xpi differ diff --git a/releases/buffer-2.13.1.xpi b/releases/buffer-2.13.1.xpi new file mode 100644 index 0000000..1cdaac0 Binary files /dev/null and b/releases/buffer-2.13.1.xpi differ diff --git a/releases/buffer-2.13.10-addon-edition.xpi b/releases/buffer-2.13.10-addon-edition.xpi new file mode 100644 index 0000000..2c1ba82 Binary files /dev/null and b/releases/buffer-2.13.10-addon-edition.xpi differ diff --git a/releases/buffer-2.13.10.xpi b/releases/buffer-2.13.10.xpi new file mode 100644 index 0000000..024735b Binary files /dev/null and b/releases/buffer-2.13.10.xpi differ diff --git a/releases/buffer-2.13.11-addon-edition.xpi b/releases/buffer-2.13.11-addon-edition.xpi new file mode 100644 index 0000000..d872ed8 Binary files /dev/null and b/releases/buffer-2.13.11-addon-edition.xpi differ diff --git a/releases/buffer-2.13.11.xpi b/releases/buffer-2.13.11.xpi new file mode 100644 index 0000000..5635a41 Binary files /dev/null and b/releases/buffer-2.13.11.xpi differ diff --git a/releases/buffer-2.13.12-addon-edition.xpi b/releases/buffer-2.13.12-addon-edition.xpi new file mode 100644 index 0000000..97a9a37 Binary files /dev/null and b/releases/buffer-2.13.12-addon-edition.xpi differ diff --git a/releases/buffer-2.13.12.xpi b/releases/buffer-2.13.12.xpi new file mode 100644 index 0000000..4bb91ac Binary files /dev/null and b/releases/buffer-2.13.12.xpi differ diff --git a/releases/buffer-2.13.13-addon-edition.xpi b/releases/buffer-2.13.13-addon-edition.xpi new file mode 100644 index 0000000..22414c6 Binary files /dev/null and b/releases/buffer-2.13.13-addon-edition.xpi differ diff --git a/releases/buffer-2.13.13.xpi b/releases/buffer-2.13.13.xpi new file mode 100644 index 0000000..b7b73de Binary files /dev/null and b/releases/buffer-2.13.13.xpi differ diff --git a/releases/buffer-2.13.15-addon-edition.xpi b/releases/buffer-2.13.15-addon-edition.xpi new file mode 100644 index 0000000..f59e587 Binary files /dev/null and b/releases/buffer-2.13.15-addon-edition.xpi differ diff --git a/releases/buffer-2.13.15.xpi b/releases/buffer-2.13.15.xpi new file mode 100644 index 0000000..d1013f8 Binary files /dev/null and b/releases/buffer-2.13.15.xpi differ diff --git a/releases/buffer-2.13.17-addon-edition.xpi b/releases/buffer-2.13.17-addon-edition.xpi new file mode 100644 index 0000000..6adf31e Binary files /dev/null and b/releases/buffer-2.13.17-addon-edition.xpi differ diff --git a/releases/buffer-2.13.17.xpi b/releases/buffer-2.13.17.xpi new file mode 100644 index 0000000..f5ce8f9 Binary files /dev/null and b/releases/buffer-2.13.17.xpi differ diff --git a/releases/buffer-2.13.18-addon-edition.xpi b/releases/buffer-2.13.18-addon-edition.xpi new file mode 100644 index 0000000..5ed99b2 Binary files /dev/null and b/releases/buffer-2.13.18-addon-edition.xpi differ diff --git a/releases/buffer-2.13.18.xpi b/releases/buffer-2.13.18.xpi new file mode 100644 index 0000000..32040cc Binary files /dev/null and b/releases/buffer-2.13.18.xpi differ diff --git a/releases/buffer-2.13.2-addon-edition.xpi b/releases/buffer-2.13.2-addon-edition.xpi new file mode 100644 index 0000000..1230c7b Binary files /dev/null and b/releases/buffer-2.13.2-addon-edition.xpi differ diff --git a/releases/buffer-2.13.2.xpi b/releases/buffer-2.13.2.xpi new file mode 100644 index 0000000..27d0e6a Binary files /dev/null and b/releases/buffer-2.13.2.xpi differ diff --git a/releases/buffer-2.13.20-addon-edition.xpi b/releases/buffer-2.13.20-addon-edition.xpi new file mode 100644 index 0000000..11adb62 Binary files /dev/null and b/releases/buffer-2.13.20-addon-edition.xpi differ diff --git a/releases/buffer-2.13.20.xpi b/releases/buffer-2.13.20.xpi new file mode 100644 index 0000000..470613c Binary files /dev/null and b/releases/buffer-2.13.20.xpi differ diff --git a/releases/buffer-2.13.22-addon-edition.xpi b/releases/buffer-2.13.22-addon-edition.xpi new file mode 100644 index 0000000..d1e9a78 Binary files /dev/null and b/releases/buffer-2.13.22-addon-edition.xpi differ diff --git a/releases/buffer-2.13.22.xpi b/releases/buffer-2.13.22.xpi new file mode 100644 index 0000000..27375fa Binary files /dev/null and b/releases/buffer-2.13.22.xpi differ diff --git a/releases/buffer-2.13.23-addon-edition.xpi b/releases/buffer-2.13.23-addon-edition.xpi new file mode 100644 index 0000000..223431f Binary files /dev/null and b/releases/buffer-2.13.23-addon-edition.xpi differ diff --git a/releases/buffer-2.13.23.xpi b/releases/buffer-2.13.23.xpi new file mode 100644 index 0000000..aec9560 Binary files /dev/null and b/releases/buffer-2.13.23.xpi differ diff --git a/releases/buffer-2.13.24-addon-edition.xpi b/releases/buffer-2.13.24-addon-edition.xpi new file mode 100644 index 0000000..4514c81 Binary files /dev/null and b/releases/buffer-2.13.24-addon-edition.xpi differ diff --git a/releases/buffer-2.13.24.xpi b/releases/buffer-2.13.24.xpi new file mode 100644 index 0000000..6af5b31 Binary files /dev/null and b/releases/buffer-2.13.24.xpi differ diff --git a/releases/buffer-2.13.25-addon-edition.xpi b/releases/buffer-2.13.25-addon-edition.xpi new file mode 100644 index 0000000..d02e8d0 Binary files /dev/null and b/releases/buffer-2.13.25-addon-edition.xpi differ diff --git a/releases/buffer-2.13.25.xpi b/releases/buffer-2.13.25.xpi new file mode 100644 index 0000000..91ad6ee Binary files /dev/null and b/releases/buffer-2.13.25.xpi differ diff --git a/releases/buffer-2.13.28-addon-edition.xpi b/releases/buffer-2.13.28-addon-edition.xpi new file mode 100644 index 0000000..846fae3 Binary files /dev/null and b/releases/buffer-2.13.28-addon-edition.xpi differ diff --git a/releases/buffer-2.13.28.xpi b/releases/buffer-2.13.28.xpi new file mode 100644 index 0000000..faf0c07 Binary files /dev/null and b/releases/buffer-2.13.28.xpi differ diff --git a/releases/buffer-2.13.3-addon-edition.xpi b/releases/buffer-2.13.3-addon-edition.xpi new file mode 100644 index 0000000..f68791e Binary files /dev/null and b/releases/buffer-2.13.3-addon-edition.xpi differ diff --git a/releases/buffer-2.13.3.xpi b/releases/buffer-2.13.3.xpi new file mode 100644 index 0000000..eac596e Binary files /dev/null and b/releases/buffer-2.13.3.xpi differ diff --git a/releases/buffer-2.13.37-addon-edition.xpi b/releases/buffer-2.13.37-addon-edition.xpi new file mode 100644 index 0000000..4d598b0 Binary files /dev/null and b/releases/buffer-2.13.37-addon-edition.xpi differ diff --git a/releases/buffer-2.13.37.xpi b/releases/buffer-2.13.37.xpi new file mode 100644 index 0000000..b3c5bdf Binary files /dev/null and b/releases/buffer-2.13.37.xpi differ diff --git a/releases/buffer-2.13.5-addon-edition.xpi b/releases/buffer-2.13.5-addon-edition.xpi new file mode 100644 index 0000000..bea1ebc Binary files /dev/null and b/releases/buffer-2.13.5-addon-edition.xpi differ diff --git a/releases/buffer-2.13.5.xpi b/releases/buffer-2.13.5.xpi new file mode 100644 index 0000000..9c5d521 Binary files /dev/null and b/releases/buffer-2.13.5.xpi differ diff --git a/releases/buffer-2.13.7-addon-edition.xpi b/releases/buffer-2.13.7-addon-edition.xpi new file mode 100644 index 0000000..c8c21ba Binary files /dev/null and b/releases/buffer-2.13.7-addon-edition.xpi differ diff --git a/releases/buffer-2.13.7.xpi b/releases/buffer-2.13.7.xpi new file mode 100644 index 0000000..3c98883 Binary files /dev/null and b/releases/buffer-2.13.7.xpi differ diff --git a/releases/buffer-2.13.9-addon-edition.xpi b/releases/buffer-2.13.9-addon-edition.xpi new file mode 100644 index 0000000..baa7bcf Binary files /dev/null and b/releases/buffer-2.13.9-addon-edition.xpi differ diff --git a/releases/buffer-2.13.9.xpi b/releases/buffer-2.13.9.xpi new file mode 100644 index 0000000..2d41087 Binary files /dev/null and b/releases/buffer-2.13.9.xpi differ