Permalink
Browse files

Use the force, Luke.

  • Loading branch information...
joepestro committed Nov 23, 2009
0 parents commit 580d1c6966b68059fd7993a721261824b82fd859
@@ -0,0 +1,47 @@
+The Force
+=========
+
+The Force is an experimental Firefox extension that binds your Rails project to Firefox.
+
+This allows you to "Use The Force" from any page and open the responsible file(s) in your text editor. Hate digging through controllers, views, and partials to find the content you're looking for? I do. But with this extension, you don't have to. It adds a context menu (right click) item and Tools menu item that are aware of the current page and selected text (if present). The Force will scan your render chain and open the appropriate file(s) automatically. If text is selected, will jump you to the line where that text is found.
+
+Installation
+------------
+
+You can install the pre-compiled theforce.xpi by dragging it into Firefox. Type *about:config* in the address bar and search for the property *extensions.theforce.projectPath*. Change the value to the root path of your desired Rails project.
+
+Usage Basics
+------------
+
+Navigate to http://localhost:3000/ and right click (or use the Tools menu), and select "Use The Force".
+
+Compiling
+---------
+
+To build from source, run the compile script:
+
+ ./compile
+
+This will build a new theforce.xpi file which should then be reinstalled in Firefox. The extension hands off control between a few files:
+
+* `theforce-browser.js`: acts as a launcher for the extension, gathers information from the current page and passes it to ruby for inspection.
+* `theforce.rb`: all functionality for loading the Rails environment and scanning rendered files happens here.
+* `preferences.js`: stores the extension variable which contains the path to the current Rails project directory.
+
+How it works
+------------
+
+The Force analyzes the most recent entries in your development Rails log to determine which files are responsible for the last page render. Uses `sed` to find the line of selected text, and passes this to the `mate` command to open the correct file and jump to the line where the text is located. Because of this, The Force works best when larger amounts of text are selected (to prevent duplicate matches), and the text should be present in the source code.
+
+Current Limitations
+-------------------
+
+* TextMate-only right now
+* Relies on default controller naming conventions
+
+Copyright
+---------
+
+**The Force** is Copyright (c) [Joe Pestro](http://joepestro.github.com), released under the MIT License.
+
+The **Generic Firefox Plugin** is Copyright (c) [David Lancashire](http://popupchinese.com)
13 compile
@@ -0,0 +1,13 @@
+cd theforce
+cd chrome
+zip -r theforce ./*
+mv theforce.zip theforce.jar
+rm -rf content
+rm -rf locale
+rm -rf skin
+cd ..
+zip -r theforce ./*
+mv theforce.zip ../theforce.xpi
+cd chrome
+unzip theforce.jar
+rm theforce.jar
Binary file not shown.
@@ -0,0 +1,8 @@
+content theforce jar:chrome/theforce.jar!/content/
+content theforce jar:chrome/theforce.jar!/content/ contentaccessible=yes
+locale theforce en-US jar:chrome/theforce.jar!/locale/en-US/
+skin theforce classic/1.0 jar:chrome/theforce.jar!/skin/classic/
+
+overlay chrome://browser/content/browser.xul chrome://theforce/content/theforce-browser.xul
+style chrome://global/content/customizeToolbar.xul chrome://theforce/skin/theforce.css
+
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
+
+ <RDF:Description RDF:about="urn:mozilla:package:theforce"
+ chrome:extension="true"
+ chrome:displayName="theforce"
+ chrome:name="theforce" />
+
+
+ <RDF:Seq RDF:about="urn:mozilla:package:root">
+ <RDF:li RDF:resource="urn:mozilla:package:theforce"/>
+ </RDF:Seq>
+
+
+ <RDF:Seq RDF:about="urn:mozilla:overlays">
+ <RDF:li RDF:resource="chrome://browser/content/browser.xul"/>
+ </RDF:Seq>
+
+
+ <RDF:Seq RDF:about="chrome://browser/content/browser.xul">
+ <RDF:li>chrome://theforce/content/theforce-browser.xul</RDF:li>
+ </RDF:Seq>
+
+
+</RDF:RDF>
@@ -0,0 +1,184 @@
+/*
+The Force by Joe Pestro
+Use the force, Luke!
+
+ .___________. __ __ _______
+ | || | | | | ____|
+ `---| |----`| |__| | | |__
+ | | | __ | | __|
+ | | | | | | | |____
+ |__| |__| |__| |_______|
+
+ _______ ______ .______ ______ _______
+ | ____| / __ \ | _ \ / || ____|
+ | |__ | | | | | |_) | | ,----'| |__
+ | __| | | | | | / | | | __|
+ | | | `--' | | |\ \----.| `----.| |____
+ |__| \______/ | _| `._____| \______||_______|
+
+*/
+
+/*
+ *
+ * Avoid conflicts with external javascript variables, etc. by packaging all of the
+ * variables this plugin uses in a special object. This requires a novel way to
+ * initialized variables and functions which may not be familiar to everyone.
+ *
+ */
+var theforce = {
+
+ /*
+ *
+ * Toggle Function
+ *
+ * This is our main function. Scroll down and edit the part of this function that screams
+ * for you to edit it. This is the javascript that will be executed whenever someone activates
+ * your plugin.
+ *
+ */
+ toggle: function() {
+
+ try {
+
+ try {
+
+ /* We test to see if our CSS has already been injected into the browser page by
+ * testing for the existence of an empty DIV tag we insert into the HTML. If this
+ * DIV tag exists, we know the page supports all of the necessary elements for
+ * operating the plugin. If it does not, we simply add them below. If you need to
+ * add DIV tags or page elements, I recommend doing it below.
+ */
+ theforce.statusWindow = content.document.getElementById("theforce-status");
+
+ if (!theforce.statusWindow) {
+
+ // Add Packaged CSS (theforce/chrome/skin/classic/theforce.css)
+ var theforceCss = content.document.createElementNS("http://www.w3.org/1999/xhtml", "link");
+ theforceCss.setAttribute("rel", "stylesheet");
+ theforceCss.setAttribute("type", "text/css");
+ theforceCss.setAttribute("href", "chrome://theforce/skin/theforce.css");
+ content.document.getElementsByTagName("head")[0].appendChild(theforceCss);
+
+ // Status Window
+ theforce.statusWindow = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+ theforce.statusWindow.setAttribute("id", "theforce-status");
+ content.document.documentElement.appendChild(theforce.statusWindow);
+
+ }
+
+ } catch (err) {}
+
+ try {
+ // get current url
+ var urlbar = document.getElementById('urlbar');
+
+ // get project path
+ var prefManager = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ var projectPath = prefManager.getCharPref("extensions.theforce.projectPath");
+
+ if (urlbar && urlbar.value.indexOf("http://localhost") == 0 && projectPath) {
+ // get directory where we are
+ // the extension's id from install.rdf
+ var MY_ID = "theforce@joe.pestro";
+ var em = Components.classes["@mozilla.org/extensions/manager;1"].
+ getService(Components.interfaces.nsIExtensionManager);
+ // the path may use forward slash ("/") as the delimiter
+ // returns nsIFile for the extension's install.rdf
+ var file = em.getInstallLocation(MY_ID).getItemFile(MY_ID, "theforce.rb");
+ var filestring = file.path.replace(/ /g, "\ "); // replace spaces in path. grr
+
+ // get path part of this url
+ var url = urlbar.value.substring(urlbar.value.indexOf("/", 7));
+ if (url.indexOf("?") != -1)
+ url = url.substring(0, url.indexOf("?"));
+ if (url.indexOf("#") != -1)
+ url = url.substring(0, url.indexOf("#"));
+
+ // create an nsILocalFile for the executable
+ var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
+ file.initWithPath("/usr/bin/ruby");
+
+ // create an nsIProcess
+ var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
+ process.init(file);
+
+ // Run the process.
+ // If first param is true, calling thread will be blocked until
+ // called process terminates.
+ // Second and third params are used to pass command-line arguments
+ // to the process.
+ if (content.document.getSelection())
+ var args = [filestring, url, projectPath, content.document.getSelection()];
+ else
+ var args = [filestring, url, projectPath];
+
+ process.run(false, args, args.length);
+ }
+ else if (!projectPath) {
+ alert("Specify project path in about:config, you must.")
+ }
+ else {
+ alert("Use The Force from localhost, you must.")
+ }
+
+ } catch (err) { alert(err.message); }
+
+ } catch (err) {}
+
+ },
+
+ /* Variables */
+
+ statusWindow: "",
+
+ /* Functions */
+
+ /* Initialization Function -- invoked at the bottom of this file, it
+ * instructs the browser to run the onPageLoad function when the browser
+ * starts up.
+ */
+ init: function() {
+ window.addEventListener('load', this.onPageLoad, false);
+ },
+
+ /*
+ *
+ * PageLoad Function - we add our general event listeners here. The most
+ * useful is listening for onTabSelect so that we can "retoggle" the plugin
+ * so that it remains in use each time the user switches tabs.
+ *
+ */
+ onPageLoad: function(evt) { theforce._onPageLoad(); },
+ _onPageLoad: function(evt) {
+ try {
+ // Add onTabSelect Listener
+ gBrowser.mTabContainer.addEventListener('select', this.onTabSelect, false);
+ } catch (err) {}
+ },
+
+ /*
+ *
+ * TabSelect Function - if you wish to start the plugin automatically every
+ * time the users switches to a new tab, add the necessary code below.
+ *
+ */
+ onTabSelect: function(evt) { theforce._onTabSelect(); },
+ _onTabSelect: function(evt) {
+ try {
+ // theforce.toggle(); // uncomment to initialize the plugin each time a user switches to a new window
+ } catch (err) {}
+ },
+
+ /* Empty Closing Function
+ *
+ * In this type of data structure all of our functions save the very last one need to be followed by a comma.
+ * Including this empty function at the end is a useful way to avoid problems. You can get rid of this if you
+ * know what you are doing.
+ *
+ */
+ all_other_functions_need_to_close_with_comma: function() {}
+
+};
+
+theforce.init();
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://theforce/skin/theforce.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://theforce/locale/theforce.dtd">
+
+<overlay id="theforce" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/x-javascript" src="chrome://theforce/content/theforce-browser.js" />
+
+ <commandset id="mainCommandSet">
+ <command id="theforce-toggle-cmd" oncommand="theforce.toggle();" />
+ </commandset>
+
+ <popup id="contentAreaContextMenu">
+ <menuseparator id="theforce-separator-cm" hidden="true" />
+ <menuitem id="theforce-toggle-menu-cm" label="Use The Force" command="theforce-toggle-cmd" hidden="false" />
+ </popup>
+
+ <menupopup id="menu_ToolsPopup">
+ <menuseparator id="theforce-separator-tm" hidden="true" insertbefore="devToolsSeparator" />
+ <menuitem id="theforce-toggle-menu-tm" label="Use The Force" command="theforce-toggle-cmd" hidden="false" />
+ </menupopup>
+
+</overlay>
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
+
+ <RDF:Seq about="urn:mozilla:locale:root">
+ <RDF:li resource="urn:mozilla:locale:en-US"/>
+ </RDF:Seq>
+
+ <RDF:Description about="urn:mozilla:locale:en-US" chrome:name="en-US">
+ <chrome:packages>
+ <RDF:Seq about="urn:mozilla:locale:en-US:packages">
+ <RDF:li resource="urn:mozilla:locale:en-US:theforce"/>
+ </RDF:Seq>
+ </chrome:packages>
+ </RDF:Description>
+
+</RDF:RDF>
@@ -0,0 +1,6 @@
+
+<!ENTITY theforce.toggle.menu.cm "Toggle Adsotrans">
+<!ENTITY theforce.toggle.menu.tm "Toggle Adsotrans">
+<!ENTITY theforce.prefs.adsouser "login">
+<!ENTITY theforce.prefs.adsopass "password">
+
Binary file not shown.
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
+
+ <RDF:Seq about="urn:mozilla:skin:root">
+ <RDF:li resource="urn:mozilla:skin:classic/1.0" />
+ </RDF:Seq>
+
+ <RDF:Description about="urn:mozilla:skin:classic/1.0">
+ <chrome:packages>
+ <RDF:Seq about="urn:mozilla:skin:classic/1.0:packages">
+ <RDF:li resource="urn:mozilla:skin:classic/1.0:adsotrans" />
+ </RDF:Seq>
+ </chrome:packages>
+ </RDF:Description>
+
+ <RDF:Seq about="urn:mozilla:stylesheets">
+ <RDF:li resource="chrome://global/content/customizeToolbar.xul"/>
+ </RDF:Seq>
+
+ <RDF:Seq about="chrome://global/content/customizeToolbar.xul">
+ <RDF:li>chrome://adsotrans/skin/adsotrans.css</RDF:li>
+ </RDF:Seq>
+
+</RDF:RDF>
Oops, something went wrong.

0 comments on commit 580d1c6

Please sign in to comment.