Initial revision
authorjkkn <jkkn>
Wed, 17 Oct 2007 08:30:47 +0000 (08:30 +0000)
committerjkkn <jkkn>
Wed, 17 Oct 2007 08:30:47 +0000 (08:30 +0000)
15 files changed:
build.sh [new file with mode: 0755]
chrome.manifest [new file with mode: 0755]
config_build.sh [new file with mode: 0755]
content/about.xul [new file with mode: 0755]
content/browser_overlay.xul [new file with mode: 0755]
content/options.xul [new file with mode: 0755]
content/tv2developer.js [new file with mode: 0755]
defaults/preferences/tv2developer.js [new file with mode: 0755]
install.rdf [new file with mode: 0755]
locale/en-US/tv2developer.dtd [new file with mode: 0755]
locale/en-US/tv2developer.properties [new file with mode: 0755]
skin/interaktiv.png [new file with mode: 0755]
skin/interaktiv_large.png [new file with mode: 0755]
skin/tv2developer.css [new file with mode: 0755]
tv2developer.xpi [new file with mode: 0644]

diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..e8f17fc
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,136 @@
+#!/usr/local/bin/bash
+# build.sh -- builds JAR and XPI files for mozilla extensions
+#   by Nickolay Ponomarev <asqueella@gmail.com>
+#   (original version based on Nathan Yergler's build script)
+# Most recent version is at <http://kb.mozillazine.org/Bash_build_script>
+
+# This script assumes the following directory structure:
+# ./
+#   chrome.manifest (optional - for newer extensions)
+#   install.rdf
+#   (other files listed in $ROOT_FILES)
+#
+#   content/    |
+#   locale/     |} these can be named arbitrary and listed in $CHROME_PROVIDERS
+#   skin/       |
+#
+#   defaults/   |
+#   components/ |} these must be listed in $ROOT_DIRS in order to be packaged
+#   ...         |
+#
+# It uses a temporary directory ./build when building; don't use that!
+# Script's output is:
+# ./$APP_NAME.xpi
+# ./$APP_NAME.jar  (only if $KEEP_JAR=1)
+# ./files -- the list of packaged files
+#
+# Note: It modifies chrome.manifest when packaging so that it points to 
+#       chrome/$APP_NAME.jar!/*
+
+#
+# default configuration file is ./config_build.sh, unless another file is 
+# specified in command-line. Available config variables:
+APP_NAME=          # short-name, jar and xpi files name. Must be lowercase with no spaces
+CHROME_PROVIDERS=  # which chrome providers we have (space-separated list)
+CLEAN_UP=          # delete the jar / "files" when done?       (1/0)
+ROOT_FILES=        # put these files in root of xpi (space separated list of leaf filenames)
+ROOT_DIRS=         # ...and these directories       (space separated list)
+BEFORE_BUILD=      # run this before building       (bash command)
+AFTER_BUILD=       # ...and this after the build    (bash command)
+
+if [ -z $1 ]; then
+  . ./config_build.sh
+else
+  . $1
+fi
+
+if [ -z $APP_NAME ]; then
+  echo "You need to create build config file first!"
+  echo "Read comments at the beginning of this script for more info."
+  exit;
+fi
+
+ROOT_DIR=`pwd`
+TMP_DIR=build
+
+#uncomment to debug
+#set -x
+
+# remove any left-over files from previous build
+rm $APP_NAME.jar
+rm $APP_NAME.xpi
+rm files
+rm -rf $TMP_DIR
+
+vi install.rdf content/about.xul
+
+$BEFORE_BUILD
+
+mkdir -pv $TMP_DIR/chrome
+
+# generate the JAR file, excluding CVS and temporary files
+JAR_FILE=$TMP_DIR/chrome/$APP_NAME.jar
+echo "Generating $JAR_FILE..."
+for CHROME_SUBDIR in $CHROME_PROVIDERS; do
+  find $CHROME_SUBDIR -path '*CVS*' -prune -o -type f -print | grep -v \~ >> files
+done
+
+zip -0 -r $JAR_FILE `cat files`
+# The following statement should be used instead if you don't wish to use the JAR file
+#cp --verbose --parents `cat files` $TMP_DIR/chrome
+
+# prepare components and defaults
+echo "Copying various files to $TMP_DIR folder..."
+for DIR in $ROOT_DIRS; do
+  mkdir $TMP_DIR/$DIR
+  FILES="`find $DIR -path '*CVS*' -prune -o -type f -print | grep -v \~`"
+  echo $FILES >> files
+  cp -v -r $DIR $TMP_DIR
+done
+
+# Copy other files to the root of future XPI.
+for ROOT_FILE in $ROOT_FILES install.rdf chrome.manifest; do
+  cp -v $ROOT_FILE $TMP_DIR
+  if [ -f $ROOT_FILE ]; then
+    echo $ROOT_FILE >> files
+  fi
+done
+
+cd $TMP_DIR
+
+if [ -f "chrome.manifest" ]; then
+  echo "Preprocessing chrome.manifest..."
+  # You think this is scary?
+  #s/^(content\s+\S*\s+)(\S*\/)$/\1jar:chrome\/$APP_NAME\.jar!\/\2/
+  #s/^(skin|locale)(\s+\S*\s+\S*\s+)(.*\/)$/\1\2jar:chrome\/$APP_NAME\.jar!\/\3/
+  #
+  # Then try this! (Same, but with characters escaped for bash :)
+  #sed -i bak -E s/^\(content\\s+\\S*\\s+\)\(\\S*\\/\)$/\\1jar:chrome\\/$APP_NAME\\.jar!\\/\\2/ chrome.manifest
+  #sed -i bak -E s/^\(skin\|locale\)\(\\s+\\S*\\s+\\S*\\s+\)\(.*\\/\)$/\\1\\2jar:chrome\\/$APP_NAME\\.jar!\\/\\3/ chrome.manifest
+
+  # (it simply adds jar:chrome/whatever.jar!/ at appropriate positions of chrome.manifest)
+fi
+
+# generate the XPI file
+echo "Generating $APP_NAME.xpi..."
+zip -r ../$APP_NAME.xpi *
+
+cd $ROOT_DIR
+
+echo "Cleanup..."
+if [ $CLEAN_UP = 0 ]; then
+  # save the jar file
+  mv $TMP_DIR/chrome/$APP_NAME.jar .
+else
+  rm ./files
+fi
+
+# remove the working files
+rm -rf $TMP_DIR
+
+cp -v tv2developer.xpi /sites/jkkndk/www.jkkn.net/webroot/tv2developer/
+vi /sites/jkkndk/www.jkkn.net/webroot/tv2developer/update.rdf
+echo "Done!"
+
+$AFTER_BUILD
+
diff --git a/chrome.manifest b/chrome.manifest
new file mode 100755 (executable)
index 0000000..dcd0227
--- /dev/null
@@ -0,0 +1,6 @@
+content        tv2developer    jar:chrome/tv2developer.jar!/content/
+skin   tv2developer    classic/1.0     jar:chrome/tv2developer.jar!/skin/
+locale tv2developer    en-US   jar:chrome/tv2developer.jar!/locale/en-US/
+
+overlay        chrome://browser/content/browser.xul    chrome://tv2developer/content/browser_overlay.xul
+style chrome://global/content/customizeToolbar.xul chrome://tv2developer/skin/tv2developer.css
diff --git a/config_build.sh b/config_build.sh
new file mode 100755 (executable)
index 0000000..4507255
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# Build config for the build script, build.sh. Look there for more info.
+
+APP_NAME=tv2developer
+CHROME_PROVIDERS="content skin locale"
+CLEAN_UP=1
+ROOT_FILES=""
+ROOT_DIRS="defaults"
+BEFORE_BUILD=
+AFTER_BUILD=
diff --git a/content/about.xul b/content/about.xul
new file mode 100755 (executable)
index 0000000..e091aa3
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://tv2developer/locale/tv2developer.dtd">
+<dialog
+    id="tv2developer_about"
+       title="&aboutDialog.title;"
+       orient="vertical"
+       buttons="accept"
+       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<groupbox align="center" orient="horizontal">
+<vbox>
+  <text value="TV 2 Developer Plugin" style="font-weight: bold; font-size: x-large;"/>
+  <text value="&version; 0.4.14"/>
+  <separator class="thin"/>
+  <text value="&createdBy;" style="font-weight: bold;"/>
+  <text value="Kristian Kræmmer Nielsen &lt;jkkn@tv2.dk&gt;" class="url"
+        onclick="window.open('http://jkkn.dk/tv2developer/'); window.close();"/>
+  <separator class="thin"/>
+    <text value="&homePage;" style="font-weight: bold;"/>
+    <text value="http://jkkn.dk/tv2developer/"
+          class="url"
+        onclick="window.open('http://jkkn.dk/tv2developer/'); window.close();"/>
+  <separator class="thin"/>
+</vbox>
+<spring flex="1"/>
+<image src="chrome://tv2developer/skin/interaktiv_large.png"/>
+</groupbox>
+
+</dialog>
diff --git a/content/browser_overlay.xul b/content/browser_overlay.xul
new file mode 100755 (executable)
index 0000000..1b5b30a
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://tv2developer/skin/tv2developer.css" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://tv2developer/locale/tv2developer.dtd">
+
+<overlay id="tv2developer_overlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/x-javascript" src="tv2developer.js" />
+<stringbundleset id="stringbundleset">
+    <stringbundle id="tv2developer_strings" src="chrome://tv2developer/locale/tv2developer.properties"/>
+</stringbundleset>
+
+<keyset id="mainKeyset">
+    <key id="tv2-button-key" modifiers="alt" key="1" oncommand="TV2Developer.handleKeyShortcut(event)"/>
+</keyset>
+
+<toolbarpalette id="BrowserToolbarPalette">
+  <toolbarbutton id="tv2-swap-button" type="menu-button"
+                 accesskey="2"
+                 insertAfter="urlbar-container"
+                 label="tv2.dk"
+                 oncommand="TV2Developer.handleButton(event);"
+                 onclick="checkForMiddleClick(this, event);"
+                 onmouseover="TV2Developer.handleStatusText(event);"
+                 onmouseout="TV2Developer.setStatusText('');">
+    <menupopup context=""
+               id="tv2developer-popupmenu"
+               onpopupshowing="TV2Developer.fillMenu(event)"
+               oncommand="TV2Developer.handleMenu(event); event.stopPropagation();"
+               onmouseover="TV2Developer.handleStatusText(event);"
+               onmouseout="TV2Developer.setStatusText('');"
+               onclick="checkForMiddleClick(this, event);"/>
+  </toolbarbutton>
+</toolbarpalette>
+
+</overlay>
+
diff --git a/content/options.xul b/content/options.xul
new file mode 100755 (executable)
index 0000000..dc2c2a5
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE prefwindow SYSTEM "chrome://tv2developer/locale/tv2developer.dtd">
+
+<prefwindow id="tv2developer_options"
+            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+               title="&optionsDialog.title;">
+
+  <prefpane id="pane1" label="Options">
+    <preferences>
+      <preference id="pref_developer-initials" name="tv2developer.developer-initials" type="string"/>
+    </preferences>
+     
+    <groupbox title="Options" align="center" orient="horizontal">
+    <vbox>
+        <label control="developer-initials" value="&developerInitials.description;"/>
+        <textbox id="developer-initials" preference="pref_developer-initials"/>
+    </vbox>
+    </groupbox>
+  </prefpane>
+
+</prefwindow>
diff --git a/content/tv2developer.js b/content/tv2developer.js
new file mode 100755 (executable)
index 0000000..51c09e9
--- /dev/null
@@ -0,0 +1,501 @@
+// TV 2 Developer Plugin
+// Javascript Implementation
+// @author Kristian Kræmmer Nielsen <jkkn@tv2.dk>
+
+var TV2Developer = {
+    
+    _lastAction: null,
+    init: function() {
+        // init
+        this._lastAction = this.getPref('lastaction-linktype');
+        if (this.getPref('firstRun')) {
+            this.setPref('firstRun', false);
+            // add icon
+             try {
+               var firefoxnav = document.getElementById('nav-bar');
+               var curSet = firefoxnav.currentSet;
+               if (curSet.indexOf('tv2-swap-button') == -1)
+               {
+                 var set;
+                 // Place the button after the urlbar
+                 if (curSet.indexOf('urlbar-container') != -1)
+                   set = curSet.replace(/urlbar-container/, 'urlbar-container,tv2-swap-button');
+                 else // otherwise at the end
+                   set = firefoxnav.currentSet + ',tv2-swap-button';
+                 firefoxnav.setAttribute('currentset', set);
+                 firefoxnav.currentSet = set;
+                 document.persist('nav-bar', 'currentset');
+                 // If you don't do the following call, funny things happen
+                 try {
+                   BrowserToolboxCustomizeDone(true);
+                 }
+                 catch (e) { }
+               }
+             }
+             catch(e) { }
+        }
+    },
+
+    _strs: null,
+    get strs() {
+        if (!this._strs) {
+            
+            this._strs = document.getElementById('tv2developer_strings');
+        }
+        return this._strs;
+    },
+    
+    _prefs: null,
+    get prefs() {
+        if (!this._prefs)
+            this._prefs =
+                Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch('tv2developer.');
+        return this._prefs;
+    },
+
+    getPref: function(name, defValue) {
+        const CI=Components.interfaces.nsIPrefBranch;
+        const prefs=this.prefs;
+        try {
+          switch(prefs.getPrefType(name)) {
+            case CI.PREF_STRING:
+              return prefs.getCharPref(name);
+            case CI.PREF_INT:
+              return prefs.getIntPref(name);
+            case CI.PREF_BOOL:
+              return prefs.getBoolPref(name);
+          }
+        } catch(e) {alert(e)}
+        return defValue;
+    },
+  
+    setPref: function(name, value) {
+        const prefs=this.prefs;
+        switch(typeof(value)) {
+          case 'string':
+              prefs.setCharPref(name, value);
+              break;
+          case 'boolean':
+            prefs.setBoolPref(name, value);
+            break;
+          case 'number':
+            prefs.setIntPref(name, value);
+            break;
+          default:
+            throw new Error('Unsupported type '+typeof(value)+' for preference '+name);
+        }
+    },
+    
+    emptyMenu: function(menu) {
+      var children = menu.childNodes;
+      for (var i = children.length - 1; i >= 0; --i)
+        {
+          var index = children[i].getAttribute('tv2link');
+          if (index)
+            menu.removeChild(children[i]);
+        }
+    },
+    
+    TV2Link: function(type, domain, uri, flags) {
+        this.type = type;
+        this.label = domain; 
+        this.url = 'http://' + domain + uri;
+        this.disabled = false;
+        this.flags = (flags ? flags : '');
+    },
+    
+    TV2LinkSplit: function () {
+        this.type = 'split';
+    },
+
+    TV2LinkWithLabel: function(type, label, url, flags, disabled) {
+        this.type = type;
+        this.label = label; 
+        this.url = url;
+        this.disabled = typeof(disabled)!='undefined' ? disabled : false;
+        this.flags = (flags ? flags : '');
+    },
+
+    addMenuLink: function(menu, tv2link, defSet) {
+        var def = false;
+        var item;
+        if (tv2link.type == 'split') {
+            item = document.createElement('menuseparator');
+        } else {
+            item = document.createElement('menuitem');
+            item.setAttribute('label', tv2link.label); 
+            item.setAttribute('url', tv2link.url);
+            item.setAttribute('tooltiptext', tv2link.label);
+            item.setAttribute('disabled', tv2link.disabled);
+            item.setAttribute('tv2flags', tv2link.flags);
+            if (!defSet && tv2link.type == this._lastAction) {
+                item.setAttribute('style', 'font-weight: bold');
+                def = true;
+            }
+        }
+        item.setAttribute('tv2link', tv2link.type);
+        menu.appendChild(item);
+        return def;
+    },
+    
+    _reg_tv2: /^https?:\/\/([^/.]*)?([^/]*?)(\.(robot|opdatering2?|template)\.?)?(\.((test|snapshot)3?)\.)?tv2\.dk((\/[^#\?]*).*)?$/,
+    _reg_php: /^(.*\.php)/,
+    _reg_nodeid: /([0-9]{2,})/g,
+    _reg_i2files: /\/([0-9]+)-/,
+    //_reg_php5: /^(www|i2|common|ttvpumpe|1234|nyhederne)$/,
+    _reg_php5: /^(1234|i2|nyhederne)$/,
+    _reg_fromviewcvs: /^http:\/\/viewcvs\.tv2.dk:7467\/cgi-bin\/viewvc\.cgi\/([^/]+)\.tv2\.dk\/(webroot|robot|opdatering|template)([^#\?]+)/,
+    _reg_fromi2if: /^\/(tango\/(entry|requeue|dynamic)|tool\/pdo_log\/frameset)\.php\?url=([^&]+)/,
+    getLinks: function() {
+        var links = new Array();
+        var currentURL = getBrowser().currentURI.spec;
+        var encodedURL = encodeURIComponent(currentURL);
+        var initials = this.getPref('developer-initials');
+
+        // Adding links as appropiate if tv2.dk site
+        var tv2 = this._reg_tv2.exec(currentURL);
+        if (tv2) {
+            var skip_treenodes = false;
+            var tv2_sitename = tv2[1];
+            var tv2_user     = tv2[2];
+            var tv2_sitetype = tv2[4];
+            var tv2_testsite = tv2[6];
+            var tv2_testtype = tv2[7]; /* no 3 */
+            var tv2_uri      = tv2[8];
+            var tv2_uriOnly  = tv2[9]; // no parameters, anchers
+
+            // Strip -dyn and -static
+            if (tv2_sitename) tv2_sitename = tv2_sitename.replace(/-(dyn|static)$/, '');
+            if (tv2_user) tv2_user = tv2_user.replace(/^\./, '');
+            
+            // php5 sites
+            //var php5 = ((!tv2_sitename) || (this._reg_php5.test(tv2_sitename)));
+            var php5 = ((tv2_sitename) && (this._reg_php5.test(tv2_sitename)));
+            var testType = php5 ? '' : '3';
+            if (tv2_sitetype && tv2_sitetype == 'opdatering2') tv2_sitetype = 'opdatering';
+            
+            // Find live, test and snapshot url for current site
+            var liveurl;
+            var live_sitename = (tv2_sitename=='www') ? '' : tv2_sitename+'.';
+            var cvs_sitename = tv2_sitename ? tv2_sitename : 'www';
+
+            if (tv2_testsite) { // test or snapshot
+                if (tv2_sitetype) { /* opdatering, ... */
+                    liveurl = tv2_sitename+'.'+tv2_sitetype+'.tv2.dk';
+                } else {
+                    liveurl = live_sitename+'tv2.dk';
+                }
+            }
+            
+            var testprompturl = cvs_sitename+'.'+'?'+(tv2_sitetype?'.'+tv2_sitetype:'')+'.test'+testType+'.tv2.dk';
+            var testurl       = cvs_sitename+'.'+initials+(tv2_sitetype?'.'+tv2_sitetype:'')+'.test'+testType+'.tv2.dk';
+            var snapshoturl   = cvs_sitename+(tv2_sitetype?'.'+tv2_sitetype:'')+'.snapshot'+testType+'.tv2.dk';
+            
+            // Add the two urls we are not at
+            if (!tv2_testsite) { // always add swaps to snapshot and the test site
+                links.push(new this.TV2Link('test_live_swap', testurl, tv2_uri));
+                links.push(new this.TV2Link('snapshot_live_swap', snapshoturl, tv2_uri));
+                links.push(new this.TV2Link('testprompt_swap', testprompturl, tv2_uri, 'promptInitials'));
+            } else if (tv2_testtype == 'snapshot') {
+                links.push(new this.TV2Link('snapshot_live_swap', liveurl, tv2_uri));
+                links.push(new this.TV2Link('test_snapshot_swap', testurl, tv2_uri));
+                links.push(new this.TV2Link('testprompt_swap', testprompturl, tv2_uri, 'promptInitials'));
+            } else { // must be test
+                links.push(new this.TV2Link('test_live_swap', liveurl, tv2_uri));
+                links.push(new this.TV2Link('test_snapshot_swap', snapshoturl, tv2_uri));
+                if (tv2_user != initials) {
+                    links.push(new this.TV2Link('testprompt_swap', testurl, tv2_uri));
+                } else {
+                    links.push(new this.TV2Link('testprompt_swap', testprompturl, tv2_uri, 'promptInitials'));
+                }
+            }
+            
+            links.push(new this.TV2LinkSplit());
+            
+            // Add link to .opdatering, .template, .robot
+            var _prefix = cvs_sitename + (tv2_user ? '.' + tv2_user : '');
+            var _postfix = (tv2_testsite ? '.' + tv2_testsite : '') + '.tv2.dk';
+            var opdatering = _prefix + '.opdatering' + _postfix;
+            //var template = _prefix + '.template' + _postfix;
+            var robot = _prefix + '.robot' + _postfix;
+            var normal = (tv2_testsite ? _prefix + '.' + tv2_testsite + '.tv2.dk'
+                                       : live_sitename + 'tv2.dk');
+            links.push(new this.TV2Link('opdatering_swap', (tv2_sitetype!='opdatering')?opdatering:normal, '/'));
+            //links.push(new this.TV2Link('template_swap', (tv2_sitetype!='template')?template:normal, '/'));
+            links.push(new this.TV2Link('robot_swap', (tv2_sitetype!='robot')?robot:normal, '/'));
+            
+            links.push(new this.TV2LinkSplit());
+            
+            // Add the ViewCVS link, inspired by Adrian Bak (ADBA)
+            var viewcvs = 'http://viewcvs.tv2.dk:7467/cgi-bin/viewvc.cgi/'
+                        + cvs_sitename + '.tv2.dk/' + (tv2_sitetype?tv2_sitetype:'webroot');
+            var php = this._reg_php.exec(tv2_uriOnly);
+            if (php) {
+                viewcvs += php[1] + '?view=log';
+            } else if(tv2_uriOnly.substr(-1) == '/') {
+                // we add 'index.php' and say that's it! :-)
+                viewcvs += tv2_uriOnly + 'index.php' + '?view=log';
+            } else {
+                viewcvs += tv2_uriOnly;
+            }
+            // we set a nice type so we can swap between using the button (test<>viewcvs, live<>viewcvs,...)
+            var viewcvs_type;
+            if (!tv2_testsite) {
+                viewcvs_type = 'viewcvs_live';
+            } else if (tv2_testtype == 'snapshot') {
+                viewcvs_type = 'viewcvs_snapshot';
+            } else {
+                viewcvs_type = 'viewcvs_test';
+            }
+            links.push(new this.TV2LinkWithLabel(viewcvs_type, this.strs.getString('lookupInViewCVS'), viewcvs));
+
+            // Update and I2 base URL
+            var updatepostfix = (tv2_user ? '.' + tv2_user : '')
+                              + '.opdatering'
+                              + (tv2_testsite ? '.' + tv2_testsite : '2') + '.tv2.dk'
+            var i2link = 'http://i2' + updatepostfix;
+
+            // Check if we are on an Tango or I2 interface, then we can extract the URL again
+            var onI2interface;
+            var onI2interface_url;
+            if (tv2_sitetype == 'opdatering' && tv2_sitename == 'i2') {
+                var tangoif = this._reg_fromi2if.exec(tv2_uri);
+                if (tangoif) {
+                    onI2interface = tangoif[1];
+                    onI2interface_url = decodeURIComponent(tangoif[3]);
+                }
+            }
+            
+            // Add Tango lookup link
+            var i2tango = i2link + '/tango/entry.php?url=';
+            var tango = encodedURL;
+            var docWin = getBrowser().contentWindow;
+            if (docWin.wrappedJSObject && docWin.wrappedJSObject.Tango_URL) {
+                tango = encodeURIComponent(docWin.wrappedJSObject.Tango_URL);
+                links.push(new this.TV2LinkWithLabel('tango/dynamic', this.strs.getString('viewDynamicVersion'),
+                        i2link + '/tango/dynamic.php?url='+tango+'&referer='+encodedURL, 'flushCache'));
+            }
+            if (onI2interface != 'tango/entry' && onI2interface != 'tango/requeue') {
+                links.push(new this.TV2LinkWithLabel('tango/entry', this.strs.getString('lookupInTango'),
+                                i2link + '/tango/entry.php?url=' + tango));
+                links.push(new this.TV2LinkWithLabel('tango/requeue', this.strs.getString('requeueInTango'),
+                                i2link + '/tango/requeue.php?url=' + tango));
+            }
+            
+            // Add run pdo_log link
+            if (onI2interface != 'tool/pdo_log/frameset') {
+                links.push(new this.TV2LinkWithLabel('tool/pdo_log/frameset', this.strs.getString('performDbPdoLog'),
+                   i2link + '/tool/pdo_log/frameset.php?url='+tango+'&autostop=1&prefix='+initials, 'flushCache'));
+            }
+            
+            if (onI2interface_url) {
+                /* link entered in I2 interface */
+                links.push(new this.TV2LinkSplit());
+                /* tango/entry, tango/requeue, tango/dynamic, tool/pdo_log */
+                links.push(new this.TV2LinkWithLabel(onI2interface, onI2interface_url, onI2interface_url));
+            }
+         
+            // Some special cases for some sites 
+            if (tv2_sitename == 'ttv') {
+                links.push(new this.TV2LinkSplit());
+                var ttv_page = /side=([0-9]+)/.exec(tv2_uri);
+                if (ttv_page) {
+                    skip_treenodes = true;
+                    links.push(new this.TV2LinkWithLabel('ttvpage', this.strs.getString('lookupTTVPage') + ' ' + ttv_page[1],
+                                i2link + '/tool/ttv/?1=' + ttv_page[1] + '&2=0')); /* hardcoded to TV 2 TTV */
+                }
+                /*links.push(new this.TV2Link('ttvpumpe', 'ttvpumpe'+updatepostfix, '/'));*/
+                links.push(new this.TV2Link('ttvpumpe', 'ttvpumpe.opdatering.tv2.dk', '/'));
+            }
+            
+            // I2-Files and I2-Images
+            if (tv2_sitename == 'i2-files' || tv2_sitename == 'i2-images') {
+                var contentId = this._reg_i2files.exec(tv2_uriOnly);
+                if (contentId) {
+                    var typeId;
+                    var typeName;
+                    skip_treenodes = true;
+                    if (tv2_sitename == 'i2-files') {
+                        typeId = 74; // I2_File (and subtypes)
+                        typeName = 'I2_File';
+                    } else {
+                        if (tv2_uriOnly.substr(0,2)=='/s') {
+                            typeId = 8; typeName = 'I2_Image_Selection';
+                        } else {
+                            typeId = 7; typeName = ' I2_Image';
+                        }
+                    }
+                    links.push(new this.TV2LinkSplit());
+                    links.push(new this.TV2LinkWithLabel('i2files', this.strs.getString('lookupContent')+ ' ' + contentId[1] + ', ' +
+                        this.strs.getString('lookupContent.type') + ' ' + typeName,
+                        i2link + 
+                            '/tool/query/?id=&_checkbox=1&2=&3='+typeId+'&content_id='+contentId[1]+'&4=&5=0&6=&action=Query&timeout=1'));
+                }
+            }
+            
+            // Try to extract node id and add links to the node tool
+            if (!skip_treenodes) {
+                var i2node = i2link + '/tool/node/?id=';
+                var nodeids;
+                var first = true;
+                while ((nodeids = this._reg_nodeid.exec(tv2_uri)) != null) {
+                    if (first) {
+                        links.push(new this.TV2LinkSplit());
+                        first = false;
+                    }
+                    links.push(new this.TV2LinkWithLabel('node', this.strs.getString('lookupTreeNode') + ' ' + nodeids[1],
+                                i2node + nodeids[1]));
+               }
+            }
+            
+        } else {
+            
+            /* Add links to the site if viewing info at ViewCVS site */
+            var fromviewcvs = this._reg_fromviewcvs.exec(currentURL);
+            if (fromviewcvs) {
+                var tv2_sitename = fromviewcvs[1];
+                var tv2_sitetype = fromviewcvs[2];
+                var tv2_uri      = fromviewcvs[3];
+                
+                // cut off 'index.php'
+                if (tv2_uri.substr(-9) == 'index.php') {
+                    tv2_uri = tv2_uri.substr(0, tv2_uri.length-9);
+                }
+
+                // php5 sites
+                //var php5 = ((!tv2_sitename) || (this._reg_php5.test(tv2_sitename)));
+                var php5 = ((tv2_sitename) && (this._reg_php5.test(tv2_sitename)));
+                var testType = php5 ? '' : '3';
+
+                var live_sitename = (tv2_sitetype=='webroot' && tv2_sitename=='www') ? '': (tv2_sitename+'.');
+                var type = (tv2_sitetype=='webroot')? '' : tv2_sitetype+'.';
+                
+                links.push(new this.TV2Link('viewcvs_live', live_sitename + type + 'tv2.dk', tv2_uri));
+                links.push(new this.TV2Link('viewcvs_test', tv2_sitename + '.' + initials + '.' + type + 'test' + testType + '.tv2.dk', tv2_uri));
+                links.push(new this.TV2Link('viewcvs_snapshot', tv2_sitename + '.' + type + 'snapshot' + testType + '.tv2.dk', tv2_uri));
+                links.push(new this.TV2Link('viewcvs_testprompt', tv2_sitename + '.?.' + type + 'test' + testType + '.tv2.dk', tv2_uri, 'promptInitials'));
+                
+            } else {
+                links.push(new this.TV2LinkWithLabel('disabled', this.strs.getString('notTV2Site'), null, '', true));
+                links.push(new this.TV2LinkSplit());
+                links.push(new this.TV2Link('tv2dk', 'tv2.dk', '/'));
+            }
+        }
+        
+        // Utility links
+        links.push(new this.TV2LinkSplit());
+        links.push(new this.TV2LinkWithLabel('link_tree', this.strs.getString('i2Tree'), 'http://i2.opdatering2.tv2.dk/tree/'));
+        links.push(new this.TV2LinkWithLabel('node', this.strs.getString('nodeInformationTool'), 'http://i2.opdatering2.tv2.dk/tool/node/'));
+        links.push(new this.TV2LinkWithLabel('link_query', this.strs.getString('nodeQueryTool'), 'http://i2.opdatering2.tv2.dk/tool/query/'));
+        links.push(new this.TV2LinkWithLabel('tango/entry', this.strs.getString('tangoInterface'), 'http://i2.opdatering2.tv2.dk/tango/'));
+        links.push(new this.TV2LinkWithLabel('w3c', this.strs.getString('w3c'),
+            'http://validator.w3.org/check?uri=' + encodedURL));
+        return links;
+        
+    },
+    
+    fillMenu: function(event) {
+        var menu = event.target;
+        var links = this.getLinks();
+        this.emptyMenu(menu);
+
+        var defSet = false;
+        for (var i=0; i<links.length; i++) {
+            defSet |= this.addMenuLink(menu, links[i], defSet);
+        }
+    },
+    
+    handleMenu: function(event) {
+        var t = event.target;
+        this.gotoLink(event, t.getAttribute('url'),
+                             t.getAttribute('tv2link'),
+                             t.getAttribute('tv2flags'));
+    },
+    
+    getButtonAction: function() {
+        /* repeat last action or may hit a fall back link of same type */
+        var children = this.getLinks();
+        for (var i = 0; i < children.length; i++) {
+            if (children[i].type == this._lastAction) {
+                return children[i];
+            }
+        }
+        return null;
+    },
+        
+    handleButton: function(event) {
+        var action = this.getButtonAction();
+        if (action) {
+            this.gotoLink(event, action.url, action.type, action.flags);
+        } else {
+            event.target.open = true;
+        }
+    },
+    
+    setStatusText: function(text) {
+        var statusTextFld = document.getElementById("statusbar-display");
+        if (statusTextFld && statusTextFld.label != text) {
+            statusTextFld.label = text;
+        }
+    },
+
+    handleStatusText: function(event) {
+        var id = event.target.getAttribute('id');
+        if (id == 'tv2-swap-button') {
+            var action = this.getButtonAction();
+            var button = document.getElementById('tv2-swap-button');
+            if (action) {
+                button.setAttribute('tooltiptext', action.label);
+                this.setStatusText(action.url);
+            } else {
+                button.removeAttribute('tooltiptext');
+            }
+        } else {
+            var url = event.target.getAttribute('url');
+            if (url) {
+                this.setStatusText(url);
+            }
+        }
+    },
+    
+    handleKeyShortcut: function(event) {
+        document.getElementById('tv2-swap-button').open = true;
+    },
+
+    gotoLink: function(event, url, tv2linktype, tv2flags) {
+        if (url) {
+            /* handle flags */
+            if (tv2flags) {
+                 if (tv2flags.indexOf('promptInitials') != -1) {
+                    var initials = prompt(this._strs.getString('enterInitials'), this.getPref('alternativ-initials', ''));
+                    if (initials == '' || initials == null) {
+                        return; // cancelled
+                    }
+                    this.setPref('alternativ-initials', initials);
+                    url = url.replace('?', initials);
+                 }
+                 if (tv2flags.indexOf('flushCache') != -1) {
+                    this.clearCache();
+                }
+            }
+            /* follow link */            
+            openUILink(url, event, false, false, false); /* allow ctrl, alt, but don't google */
+            if (tv2linktype) {
+                this._lastAction = tv2linktype;
+                this.setPref('lastaction-linktype', tv2linktype);
+            }
+        }
+    },
+    
+    /* function to clear cache */
+    clearCache: function () {
+        var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
+                                     .getService(Components.interfaces.nsICacheService);
+        try {
+          cacheService.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
+        } catch(ex) {}
+    },
+
+}
+
+window.addEventListener("load", function(e) { TV2Developer.init(); }, false);
diff --git a/defaults/preferences/tv2developer.js b/defaults/preferences/tv2developer.js
new file mode 100755 (executable)
index 0000000..2c9bf72
--- /dev/null
@@ -0,0 +1,5 @@
+// Defaults
+
+pref('tv2developer.firstRun', true);
+pref('tv2developer.developer-initials', 'CHANGE-THIS');
+pref('tv2developer.lastaction-linktype', 'tango/entry');
diff --git a/install.rdf b/install.rdf
new file mode 100755 (executable)
index 0000000..97a0920
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+    
+    <Description about="urn:mozilla:install-manifest">
+    
+        <em:id>{17AB1CC5-F137-4697-9E48-D8C49AFC3B77}</em:id>
+        <em:name>TV 2 Developer Plugin</em:name>
+        <em:version>0.4.14</em:version>
+        <em:description>Adds a menu with tv2.dk development URLs depending on the tv2-page you are visting.</em:description>
+        <em:creator>Kristian Kræmmer Nielsen</em:creator>
+        <em:homepageURL>http://jkkn.dk/tv2developer/</em:homepageURL>
+        <em:iconURL>chrome://tv2developer/skin/tv2icon.png</em:iconURL>
+        <em:aboutURL>chrome://tv2developer/content/about.xul</em:aboutURL>
+        <em:optionsURL>chrome://tv2developer/content/options.xul</em:optionsURL>
+        <em:updateURL>http://jkkn.dk/tv2developer/update.rdf</em:updateURL>
+        
+        <em:targetApplication>
+            <Description>
+                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> 
+                <em:minVersion>1.5</em:minVersion>
+                <em:maxVersion>2.0.0.*</em:maxVersion>
+            </Description>
+        </em:targetApplication>
+        
+    </Description>
+
+</RDF>
diff --git a/locale/en-US/tv2developer.dtd b/locale/en-US/tv2developer.dtd
new file mode 100755 (executable)
index 0000000..88ba1dc
--- /dev/null
@@ -0,0 +1,8 @@
+<!ENTITY version "version">
+<!ENTITY aboutDialog.title "TV 2 Developer Plugin - about">
+<!ENTITY createdBy "Created By:">
+<!ENTITY homePage "Home Page:">
+
+<!ENTITY optionsDialog.title "TV 2 Developer Plugin - Options">
+<!ENTITY developerInitials.description "Enter your TV 2 initials (e.x. jkkn):">
+
diff --git a/locale/en-US/tv2developer.properties b/locale/en-US/tv2developer.properties
new file mode 100755 (executable)
index 0000000..c7c9086
--- /dev/null
@@ -0,0 +1,18 @@
+lookupInViewCVS=Lookup this page in ViewCVS
+viewDynamicVersion=View dynamic version of this page
+lookupInTango=Tango: Lookup this page
+requeueInTango=Tango: Open requeue
+performDbPdoLog=Examine database queries
+lookupTTVPage=Lookup TTV page
+lookupContent=Lookup content ID
+lookupContent.type=type
+lookupTreeNode=Lookup tree node with ID
+notTV2Site=Not a tv2.dk site
+
+i2Tree=I2 Tree
+nodeInformationTool=Node Information Tool
+nodeQueryTool=Node Query Tool
+tangoInterface=Tango Interface
+w3c=W3C Markup Validator
+
+enterInitials=Enter TV 2 initials (e.x. jkkn):
diff --git a/skin/interaktiv.png b/skin/interaktiv.png
new file mode 100755 (executable)
index 0000000..9c7530c
Binary files /dev/null and b/skin/interaktiv.png differ
diff --git a/skin/interaktiv_large.png b/skin/interaktiv_large.png
new file mode 100755 (executable)
index 0000000..9615e6c
Binary files /dev/null and b/skin/interaktiv_large.png differ
diff --git a/skin/tv2developer.css b/skin/tv2developer.css
new file mode 100755 (executable)
index 0000000..45c4bd6
--- /dev/null
@@ -0,0 +1,13 @@
+
+#tv2-swap-button {
+    list-style-image: url('interaktiv.png');
+    -moz-box-orient: vertical;
+}
+
+toolbar:not([iconsize="small"]) #tv2-swap-button .toolbarbutton-icon {
+    padding-top: 5px;
+}
+
+toolbar:not([iconsize="small"])[mode="icons"] #tv2-swap-button .toolbarbutton-icon {
+    padding-top: 0px;
+}
diff --git a/tv2developer.xpi b/tv2developer.xpi
new file mode 100644 (file)
index 0000000..ccb684e
Binary files /dev/null and b/tv2developer.xpi differ