Permalink
Browse files

Opera Extension; initial commit. Beta stage!

Simplified extension: Global.js is gone; Livereload.js as part of the
package is a no-go; Using the localhost fallback permanently for now;
All of the web socket functionality is skipped, as it is done from
livereload.js already
  • Loading branch information...
1 parent 35a90b1 commit 3256ac774287a41b9970a478ec86e541cf727f7e @gavro gavro committed Mar 31, 2012
View
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" id="LiveReload2.0.1" defaultlocale="en">
+ <name>LiveReload 2.0.1 (Beta)</name>
+ <description>LiveReload refreshes a web page when files change. Please make sure you enable Websockets and LiveReload is running.
+[Beta note] This extension is not as sophisticated as the Chrome/Firefox version; keep your bug reports coming and it might get there.</description>
+ <author href="http://gavro.nl" email="gabrijel@gavro.nl">Gabrijel Gavranović</author>
+ <icon src="images/livereload_64.png"/>
+ <access origin="http://localhost"/>
+ <access origin="http://localhost:35729"/>
+ <access origin="http://livereload.com" subdomains="true"/>
+</widget>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
@@ -0,0 +1,138 @@
+/***
+ * Author: Gabrijel Gavranović // gavro.nl
+ * CustomEvent & LiveReload objects/prototype function taken (and partially adapted) from:
+ * LiveReload Chrome & Firefox extentions, LiveReload.com & Nikita Vasilyev.
+ * See: http://help.livereload.com/kb/general-use/browser-extensions
+ ***/
+
+var tabId, CustomEvents, ExtVersion, LiveReloadInjected, liveReloadInjected;
+var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+CustomEvents = {
+ bind: function(element, eventName, handler) {
+ if (element.addEventListener) {
+ return element.addEventListener(eventName, handler, false);
+ } else if (element.attachEvent) {
+ element[eventName] = 1;
+ return element.attachEvent('onpropertychange', function(event) {
+ if (event.propertyName === eventName) {
+ return handler();
+ }
+ });
+ } else {
+ throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement");
+ }
+ },
+ fire: function(element, eventName) {
+ var document, event;
+ document = element instanceof window.HTMLDocument ? element : element.ownerDocument;
+ if (element.addEventListener) {
+ event = document.createEvent('HTMLEvents');
+ event.initEvent(eventName, true, true);
+ return document.dispatchEvent(event);
+ } else if (element.attachEvent) {
+ if (element[eventName]) {
+ return element[eventName]++;
+ }
+ } else {
+ throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
+ }
+ }
+};
+ExtVersion = '2.0.1';
+LiveReloadInjected = (function() {
+ function LiveReloadInjected(tabId, document, extName) {
+ this.tabId = tabId;
+ this.document = document;
+ this.extName = extName;
+ };
+ LiveReloadInjected.prototype.doDisable = function() {
+ var element = this.document.getElementById('lr-script');
+ if (element) {
+ CustomEvents.fire(this.document, 'LiveReloadShutDown');
+ if (element.parentNode) {
+ element.parentNode.removeChild(element);
+ }
+ }
+ return;
+ };
+ LiveReloadInjected.prototype.doEnable = function(_arg) {
+ var element, scriptURI, url, useFallback;
+ useFallback = _arg.useFallback, scriptURI = _arg.scriptURI;
+ if (useFallback) {
+ url = "" + scriptURI + "?ext=" + this.extName + "&extver=" + ExtVersion + "&host=localhost";
+ console.log("Loading LiveReload.js bundled with the browser extension...");
+ } else {
+ url = "http://localhost:35729/livereload.js?ext=" + this.extName + "&extver=" + ExtVersion;
+ console.log("Loading LiveReload.js from " + (url.replace(/\?.*$/, '')) + "...");
+ }
+ element = this.document.createElement('script');
+ element.src = url;
+ element.id = "lr-script";
+ return this.document.getElementsByTagName('head')[0].appendChild(element);
+ };
+ LiveReloadInjected.prototype.disable = function() {
+ return this.doDisable(__bind(function() {
+ return this.send('status', {
+ enabled: false,
+ active: false
+ });
+ }, this));
+ };
+ LiveReloadInjected.prototype.enable = function(options) {
+ return this.doDisable(__bind(function() {
+ this.doEnable(options);
+ return this.send('status', {
+ enabled: true
+ });
+ }, this));
+ };
+ return LiveReloadInjected;
+})();
+
+
+
+window.addEventListener('DOMContentLoaded', function(event) {
+ /***
+ * We need a sort of handshake communication: need to check and/or set current tab ID for things to work.
+ * Opera currently does not support an "onReload" function and neither is it possible to get the current tab id
+ * from the injected JS. From background.js it is not possible to any useful information (e.g. the tab ID) from
+ * the connecting tab if it is not the focused tab (event object has limited data and tab/windows extension
+ * functionality is far from complete)!
+ * LiveReload reloads the entire tab if the page src (html) is edited, so background functionality is really needed.
+ *
+ * Current workflow: (work-around), with added latency...):
+ * > [inject.js] send message on DOM ready with seesiondata: tabId (instead of onconnect @ background.js)
+ * > [background.js] is tabId null or set? If set: resume state from own stored data. Null? New setup.
+ ***/
+ tabId = window.sessionStorage.getItem('tabId');
+ opera.extension.postMessage({action: 'initConnection', tabid: tabId});
+
+ opera.extension.onmessage = function(event){
+ if(tabId == event.data.tabid || event.data.action.indexOf('Connection') > -1) {
+ switch(event.data.action) {
+ case 'setupConnection':
+ //store your own ID, used for further communications (broadcastMessage is multicast only... :/)
+ tabId = event.data.tabid;
+ window.sessionStorage.setItem('tabId', event.data.tabid);
+ liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
+ break;
+ case 'resumeConnection':
+ if(event.data.state === 'active') {
+ liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
+ liveReloadInjected.doEnable({useFallback: false, scriptURI: ''});
+ } else {
+ liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
+ }
+ break;
+ case 'enable':
+ liveReloadInjected.doEnable({useFallback: false, scriptURI: ''});
+ //can't call internal scripts (getFile function from extension does not exsist) @ Opera Extension
+ //(or I just don't know how...)
+ break;
+ case 'disable':
+ liveReloadInjected.doDisable();
+ break;
+ }
+ }
+ }
+}, false);
View
@@ -0,0 +1,9 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <script src="scripts/o-min.js" type="text/javascript"></script>
+ <script src="scripts/background.js" type="text/javascript"></script>
+ </head>
+ <body>
+ </body>
+</html>
Binary file not shown.
@@ -0,0 +1,120 @@
+/***
+ * Author: Gabrijel Gavranović // gavro.nl
+ * CustomEvent & LiveReload objects/prototype function taken (and partially adapted) from:
+ * LiveReload Chrome & Firefox extentions, LiveReload.com & Nikita Vasilyev.
+ * See: http://help.livereload.com/kb/general-use/browser-extensions
+ ***/
+
+//global vars/objects
+/***
+ * lrdata structure: tabID, status --> We should keep track of closed tab and remove them but can't get the ID
+ * of the closed tabs! So let the object fill up, better a larger object instead of a periodical check of
+ * object agains all open tabs with extension.tabs.getAll()....
+ ***/
+var lrdata = {};
+
+window.addEventListener("load", setupConnection, false);
+
+function setupConnection() {
+ var UIItemProperties = {
+ disabled: true,
+ title: "Please reload the page to be able to enable the LiveReload plugin.",
+ icon: "images/IconDisabled.png",
+ onclick: function(){
+ toggleLiveReload(true);
+ }
+ };
+
+ toggleButton = opera.contexts.toolbar.createItem(UIItemProperties);
+ opera.contexts.toolbar.addItem(toggleButton);
+
+ /***
+ * We need a sort of handshake communication: need to check and/or set current tab ID for things to work.
+ * Opera currently does not support an "onReload" function and neither is it possible to get the current tab id
+ * from the injected JS. From background.js it is not possible to any useful information (e.g. the tab ID) from
+ * the connecting tab if it is not the focused tab (event object has limited data and tab/windows extension
+ * functionality is far from complete)!
+ * LiveReload reloads the entire tab if the page src (html) is edited, so background functionality is really needed.
+ *
+ * Current workflow: (work-around), with added latency...):
+ * > [inject.js] send message on DOM ready with seesiondata: tabId (instead of onconnect @ background.js)
+ * > [background.js] is tabId null or set? If set: resume state from own stored data. Null? New setup.
+ ***/
+
+ /*opera.extension.onconnect = function(event) {
+ var tab = opera.extension.tabs.getFocused();
+ if(tab) {
+ if(o.has(lrdata, tab.id) && lrdata[tab.id].state === 'active') {
+ event.source.postMessage({action: 'resumeConnection', tabid: tab.id});
+ } else {
+ o.add(lrdata, tab.id, {state: 'inactive', timeStamp: event.timeStamp});
+ event.source.postMessage({action: 'setupConnection', tabid: tab.id});
+
+ toggleButton.disabled = false;
+ toggleButton.title = 'Enable LiveReload';
+ }
+ }
+ }*/
+
+ opera.extension.onmessage = function(event) {
+ switch(event.data.action) {
+ case "initConnection":
+ if(event.data.tabid === null) {
+ var tab = opera.extension.tabs.getFocused();
+ o.add(lrdata, tab.id, {state: 'inactive'});
+ event.source.postMessage({action: 'setupConnection', tabid: tab.id});
+ toggleButton.disabled = false;
+ toggleButton.title = 'Enable LiveReload';
+ } else if(o.has(lrdata, event.data.tabid) && lrdata[event.data.tabid].state === 'active'){
+ event.source.postMessage({action: 'resumeConnection', tabid: event.data.tabid, state: 'active'});
+ } else {
+ //event.source.postMessage({action: 'resumeConnection', tabid: event.data.tabid, state: 'inactive'});
+ event.source.postMessage({action: 'setupConnection', tabid: event.data.tabid});
+ }
+ break;
+ }
+ }
+
+ opera.extension.tabs.onfocus = function(event) {
+ var tab = opera.extension.tabs.getFocused();
+ if(tab) {
+ if(!o.has(lrdata, tab.id)) {
+ toggleButton.disabled = true;
+ toggleButton.title = 'Please reload or even reopen the tab to be able to enable the LiveReload plugin.';
+ toggleButton.icon = 'images/IconDisabled.png';
+ } else {
+ toggleButton.disabled = false;
+ toggleLiveReload(event, false);
+ }
+ }
+ }
+}
+
+
+function toggleLiveReload(change) {
+ var tab = opera.extension.tabs.getFocused();
+ if(tab) {
+ if(o.has(lrdata, tab.id)) {
+ switch(lrdata[tab.id].state) {
+ case 'inactive':
+ if(change === true) {
+ opera.extension.broadcastMessage({action: 'enable', tabid: tab.id});
+ lrdata[tab.id].state = 'active';
+ toggleButton.icon = 'images/IconActive.png';
+ } else {
+ toggleButton.icon = 'images/IconDisabled.png';
+ }
+ break;
+ case 'active':
+ if(change === true){
+ opera.extension.broadcastMessage({action: 'disable', tabid: tab.id});
+ lrdata[tab.id].state = 'inactive';
+ toggleButton.icon = 'images/IconDisabled.png';
+ } else {
+ toggleButton.icon = 'images/IconActive.png';
+ }
+ break;
+ }
+ }
+ }
+}
@@ -0,0 +1,4 @@
+//https://github.com/vladocar/o---JS-Library-for-Object-Manipulation
+(function(e){var d={add:function(a,b,c){return a[b]=c},remove:function(a,b){return delete a[b]},key:function(a,b){return a[b]},extend:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])},cloneAll:function(){for(var a={},b=arguments.length;b--;){var c=arguments[b],d;for(d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}return a},values:function(a){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(a[c]);return b},keys:Object.keys||function(a){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(c);return b},
+len:function(a){return this.keys(a).length},has:function(a,b){return a.hasOwnProperty(b)},isEmpty:function(a){return!this.len(a)},type:function(a,b){return b?Object.prototype.toString.call(a[b]):Object.prototype.toString.call(a)},is:function(a,b){return d.type(a)==="[object "+b+"]"},isArray:function(a){return d.is(a,"Array")},isObject:function(a){return d.is(a,"Object")},isRegExp:function(a){return d.is(a,"RegExp")},isFunction:function(a){return d.is(a,"Function")},isNumber:function(a){return d.is(a,
+"Number")},isString:function(a){return d.is(a,"String")},isBoolean:function(a){return d.is(a,"Boolean")},isNull:function(a){return d.is(a,"Null")},isUndefined:function(a){return d.is(a,"Undefined")},toJSON:function(a){return JSON.stringify(a)},toObject:function(a){return JSON.parse(a)},setStorage:function(a,b){return localStorage.setItem(a,JSON.stringify(b))},getStorage:function(a){return JSON.parse(localStorage.getItem(a))},removeStorage:function(a){return localStorage.removeItem(a)}};e.o=d})(window);

0 comments on commit 3256ac7

Please sign in to comment.