├── .gitignore
├── Chrome
└── LiveReload
│ ├── IconActive.png
│ ├── IconActive@2x.png
│ ├── IconDisabled.png
│ ├── IconDisabled@2x.png
│ ├── IconEnabled.png
│ ├── IconEnabled@2x.png
│ ├── IconUnavailable.png
│ ├── IconUnavailable@2x.png
│ ├── devtools.html
│ ├── icon128.png
│ ├── icon48.png
│ └── manifest.json
├── Firefox
├── chrome.manifest
├── content
│ └── browser.xul
├── defaults
│ └── preferences
│ │ └── defaults.js
├── install.rdf
└── skin
│ ├── IconActive.png
│ ├── IconDisabled.png
│ ├── IconEnabled.png
│ ├── IconUnavailable.png
│ └── icon_32.png
├── Gruntfile.js
├── LiveReload.safariextension
├── Icon-32.png
├── Icon-48.png
├── IconActive.png
├── IconActive@2x.png
├── IconDisabled.png
├── IconDisabled@2x.png
├── IconEnabled.png
├── IconEnabled@2x.png
├── IconUnavailable.png
├── IconUnavailable@2x.png
├── Info.plist
├── Settings.plist
└── global.html
├── Opera
├── config.xml
├── images
│ ├── IconActive.png
│ ├── IconDisabled.png
│ ├── IconEnabled.png
│ ├── IconUnavailable.png
│ └── livereload_64.png
├── includes
│ ├── .DS_Store
│ └── injected.js
├── index.html
└── scripts
│ ├── .DS_Store
│ ├── background.js
│ └── o-min.js
├── README.md
├── Rakefile
├── dist
└── .keepme
├── package.json
├── src
├── chrome
│ ├── devtools.coffee
│ ├── global.coffee
│ └── injected.coffee
├── common
│ ├── devtools.coffee
│ ├── global.coffee
│ ├── injected.coffee
│ └── version.coffee
├── firefox
│ └── firefox.coffee
├── livereload-js.coffee
└── safari
│ ├── global.coffee
│ └── injected.coffee
└── update
├── LiveReload-Firefox-update.rdf
└── LiveReload-Safari-update.plist
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | LiveReload.safariextension/*.js
3 | Chrome/LiveReload/*.js
4 | Firefox/content/*.js
5 | lib/*.js
6 | lib/*/*.js
7 | /dist
8 | /update/McCoy
9 | /Chrome/*.pem
10 |
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconActive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconActive.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconActive@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconActive@2x.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconDisabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconDisabled.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconDisabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconDisabled@2x.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconEnabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconEnabled.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconEnabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconEnabled@2x.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconUnavailable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconUnavailable.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/IconUnavailable@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/IconUnavailable@2x.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Chrome/LiveReload/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/icon128.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Chrome/LiveReload/icon48.png
--------------------------------------------------------------------------------
/Chrome/LiveReload/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "LiveReload",
4 | "version": "2.1.0",
5 | "background": {
6 | "scripts": [
7 | "global.js"
8 | ]
9 | },
10 | "content_scripts": [
11 | {
12 | "matches": [""],
13 | "js": ["injected.js"]
14 | }
15 | ],
16 | "web_accessible_resources": [
17 | "livereload.js"
18 | ],
19 | "permissions": [
20 | "tabs",
21 | ""
22 | ],
23 | "icons": { "48": "icon48.png",
24 | "128": "icon128.png" },
25 | "browser_action": {
26 | "default_title": "Enable LiveReload",
27 | "default_icon": "IconDisabled.png"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Firefox/chrome.manifest:
--------------------------------------------------------------------------------
1 | content livereload content/ contentaccessible=yes
2 | skin livereload classic/1.0 skin/
3 |
4 | overlay chrome://browser/content/browser.xul chrome://livereload/content/browser.xul
5 |
--------------------------------------------------------------------------------
/Firefox/content/browser.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Firefox/defaults/preferences/defaults.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/defaults/preferences/defaults.js
--------------------------------------------------------------------------------
/Firefox/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
5 |
15 | Nikita Vasilyev
16 | Stefan Thomas
17 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/Firefox/skin/IconActive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/skin/IconActive.png
--------------------------------------------------------------------------------
/Firefox/skin/IconDisabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/skin/IconDisabled.png
--------------------------------------------------------------------------------
/Firefox/skin/IconEnabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/skin/IconEnabled.png
--------------------------------------------------------------------------------
/Firefox/skin/IconUnavailable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/skin/IconUnavailable.png
--------------------------------------------------------------------------------
/Firefox/skin/icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Firefox/skin/icon_32.png
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 |
6 | browserify: {
7 | options: {
8 | transform: ['coffeeify'],
9 | browserifyOptions: {
10 | extensions: ['.coffee']
11 | }
12 | },
13 | safari: {
14 | files: {
15 | 'LiveReload.safariextension/global.js': ['src/safari/global.coffee'],
16 | 'LiveReload.safariextension/injected.js': ['src/safari/injected.coffee'],
17 | 'LiveReload.safariextension/livereload.js': ['src/livereload-js.coffee']
18 | }
19 | },
20 | chrome: {
21 | files: {
22 | 'Chrome/LiveReload/global.js': ['src/chrome/global.coffee'],
23 | 'Chrome/LiveReload/injected.js': ['src/chrome/injected.coffee'],
24 | 'Chrome/LiveReload/devtools.js': ['src/chrome/devtools.coffee'],
25 | 'Chrome/LiveReload/livereload.js': ['src/livereload-js.coffee']
26 | }
27 | },
28 | firefox: {
29 | files: {
30 | 'Firefox/content/firefox.js': ['src/firefox/firefox.coffee'],
31 | 'Firefox/content/livereload.js': ['src/livereload-js.coffee']
32 | }
33 | }
34 | },
35 |
36 | compress: {
37 | options: {
38 | pretty: true,
39 | level: 9,
40 | },
41 | chrome: {
42 | options: {
43 | archive: 'dist/<%= pkg.version %>/LiveReload-<%= pkg.version %>-ChromeWebStore.zip'
44 | },
45 | files: [
46 | { expand: true, cwd: 'Chrome/LiveReload', src: ['**.{json,js,html,png}'], dest: 'LiveReload/' }
47 | ]
48 | },
49 | firefox: {
50 | options: {
51 | archive: 'dist/<%= pkg.version %>/LiveReload-<%= pkg.version %>.xpi',
52 | mode: 'zip'
53 | },
54 | files: [
55 | { expand: true, cwd: 'Firefox', src: ['**/*.{js,xul,manifest,rdf,png}'], dest: '/' }
56 | ]
57 | }
58 | }
59 | });
60 |
61 | grunt.loadNpmTasks('grunt-contrib-coffee');
62 | grunt.loadNpmTasks('grunt-browserify');
63 | grunt.loadNpmTasks('grunt-contrib-compress');
64 |
65 | grunt.registerTask('build', ['browserify']);
66 | grunt.registerTask('default', ['build']);
67 |
68 | grunt.registerTask('chrome', ['browserify:chrome', 'compress:chrome']);
69 | grunt.registerTask('firefox', ['browserify:firefox', 'compress:firefox']);
70 | grunt.registerTask('all', ['chrome', 'firefox']);
71 |
72 | };
73 |
--------------------------------------------------------------------------------
/LiveReload.safariextension/Icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/Icon-32.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/Icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/Icon-48.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconActive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconActive.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconActive@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconActive@2x.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconDisabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconDisabled.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconDisabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconDisabled@2x.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconEnabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconEnabled.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconEnabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconEnabled@2x.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconUnavailable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconUnavailable.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/IconUnavailable@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/LiveReload.safariextension/IconUnavailable@2x.png
--------------------------------------------------------------------------------
/LiveReload.safariextension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Author
6 | Andrey Tarantsov
7 | Builder Version
8 | 10600.4.10.7
9 | CFBundleDisplayName
10 | LiveReload
11 | CFBundleIdentifier
12 | com.livereload.extensions.SafariLiveReload
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleShortVersionString
16 | 2.1.0
17 | CFBundleVersion
18 | 2.1.0
19 | Chrome
20 |
21 | Global Page
22 | global.html
23 | Toolbar Items
24 |
25 |
26 | Command
27 | toggle
28 | Identifier
29 | toggleToolbar
30 | Image
31 | IconDisabled.png
32 | Label
33 | LiveReload
34 | Palette Label
35 | LiveReload
36 | Tool Tip
37 | Enable LiveReload on this tab
38 |
39 |
40 |
41 | Content
42 |
43 | Scripts
44 |
45 | End
46 |
47 | injected.js
48 |
49 |
50 |
51 | Description
52 | Browser extension for LiveReload app
53 | DeveloperIdentifier
54 | D963M2VVCH
55 | ExtensionInfoDictionaryVersion
56 | 1.0
57 | Permissions
58 |
59 | Website Access
60 |
61 | Include Secure Pages
62 |
63 | Level
64 | All
65 |
66 |
67 | Update Manifest URL
68 | http://download.livereload.com/LiveReload-Safari-update.plist
69 | Website
70 | http://livereload.com/
71 |
72 |
73 |
--------------------------------------------------------------------------------
/LiveReload.safariextension/Settings.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LiveReload.safariextension/global.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Opera/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | LiveReload 2.0.1 (Beta)
4 | LiveReload refreshes a web page when files change. Please make sure you enable Websockets and LiveReload is running.
5 | [Beta note] This extension is not as sophisticated as the Chrome/Firefox version; keep your bug reports coming and it might get there.
6 | Gabrijel Gavranović
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Opera/images/IconActive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/images/IconActive.png
--------------------------------------------------------------------------------
/Opera/images/IconDisabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/images/IconDisabled.png
--------------------------------------------------------------------------------
/Opera/images/IconEnabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/images/IconEnabled.png
--------------------------------------------------------------------------------
/Opera/images/IconUnavailable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/images/IconUnavailable.png
--------------------------------------------------------------------------------
/Opera/images/livereload_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/images/livereload_64.png
--------------------------------------------------------------------------------
/Opera/includes/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/includes/.DS_Store
--------------------------------------------------------------------------------
/Opera/includes/injected.js:
--------------------------------------------------------------------------------
1 | /***
2 | * Author: Gabrijel Gavranović // gavro.nl
3 | * CustomEvent & LiveReload objects/prototype function taken (and partially adapted) from:
4 | * LiveReload Chrome & Firefox extentions, LiveReload.com & Nikita Vasilyev.
5 | * See: http://help.livereload.com/kb/general-use/browser-extensions
6 | ***/
7 |
8 | var tabId, CustomEvents, ExtVersion, LiveReloadInjected, liveReloadInjected;
9 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
10 | CustomEvents = {
11 | bind: function(element, eventName, handler) {
12 | if (element.addEventListener) {
13 | return element.addEventListener(eventName, handler, false);
14 | } else if (element.attachEvent) {
15 | element[eventName] = 1;
16 | return element.attachEvent('onpropertychange', function(event) {
17 | if (event.propertyName === eventName) {
18 | return handler();
19 | }
20 | });
21 | } else {
22 | throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement");
23 | }
24 | },
25 | fire: function(element, eventName) {
26 | var document, event;
27 | document = element instanceof window.HTMLDocument ? element : element.ownerDocument;
28 | if (element.addEventListener) {
29 | event = document.createEvent('HTMLEvents');
30 | event.initEvent(eventName, true, true);
31 | return document.dispatchEvent(event);
32 | } else if (element.attachEvent) {
33 | if (element[eventName]) {
34 | return element[eventName]++;
35 | }
36 | } else {
37 | throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
38 | }
39 | }
40 | };
41 | ExtVersion = '2.0.1';
42 | LiveReloadInjected = (function() {
43 | function LiveReloadInjected(tabId, document, extName) {
44 | this.tabId = tabId;
45 | this.document = document;
46 | this.extName = extName;
47 | };
48 | LiveReloadInjected.prototype.doDisable = function() {
49 | var element = this.document.getElementById('lr-script');
50 | if (element) {
51 | CustomEvents.fire(this.document, 'LiveReloadShutDown');
52 | if (element.parentNode) {
53 | element.parentNode.removeChild(element);
54 | }
55 | }
56 | return;
57 | };
58 | LiveReloadInjected.prototype.doEnable = function(_arg) {
59 | var element, scriptURI, url, useFallback;
60 | useFallback = _arg.useFallback, scriptURI = _arg.scriptURI;
61 | if (useFallback) {
62 | url = "" + scriptURI + "?ext=" + this.extName + "&extver=" + ExtVersion + "&host=localhost";
63 | console.log("Loading LiveReload.js bundled with the browser extension...");
64 | } else {
65 | url = "http://localhost:35729/livereload.js?ext=" + this.extName + "&extver=" + ExtVersion;
66 | console.log("Loading LiveReload.js from " + (url.replace(/\?.*$/, '')) + "...");
67 | }
68 | element = this.document.createElement('script');
69 | element.src = url;
70 | element.id = "lr-script";
71 | return this.document.getElementsByTagName('head')[0].appendChild(element);
72 | };
73 | LiveReloadInjected.prototype.disable = function() {
74 | return this.doDisable(__bind(function() {
75 | return this.send('status', {
76 | enabled: false,
77 | active: false
78 | });
79 | }, this));
80 | };
81 | LiveReloadInjected.prototype.enable = function(options) {
82 | return this.doDisable(__bind(function() {
83 | this.doEnable(options);
84 | return this.send('status', {
85 | enabled: true
86 | });
87 | }, this));
88 | };
89 | return LiveReloadInjected;
90 | })();
91 |
92 |
93 |
94 | window.addEventListener('DOMContentLoaded', function(event) {
95 | /***
96 | * We need a sort of handshake communication: need to check and/or set current tab ID for things to work.
97 | * Opera currently does not support an "onReload" function and neither is it possible to get the current tab id
98 | * from the injected JS. From background.js it is not possible to any useful information (e.g. the tab ID) from
99 | * the connecting tab if it is not the focused tab (event object has limited data and tab/windows extension
100 | * functionality is far from complete)!
101 | * LiveReload reloads the entire tab if the page src (html) is edited, so background functionality is really needed.
102 | *
103 | * Current workflow: (work-around), with added latency...):
104 | * > [inject.js] send message on DOM ready with seesiondata: tabId (instead of onconnect @ background.js)
105 | * > [background.js] is tabId null or set? If set: resume state from own stored data. Null? New setup.
106 | ***/
107 | tabId = window.sessionStorage.getItem('tabId');
108 | opera.extension.postMessage({action: 'initConnection', tabid: tabId});
109 |
110 | opera.extension.onmessage = function(event){
111 | if(tabId == event.data.tabid || event.data.action.indexOf('Connection') > -1) {
112 | switch(event.data.action) {
113 | case 'setupConnection':
114 | //store your own ID, used for further communications (broadcastMessage is multicast only... :/)
115 | tabId = event.data.tabid;
116 | window.sessionStorage.setItem('tabId', event.data.tabid);
117 | liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
118 | break;
119 | case 'resumeConnection':
120 | if(event.data.state === 'active') {
121 | liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
122 | liveReloadInjected.doEnable({useFallback: false, scriptURI: ''});
123 | } else {
124 | liveReloadInjected = new LiveReloadInjected(event.data.tabid, document, 'Opera');
125 | }
126 | break;
127 | case 'enable':
128 | liveReloadInjected.doEnable({useFallback: false, scriptURI: ''});
129 | //can't call internal scripts (getFile function from extension does not exsist) @ Opera Extension
130 | //(or I just don't know how...)
131 | break;
132 | case 'disable':
133 | liveReloadInjected.doDisable();
134 | break;
135 | }
136 | }
137 | }
138 | }, false);
--------------------------------------------------------------------------------
/Opera/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Opera/scripts/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/Opera/scripts/.DS_Store
--------------------------------------------------------------------------------
/Opera/scripts/background.js:
--------------------------------------------------------------------------------
1 | /***
2 | * Author: Gabrijel Gavranović // gavro.nl
3 | * CustomEvent & LiveReload objects/prototype function taken (and partially adapted) from:
4 | * LiveReload Chrome & Firefox extentions, LiveReload.com & Nikita Vasilyev.
5 | * See: http://help.livereload.com/kb/general-use/browser-extensions
6 | ***/
7 |
8 | //global vars/objects
9 | /***
10 | * lrdata structure: tabID, status --> We should keep track of closed tab and remove them but can't get the ID
11 | * of the closed tabs! So let the object fill up, better a larger object instead of a periodical check of
12 | * object agains all open tabs with extension.tabs.getAll()....
13 | ***/
14 | var lrdata = {};
15 |
16 | window.addEventListener("load", setupConnection, false);
17 |
18 | function setupConnection() {
19 | var UIItemProperties = {
20 | disabled: true,
21 | title: "Please reload the page to be able to enable the LiveReload plugin.",
22 | icon: "images/IconDisabled.png",
23 | onclick: function(){
24 | toggleLiveReload(true);
25 | }
26 | };
27 |
28 | toggleButton = opera.contexts.toolbar.createItem(UIItemProperties);
29 | opera.contexts.toolbar.addItem(toggleButton);
30 |
31 | /***
32 | * We need a sort of handshake communication: need to check and/or set current tab ID for things to work.
33 | * Opera currently does not support an "onReload" function and neither is it possible to get the current tab id
34 | * from the injected JS. From background.js it is not possible to any useful information (e.g. the tab ID) from
35 | * the connecting tab if it is not the focused tab (event object has limited data and tab/windows extension
36 | * functionality is far from complete)!
37 | * LiveReload reloads the entire tab if the page src (html) is edited, so background functionality is really needed.
38 | *
39 | * Current workflow: (work-around), with added latency...):
40 | * > [inject.js] send message on DOM ready with seesiondata: tabId (instead of onconnect @ background.js)
41 | * > [background.js] is tabId null or set? If set: resume state from own stored data. Null? New setup.
42 | ***/
43 |
44 | /*opera.extension.onconnect = function(event) {
45 | var tab = opera.extension.tabs.getFocused();
46 | if(tab) {
47 | if(o.has(lrdata, tab.id) && lrdata[tab.id].state === 'active') {
48 | event.source.postMessage({action: 'resumeConnection', tabid: tab.id});
49 | } else {
50 | o.add(lrdata, tab.id, {state: 'inactive', timeStamp: event.timeStamp});
51 | event.source.postMessage({action: 'setupConnection', tabid: tab.id});
52 |
53 | toggleButton.disabled = false;
54 | toggleButton.title = 'Enable LiveReload';
55 | }
56 | }
57 | }*/
58 |
59 | opera.extension.onmessage = function(event) {
60 | switch(event.data.action) {
61 | case "initConnection":
62 | if(event.data.tabid === null) {
63 | var tab = opera.extension.tabs.getFocused();
64 | o.add(lrdata, tab.id, {state: 'inactive'});
65 | event.source.postMessage({action: 'setupConnection', tabid: tab.id});
66 | toggleButton.disabled = false;
67 | toggleButton.title = 'Enable LiveReload';
68 | } else if(o.has(lrdata, event.data.tabid) && lrdata[event.data.tabid].state === 'active'){
69 | event.source.postMessage({action: 'resumeConnection', tabid: event.data.tabid, state: 'active'});
70 | } else {
71 | //event.source.postMessage({action: 'resumeConnection', tabid: event.data.tabid, state: 'inactive'});
72 | event.source.postMessage({action: 'setupConnection', tabid: event.data.tabid});
73 | }
74 | break;
75 | }
76 | }
77 |
78 | opera.extension.tabs.onfocus = function(event) {
79 | var tab = opera.extension.tabs.getFocused();
80 | if(tab) {
81 | if(!o.has(lrdata, tab.id)) {
82 | toggleButton.disabled = true;
83 | toggleButton.title = 'Please reload or even reopen the tab to be able to enable the LiveReload plugin.';
84 | toggleButton.icon = 'images/IconDisabled.png';
85 | } else {
86 | toggleButton.disabled = false;
87 | toggleLiveReload(event, false);
88 | }
89 | }
90 | }
91 | }
92 |
93 |
94 | function toggleLiveReload(change) {
95 | var tab = opera.extension.tabs.getFocused();
96 | if(tab) {
97 | if(o.has(lrdata, tab.id)) {
98 | switch(lrdata[tab.id].state) {
99 | case 'inactive':
100 | if(change === true) {
101 | opera.extension.broadcastMessage({action: 'enable', tabid: tab.id});
102 | lrdata[tab.id].state = 'active';
103 | toggleButton.icon = 'images/IconActive.png';
104 | } else {
105 | toggleButton.icon = 'images/IconDisabled.png';
106 | }
107 | break;
108 | case 'active':
109 | if(change === true){
110 | opera.extension.broadcastMessage({action: 'disable', tabid: tab.id});
111 | lrdata[tab.id].state = 'inactive';
112 | toggleButton.icon = 'images/IconDisabled.png';
113 | } else {
114 | toggleButton.icon = 'images/IconActive.png';
115 | }
116 | break;
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Opera/scripts/o-min.js:
--------------------------------------------------------------------------------
1 | //https://github.com/vladocar/o---JS-Library-for-Object-Manipulation
2 | (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},
3 | 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,
4 | "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);
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LiveReload Browser Extensions
2 | =============================
3 |
4 | Prerequsities:
5 |
6 | * Node.js (0.10.x or later) with npm
7 |
8 | Install dependencies:
9 |
10 | * `npm install`
11 |
12 | Build and package extensions:
13 |
14 | grunt chrome
15 | grunt firefox
16 | grunt all
17 |
18 | (Safari extension must be built manually, using Safari's GUI packager tool.)
19 |
20 | Build CoffeeScript modules, but don't pack:
21 |
22 | grunt build
23 |
24 |
25 | Release checklist
26 | -----------------
27 |
28 | 1. Bump version number in `package.json`, run `rake version`, commit.
29 |
30 | 1. `grunt all`
31 |
32 | 1. Package Safari extension.
33 |
34 | 1. Test, test, test.
35 |
36 | 1. `rake tag`
37 |
38 | 1. `rake upload:safari`, `rake upload:firefox` or `rake upload:all`
39 |
40 | 1. Download and verify that uploads worked.
41 |
42 | 1. `rake upload:manifest`
43 |
44 | 1. Publish Chrome extension on the Chrome Web Store.
45 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | VERSION_FILES = %w(
2 | src/common/version.coffee
3 | LiveReload.safariextension/Info.plist
4 | Chrome/LiveReload/manifest.json
5 | Firefox/install.rdf
6 | )
7 |
8 | def version
9 | content = File.read('package.json')
10 | if content =~ /"version": "(\d+\.\d+\.\d+)"/
11 | return $1
12 | else
13 | raise "Failed to get version info from package.json"
14 | end
15 | end
16 |
17 | def subst_version_refs_in_file file, ver
18 | puts file
19 | orig = File.read(file)
20 | prev_line = ""
21 | anything_matched = false
22 | data = orig.lines.map do |line|
23 | if line =~ /\d\.\d\.\d/ && (line =~ /version/i || prev_line =~ /CFBundleShortVersionString|CFBundleVersion/)
24 | anything_matched = true
25 | new_line = line.gsub /\d\.\d\.\d/, ver
26 | puts " #{new_line.strip}"
27 | else
28 | new_line = line
29 | end
30 | prev_line = line
31 | new_line
32 | end.join('')
33 |
34 | raise "Error: no substitutions made in #{file}" unless anything_matched
35 |
36 | File.open(file, 'w') { |f| f.write data }
37 | end
38 |
39 | desc "Embed version number where it belongs"
40 | task :version do
41 | ver = version
42 | VERSION_FILES.each { |file| subst_version_refs_in_file(file, ver) }
43 | end
44 |
45 |
46 | def upload_file file, folder='dist'
47 | path = "#{folder}/#{file}"
48 | # application/x-chrome-extension
49 | sh 's3cmd', '-P', '--mime-type=application/octet-stream', 'put', path, "s3://download.livereload.com/#{file}"
50 | puts "http://download.livereload.com/#{file}"
51 | end
52 |
53 | desc "Upload the chosen build to S3"
54 | task 'upload:custom' do |t, args|
55 | require 'rubygems'
56 | require 'highline'
57 | HighLine.new.choose do |menu|
58 | menu.prompt = "Please choose a file to upload: "
59 | menu.choices(*Dir['dist/**/*.{crx,safariextz,xpi}'].sort.map { |f| f[5..-1] }) do |file|
60 | upload_file file
61 | end
62 | end
63 | end
64 |
65 | desc "Upload the latest Firefox build to S3"
66 | task 'upload:firefox' do
67 | upload_file "#{version}/LiveReload-#{version}.xpi"
68 | end
69 |
70 | desc "Upload the latest Safari build to S3"
71 | task 'upload:safari' do
72 | upload_file "#{version}/LiveReload-#{version}.safariextz"
73 | end
74 |
75 | desc "Upload the latest builds of all extensions to S3"
76 | task 'upload:all' => ['upload:safari', 'upload:firefox']
77 |
78 | desc "Upload update manifests"
79 | task 'upload:manifest' do
80 | upload_file "LiveReload-Firefox-update.rdf", 'update'
81 | upload_file "LiveReload-Safari-update.plist", 'update'
82 | end
83 |
84 | desc "Tag the current version"
85 | task :tag do
86 | sh 'git', 'tag', "v#{version}"
87 | end
88 | desc "Move (git tag -f) the tag for the current version"
89 | task :retag do
90 | sh 'git', 'tag', '-f', "v#{version}"
91 | end
92 |
--------------------------------------------------------------------------------
/dist/.keepme:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/livereload/livereload-extensions/0a8edb9cc7008249c23718386e19d99230e81179/dist/.keepme
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Andrey Tarantsov ",
3 | "name": "livereload-extensions",
4 | "description": "LiveReload browser extensions (not meant to be installed; npm is used for dependencies only)",
5 | "version": "2.1.0",
6 | "private": true,
7 | "repository": {
8 | "type": "git",
9 | "url": "git://github.com/livereload/livereload-extensions.git"
10 | },
11 | "dependencies": {
12 | "livereload-js": "^2.2.1"
13 | },
14 | "devDependencies": {
15 | "coffeeify": "^1.0.0",
16 | "grunt": "^0.4.5",
17 | "grunt-browserify": "^3.3.0",
18 | "grunt-contrib-coffee": "^0.12.0",
19 | "grunt-contrib-compress": "^0.13.0"
20 | },
21 | "optionalDependencies": {},
22 | "engines": {
23 | "node": "*"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/chrome/devtools.coffee:
--------------------------------------------------------------------------------
1 | require('../common/devtools')
2 |
3 | class DevTools
4 |
5 | resourceAdded: (resource) ->
6 | console.log "LiveReload.resourceAdded: #{resource.url}"
7 | @send 'resourceAdded', url: resource.url
8 |
9 | resourceUpdated: (resource, content) ->
10 | console.log "LiveReload.resourceUpdated: %s - %s", resource.url, content
11 | @send 'resourceUpdated', url: resource.url, content: content
12 |
13 |
14 | class ChromeDevTools extends DevTools
15 |
16 | send: (message, data) ->
17 | chrome.runtime.sendMessage [message, data]
18 |
19 |
20 | do ->
21 |
22 | devTools = new ChromeDevTools()
23 |
24 | chrome.devtools.inspectedWindow.onResourceAdded.addListener (resource) ->
25 | devTools.resourceAdded(resource)
26 |
27 | chrome.devtools.inspectedWindow.onResourceContentCommitted.addListener (resource, content) ->
28 | devTools.resourceUpdated(resource, content)
29 |
--------------------------------------------------------------------------------
/src/chrome/global.coffee:
--------------------------------------------------------------------------------
1 | { LiveReloadGlobal, TabState } = require('../common/global')
2 |
3 | TabState::send = (message, data={}) ->
4 | chrome.tabs.sendMessage @tab, [message, data]
5 |
6 | TabState::bundledScriptURI = -> chrome.runtime.getURL('livereload.js')
7 |
8 | LiveReloadGlobal.isAvailable = (tab) -> yes
9 |
10 | LiveReloadGlobal.initialize()
11 |
12 |
13 | ToggleCommand =
14 | invoke: ->
15 | update: (tabId) ->
16 | status = LiveReloadGlobal.tabStatus(tabId)
17 | chrome.browserAction.setTitle { tabId, title: status.buttonToolTip }
18 | chrome.browserAction.setIcon { tabId, path: { '19' : status.buttonIcon, '38' : status.buttonIconHiRes } }
19 |
20 |
21 | chrome.browserAction.onClicked.addListener (tab) ->
22 | LiveReloadGlobal.toggle(tab.id)
23 | ToggleCommand.update(tab.id)
24 |
25 | chrome.tabs.onSelectionChanged.addListener (tabId, selectInfo) ->
26 | ToggleCommand.update(tabId)
27 |
28 | chrome.tabs.onRemoved.addListener (tabId) ->
29 | LiveReloadGlobal.killZombieTab tabId
30 |
31 |
32 | chrome.runtime.onMessage.addListener ([eventName, data], sender, sendResponse) ->
33 | # console.log "#{eventName}(#{JSON.stringify(data)})"
34 | switch eventName
35 | when 'status'
36 | LiveReloadGlobal.updateStatus(sender.tab.id, data)
37 | ToggleCommand.update(sender.tab.id)
38 | else
39 | LiveReloadGlobal.received(eventName, data)
40 |
--------------------------------------------------------------------------------
/src/chrome/injected.coffee:
--------------------------------------------------------------------------------
1 | { LiveReloadInjected } = require('../common/injected')
2 |
3 | LiveReloadInjected::send = (message, data) ->
4 | chrome.runtime.sendMessage [message, data]
5 |
6 | liveReloadInjected = new LiveReloadInjected(document, window, 'Chrome')
7 |
8 | chrome.runtime.onMessage.addListener ([eventName, data], sender, sendResponse) ->
9 | # console.log "#{eventName}(#{JSON.stringify(data)})"
10 | switch eventName
11 | when 'alert'
12 | alert data
13 | when 'enable'
14 | liveReloadInjected.enable(data)
15 | when 'disable'
16 | liveReloadInjected.disable()
17 |
--------------------------------------------------------------------------------
/src/common/devtools.coffee:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/common/global.coffee:
--------------------------------------------------------------------------------
1 | # LRClient = require 'livereload-client'
2 |
3 | ExtVersion = require('./version')
4 |
5 | Status =
6 | unavailable:
7 | buttonEnabled: no
8 | buttonToolTip: 'LiveReload not available on this tab'
9 | buttonIcon: 'IconUnavailable.png'
10 | buttonIconHiRes: 'IconUnavailable@2x.png'
11 | disabled:
12 | buttonEnabled: yes
13 | buttonToolTip: 'Enable LiveReload'
14 | buttonIcon: 'IconDisabled.png'
15 | buttonIconHiRes: 'IconDisabled@2x.png'
16 | enabled:
17 | buttonEnabled: yes
18 | buttonToolTip: 'LiveReload is connecting, click to disable'
19 | buttonIcon: 'IconEnabled.png'
20 | buttonIconHiRes: 'IconEnabled@2x.png'
21 | active:
22 | buttonEnabled: yes
23 | buttonToolTip: 'LiveReload is connected, click to disable'
24 | buttonIcon: 'IconActive.png'
25 | buttonIconHiRes: 'IconActive@2x.png'
26 |
27 |
28 |
29 | class TabState
30 | constructor: (@tab) ->
31 | @enabled = no
32 | @active = no
33 |
34 | enable: ->
35 | @send 'enable', { @useFallback, scriptURI: @bundledScriptURI(), host: LiveReloadGlobal.host, port: LiveReloadGlobal.port }
36 |
37 | disable: ->
38 | @send 'disable'
39 |
40 | updateStatus: (status) ->
41 | if status.initial
42 | if !status.enabled
43 | @active = no
44 | if @enabled
45 | @enable()
46 | return
47 | if status.enabled?
48 | @enabled = status.enabled
49 | if status.active?
50 | @active = status.active
51 |
52 | status: ->
53 | switch
54 | when @active
55 | Status.active
56 | when @enabled
57 | Status.enabled
58 | else
59 | Status.disabled
60 |
61 | alert: (message) ->
62 | @send 'alert', message
63 |
64 |
65 | if navigator.userAgent.match(/Mac OS X/)
66 | CannotConnectAlert = """Could not connect to LiveReload server. Please make sure that LiveReload 2.3 (or later) or another compatible server is running."""
67 | else
68 | CannotConnectAlert = """Could not connect to LiveReload server. Please make sure that a compatible LiveReload server is running. (We recommend guard-livereload, until LiveReload 2 comes to your platform.)"""
69 |
70 |
71 | TheWebSocket = (WebSocket ? MozWebSocket)
72 |
73 |
74 | LiveReloadGlobal =
75 | _tabs: []
76 |
77 | initialize: ->
78 | @host = '127.0.0.1'
79 | @port = 35729
80 | # @client = new LRClient
81 | # host: @host
82 | # port: @port
83 | # supportedProtocols:
84 | # monitoring: [LRClient.protocols.MONITORING_7]
85 | # connCheck: [LRClient.protocols.CONN_CHECK_1]
86 | # saving: [LRClient.protocols.SAVING_1]
87 |
88 | # WebSocket: TheWebSocket
89 |
90 | # id: 'com.livereload.extension.chrome'
91 | # name: 'Chrome extension'
92 | # version: ExtVersion
93 | # @client.open()
94 |
95 |
96 | killZombieTabs: ->
97 | @_tabs = (tabState for tabState in @_tabs when @isAvailable(tabState.tab))
98 |
99 | killZombieTab: (tab) ->
100 | for tabState, index in @_tabs
101 | if tabState.tab is tab
102 | @_tabs.splice index, 1
103 | return
104 | return
105 |
106 | findState: (tab, create=no) ->
107 | for tabState in @_tabs
108 | return tabState if tabState.tab is tab
109 | if create
110 | state = new TabState(tab)
111 | @_tabs.push state
112 | state
113 | else
114 | null
115 |
116 | toggle: (tab) ->
117 | if @isAvailable(tab)
118 | state = @findState(tab, yes)
119 | if state.enabled
120 | state.disable()
121 | unless @areAnyTabsEnabled()
122 | @afterDisablingLast()
123 | else
124 | if @areAnyTabsEnabled()
125 | state.useFallback = @useFallback
126 | state.enable()
127 | else
128 | @beforeEnablingFirst (err) =>
129 | if err
130 | switch err
131 | when 'cannot-connect' then state.alert(CannotConnectAlert)
132 | when 'cannot-download' then state.alert("Cannot download livereload.js")
133 | else
134 | state.useFallback = @useFallback
135 | state.enable()
136 |
137 | tabStatus: (tab) ->
138 | unless @isAvailable(tab)
139 | return Status.unavailable
140 | @findState(tab)?.status() || Status.disabled
141 |
142 | updateStatus: (tab, status) ->
143 | @findState(tab, yes).updateStatus(status)
144 |
145 | areAnyTabsEnabled: ->
146 | return yes for tabState in @_tabs when tabState.enabled
147 | no
148 |
149 | beforeEnablingFirst: (callback) ->
150 | @useFallback = no
151 |
152 | # probe using web sockets
153 | callbackCalled = no
154 |
155 | failOnTimeout = ->
156 | console.log "Haven't received a handshake reply in time, disconnecting."
157 | ws.close()
158 | timeout = setTimeout(failOnTimeout, 1000)
159 |
160 | console.log "Connecting to ws://#{@host}:#{@port}/livereload..."
161 | ws = new TheWebSocket("ws://#{@host}:#{@port}/livereload")
162 | ws.onerror = =>
163 | console.log "Web socket error."
164 | callback('cannot-connect') unless callbackCalled
165 | callbackCalled = yes
166 | ws.onopen = =>
167 | console.log "Web socket connected, sending handshake."
168 | ws.send JSON.stringify({ command: 'hello', protocols: ['http://livereload.com/protocols/connection-check-1'] })
169 | ws.onclose = ->
170 | console.log "Web socket disconnected."
171 | callback('cannot-connect') unless callbackCalled
172 | callbackCalled = yes
173 | ws.onmessage = (event) =>
174 | clearTimeout(timeout) if timeout
175 | timeout = null
176 |
177 | console.log "Incoming message: #{event.data}"
178 | if event.data.match(/^!!/)
179 | @useFallback = yes
180 | callback(null) unless callbackCalled
181 | callbackCalled = yes
182 | ws.close()
183 | else if event.data.match(/^\{/)
184 | xhr = new XMLHttpRequest()
185 | xhr.onreadystatechange = =>
186 | if xhr.readyState is XMLHttpRequest.DONE and xhr.status is 200
187 | @script = xhr.responseText
188 | callback(null) unless callbackCalled
189 | callbackCalled = yes
190 | xhr.onerror = (event) =>
191 | callback('cannot-download') unless callbackCalled
192 | callbackCalled = yes
193 | xhr.open("GET", "http://#{@host}:#{@port}/livereload.js", true)
194 | xhr.send(null)
195 |
196 |
197 | afterDisablingLast: ->
198 |
199 |
200 | received: (eventName, data) ->
201 | if func = @["on #{eventName}"]
202 | func.call(this, data)
203 |
204 | 'on resourceAdded': ({ url }) ->
205 | console.log "Resource added: #{url}"
206 | # if @client.connected
207 | # if @client.negotiatedProtocols?.connCheck >= 1
208 | # @client.send { command: "presave", url }
209 | # else
210 | # console.log "Saving protocol not supported."
211 | # else
212 | # @client.open()
213 |
214 | 'on resourceUpdated': ({ url, content }) ->
215 | console.log "Resource updated: #{url}"
216 | # if @client.connected
217 | # if @client.negotiatedProtocols?.connCheck >= 1
218 | # @client.send { command: "save", url, content }
219 | # else
220 | # console.log "Saving protocol not supported."
221 | # else
222 | # @client.open()
223 |
224 |
225 | exports.TabState = TabState
226 | exports.LiveReloadGlobal = LiveReloadGlobal
227 |
--------------------------------------------------------------------------------
/src/common/injected.coffee:
--------------------------------------------------------------------------------
1 | CustomEvents =
2 | bind: (element, eventName, handler) ->
3 | if element.addEventListener
4 | element.addEventListener eventName, handler, false
5 | else if element.attachEvent
6 | element[eventName] = 1
7 | element.attachEvent 'onpropertychange', (event) ->
8 | if event.propertyName is eventName
9 | handler()
10 | else
11 | throw new Error("Attempt to attach custom event #{eventName} to something which isn't a DOMElement")
12 |
13 | fire: (element, eventName) ->
14 | document = if element instanceof HTMLDocument then element else element.ownerDocument
15 | if element.addEventListener
16 | event = document.createEvent('HTMLEvents')
17 | event.initEvent(eventName, true, true)
18 | document.dispatchEvent(event)
19 | else if element.attachEvent
20 | if element[eventName]
21 | element[eventName]++
22 | else
23 | throw new Error("Attempt to fire custom event #{eventName} on something which isn't a DOMElement")
24 |
25 | ExtVersion = require('./version')
26 |
27 | class LiveReloadInjected
28 |
29 | constructor: (@document, @window, @extName) ->
30 | @_hooked = no
31 | @_verbose = !!@window?.location?.href?.match(/LR-verbose/)
32 |
33 | setTimeout((=> @determineInitialState()), 1)
34 |
35 | determineInitialState: ->
36 | if @findScriptTag()
37 | @send 'status', enabled: yes, active: yes, initial: yes
38 | @hook()
39 | else
40 | @send 'status', enabled: no, active: no, initial: yes
41 |
42 | findScriptTag: ->
43 | for element in @document.getElementsByTagName('script')
44 | if src = element.src
45 | if m = src.match /// /livereload\.js (?: \? (.*) )? $///
46 | return element
47 | null
48 |
49 | doDisable: (callback) ->
50 | element = @findScriptTag()
51 | if element
52 | CustomEvents.fire @document, 'LiveReloadShutDown'
53 | element.parentNode.removeChild(element) if element.parentNode
54 | callback()
55 |
56 | doEnable: ({ useFallback, scriptURI, @host, @port })->
57 | # our stuff isn't welcome in CKEditor's editing IFRAME :-)
58 | if @document.documentElement?.contentEditable is 'true'
59 | return
60 |
61 | if useFallback
62 | url = "#{scriptURI}?ext=#{@extName}&extver=#{ExtVersion}&host=#{@host}&port=#{@port}"
63 | if @_verbose
64 | console.log "Loading LiveReload.js bundled with the browser extension..."
65 | else
66 | url = "http://#{@host}:#{@port}/livereload.js?ext=#{@extName}&extver=#{ExtVersion}"
67 | if @_verbose
68 | console.log "Loading LiveReload.js from #{url.replace(/\?.*$/, '')}..."
69 |
70 | @hook()
71 | element = @document.createElement('script')
72 | element.src = url
73 | @document.body.appendChild(element)
74 |
75 | hook: ->
76 | return if @_hooked
77 | @_hooked = yes
78 |
79 | CustomEvents.bind @document, 'LiveReloadConnect', =>
80 | @send 'status', active: yes
81 | CustomEvents.bind @document, 'LiveReloadDisconnect', =>
82 | @send 'status', active: no
83 |
84 | disable: ->
85 | @doDisable =>
86 | @send 'status', enabled: no, active: no
87 |
88 | enable: (options) ->
89 | @doDisable =>
90 | @doEnable options
91 | @send 'status', enabled: yes
92 |
93 | exports.LiveReloadInjected = LiveReloadInjected
94 |
--------------------------------------------------------------------------------
/src/common/version.coffee:
--------------------------------------------------------------------------------
1 | module.exports = ExtVersion = '2.1.0'
2 |
--------------------------------------------------------------------------------
/src/firefox/firefox.coffee:
--------------------------------------------------------------------------------
1 | # Firefox does not use background/injected content separation, so this file
2 | # serves the purpose of both global-firefox and injected-firefox.
3 | { LiveReloadGlobal, TabState } = require('../common/global')
4 | { LiveReloadInjected } = require('../common/injected')
5 |
6 | findTabByContentDocument = (doc) ->
7 | for tab in gBrowser.tabs
8 | if gBrowser.getBrowserForTab(tab).contentDocument is doc
9 | return tab
10 | return null
11 |
12 |
13 | LiveReloadInjected::send = (eventName, data) ->
14 | tab = findTabByContentDocument(@document)
15 | unless tab
16 | # TODO: we're inside an (I)FRAME. Is any special treatment needed?
17 | return
18 |
19 | switch eventName
20 | when 'status'
21 | LiveReloadGlobal.updateStatus(tab, data)
22 | ToggleButton.update()
23 |
24 | TabState::send = (eventName, data={}) ->
25 | doc = gBrowser.getBrowserForTab(@tab).contentDocument
26 | injected = doc.__LiveReload_injected
27 | unless injected
28 | alert "There is no LiveReloadInjected for #{doc.location.href}"
29 | return
30 |
31 | switch eventName
32 | when 'alert'
33 | alert data
34 | when 'enable'
35 | injected.enable(data)
36 | when 'disable'
37 | injected.disable()
38 |
39 | TabState::bundledScriptURI = -> 'chrome://livereload/content/livereload.js'
40 |
41 | LiveReloadGlobal.isAvailable = (tab) -> yes
42 |
43 | LiveReloadGlobal.initialize()
44 |
45 |
46 | ToggleButton =
47 | initialize: ->
48 | @toggleButton = document.getElementById('livereload-button')
49 | @toggleButton.addEventListener 'command', (event) ->
50 | LiveReloadGlobal.toggle(gBrowser.selectedTab)
51 | ToggleButton.update()
52 |
53 | update: ->
54 | status = LiveReloadGlobal.tabStatus(gBrowser.selectedTab)
55 | @toggleButton.tooltiptext = status.buttonToolTip
56 | @toggleButton.image = "chrome://livereload/skin/#{status.buttonIcon}"
57 |
58 |
59 | window.addEventListener 'load', ->
60 | ToggleButton.initialize()
61 |
62 | # alert "Hello from LiveReload!"
63 | # event.view.gBrowser.selectedTab
64 |
65 | ContentScriptInjectionSimulation =
66 | initialize: ->
67 | gBrowser.addEventListener 'DOMContentLoaded', (event) ->
68 | doc = event.originalTarget
69 | win = doc.defaultView
70 | return if doc?.location?.href is 'about:blank'
71 | # alert "Page loaded! #{doc?.location?.href}"
72 |
73 | doc.__LiveReload_injected = new LiveReloadInjected(doc, win, 'Firefox')
74 |
75 | win.addEventListener "unload", (event) ->
76 | doc.__LiveReload_injected = null
77 | # alert "Page unloaded #{doc.foo?.x}: #{doc.location.href}"
78 |
79 | ContentScriptInjectionSimulation.initialize()
80 |
81 | # window.addEventListener "pagehide", (event) ->
82 | # if event.originalTarget instanceof HTMLDocument
83 | # doc = event.originalTarget
84 |
85 | gBrowser.tabContainer.addEventListener 'TabSelect', (event) ->
86 | tab = event.target
87 | ToggleButton.update()
88 | # alert "Tab select:\nlabel = #{tab.label}\ndocument = #{tab.linkedBrowser?.contentDocument}\ndocument.href = #{tab.linkedBrowser?.contentDocument?.location?.href}"
89 | # var index = livereloadBackground.pages.indexOf(tab);
90 | # if (index == -1) {
91 | # livereloadBackground.onDisablePage(tab);
92 | # } else {
93 | # livereloadBackground.onEnablePage(tab);
94 | # }
95 | # }, false);
96 |
97 | gBrowser.tabContainer.addEventListener 'TabClose', (event) ->
98 | LiveReloadGlobal.killZombieTab event.target
99 | ToggleButton.update()
100 | # tab = event.target
101 | # console.error "Tab close:"
102 | # console.error tab
103 |
--------------------------------------------------------------------------------
/src/livereload-js.coffee:
--------------------------------------------------------------------------------
1 | require('livereload-js')
2 |
--------------------------------------------------------------------------------
/src/safari/global.coffee:
--------------------------------------------------------------------------------
1 | { LiveReloadGlobal, TabState } = require('../common/global')
2 |
3 | TabState::send = (message, data={}) ->
4 | @tab.page.dispatchMessage message, data
5 |
6 | TabState::bundledScriptURI = -> safari.extension.baseURI + 'livereload.js'
7 |
8 | LiveReloadGlobal.isAvailable = (tab) -> !!tab.url
9 |
10 | LiveReloadGlobal.initialize()
11 |
12 |
13 | Commands =
14 | toggle:
15 | invoke: (event) ->
16 | LiveReloadGlobal.toggle(event.target.browserWindow.activeTab)
17 | event.target.validate()
18 | validate: (event) ->
19 | @toolbarItem = event.target
20 | LiveReloadGlobal.killZombieTabs()
21 |
22 | status = LiveReloadGlobal.tabStatus(event.target.browserWindow.activeTab)
23 | event.target.disabled = !status.buttonEnabled
24 | event.target.toolTip = status.buttonToolTip
25 | event.target.image = safari.extension.baseURI + status.buttonIcon
26 |
27 | revalidate: ->
28 | @toolbarItem?.validate()
29 |
30 |
31 | safari.application.addEventListener 'command', (event) ->
32 | Commands[event.command]?.invoke?(event)
33 |
34 | safari.application.addEventListener 'validate', (event) ->
35 | Commands[event.command]?.validate?(event)
36 |
37 | safari.application.addEventListener 'message', (event) ->
38 | # console.log "#{event.name}(#{JSON.stringify(event.message)})"
39 | switch event.name
40 | when 'status'
41 | LiveReloadGlobal.updateStatus(event.target, event.message)
42 | Commands.toggle.revalidate()
43 |
--------------------------------------------------------------------------------
/src/safari/injected.coffee:
--------------------------------------------------------------------------------
1 | { LiveReloadInjected } = require('../common/injected')
2 |
3 | LiveReloadInjected::send = (message, data) ->
4 | safari.self.tab.dispatchMessage message, data
5 |
6 | liveReloadInjected = new LiveReloadInjected(document, window, 'Safari')
7 |
8 | safari.self.addEventListener 'message', (event) ->
9 | # console.log "#{event.name}(#{JSON.stringify(event.message)})"
10 | switch event.name
11 | when 'alert'
12 | alert event.message
13 | when 'enable'
14 | liveReloadInjected.enable(event.message)
15 | when 'disable'
16 | liveReloadInjected.disable()
17 |
--------------------------------------------------------------------------------
/update/LiveReload-Firefox-update.rdf:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/update/LiveReload-Safari-update.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Extension Updates
6 |
7 |
8 | CFBundleIdentifier
9 | com.livereload.extensions.SafariLiveReload
10 | Developer Identifier
11 | D963M2VVCH
12 | CFBundleVersion
13 | 2.1.0
14 | CFBundleShortVersionString
15 | 2.1.0
16 | URL
17 | http://download.livereload.com/2.1.0/LiveReload-2.1.0.safariextz
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------