Skip to content

Instantly share code, notes, and snippets.

@bpierre
Created January 13, 2011 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpierre/777905 to your computer and use it in GitHub Desktop.
Save bpierre/777905 to your computer and use it in GitHub Desktop.
To fix the "disappearing background images and @font-face" bug in the "edit CSS" feature of the Web Developer Toolbar Firefox Addon. See instructions below.
var webdeveloper_editCSSIntervalId = null;
var webdeveloper_editCSSOldStyleText = new Array();
var webdeveloper_editCSSSelectedTab = 0;
var webdeveloper_editCSSUpdateFrequency = 500;
// Applies the CSS
function webdeveloper_applyCSS()
{
var contentDocument = webdeveloper_getContentDocument();
var headElement = webdeveloper_getDocumentHeadElement(contentDocument);
var styleElement = null;
var styleText = null;
var textBox = null;
var textBoxes = document.getElementById("webdeveloper-edit-css-tab-panels").getElementsByTagName("textbox");
var textBoxesLength = textBoxes.length;
// Loop through the text boxes
for(var i = 0; i < textBoxesLength; i++)
{
styleElement = contentDocument.getElementById("webdeveloper-edit-css-style-" + i);
textBox = textBoxes[i];
styleText = textBox.value;
styleDomain = textBox.getAttribute("webdeveloper-domain");
stylePath = textBox.getAttribute("webdeveloper-base");
// Replace absolute (root) URLs
styleText = styleText.replace(/url\((["']?)(\/[^"'\)]+)\1\)/g, 'url('+ styleDomain +'$2)');
// Relpace relative URLs
styleText = styleText.replace(/url\((["']?)(?!https?:\/\/)([^"'\)]+)\1\)/g, 'url('+ styleDomain + stylePath +'$2)');
// If the strip import preference is not set or is set to true
if(!webdeveloper_isPreferenceSet("webdeveloper.edit.css.import.strip") || webdeveloper_getBooleanPreference("webdeveloper.edit.css.import.strip", true))
{
styleText = styleText.replace(new RegExp("@import.*?;", "gi"), "");
}
// If the style element does not exist
if(!styleElement)
{
styleElement = contentDocument.createElement("style");
styleElement.setAttribute("id", "webdeveloper-edit-css-style-" + i);
styleElement.setAttribute("type", "text/css");
styleElement.setAttribute("xml:base", styleDomain + stylePath);
headElement.appendChild(styleElement);
// Make the styles different to make sure they get written if not there already
webdeveloper_editCSSOldStyleText[i] = styleText + " ";
}
// If the style text is not the same as the old style text
if(styleText != webdeveloper_editCSSOldStyleText[i])
{
webdeveloper_editCSSOldStyleText[i] = styleText;
webdeveloper_removeAllChildElements(styleElement);
styleElement.appendChild(contentDocument.createTextNode(styleText));
}
}
}
// Clear the CSS
function webdeveloper_clearCSS()
{
webdeveloper_getSelectedPanel().firstChild.value = "";
}
// Reinitializes the dashboard when the page changes
function webdeveloper_editCSSPageLoad(event)
{
// If the content document is set
if(webdeveloper_getPageLoadEventContentDocument(event) && !webdeveloper_getBooleanPreference("webdeveloper.edit.stick", true))
{
webdeveloper_resetCSS();
}
}
// Handles a browser tab being selected
function webdeveloper_editCSSTabSelect(event)
{
var browser = window.top.getBrowser();
var selectedTab = browser.mTabBox.selectedIndex;
// If the selected tab is different
if(selectedTab != webdeveloper_editCSSSelectedTab)
{
var browsers = browser.browsers;
var browserLength = browsers.length;
// If the previous selected tab equals the browser length
if(webdeveloper_editCSSSelectedTab == browserLength)
{
webdeveloper_editCSSSelectedTab = browserLength - 1;
}
webdeveloper_resetDocument(browsers[webdeveloper_editCSSSelectedTab].contentDocument);
webdeveloper_editCSSSelectedTab = selectedTab;
// If the CSS stick preference is not set to true
if(!webdeveloper_getBooleanPreference("webdeveloper.edit.stick", true))
{
webdeveloper_resetCSS();
}
}
}
// Returns the selected panel
function webdeveloper_getSelectedPanel()
{
var selectedPanel = document.getElementById("webdeveloper-edit-css-tab-box").selectedPanel;
// If the selected panel is not set
if(!selectedPanel)
{
selectedPanel = document.getElementById("webdeveloper-edit-css-tab-panels").firstChild;
}
return selectedPanel;
}
// Returns the selected tab
function webdeveloper_getSelectedTab()
{
var selectedTab = document.getElementById("webdeveloper-edit-css-tab-box").selectedTab;
// If the selected tab is not set
if(!selectedTab)
{
selectedTab = document.getElementById("webdeveloper-edit-css-tabs").firstChild;
}
return selectedTab;
}
// Initializes the edit CSS dashboard
function webdeveloper_initializeEditCSS()
{
var windowContent = window.top.getBrowser();
// If the window content is set
if(windowContent)
{
var tabBox = windowContent.mTabBox;
webdeveloper_editCSSSelectedTab = tabBox.selectedIndex;
webdeveloper_editCSSUpdateFrequency = webdeveloper_getIntegerPreference("webdeveloper.edit.update.frequency", true);
document.getElementById("webdeveloper-search-dashboard-text").addEventListener("keypress", webdeveloper_searchTextKeyPress, false);
windowContent.addEventListener("load", webdeveloper_editCSSPageLoad, true);
// If the tab box is set
if(tabBox)
{
tabBox.addEventListener("select", webdeveloper_editCSSTabSelect, false);
}
webdeveloper_updateStickCSS();
webdeveloper_retrieveCSS();
// If the update frequency is greater than 0
if(webdeveloper_editCSSUpdateFrequency > 0)
{
webdeveloper_editCSSIntervalId = window.setInterval(webdeveloper_applyCSS, webdeveloper_editCSSUpdateFrequency);
}
}
}
// Opens new CSS
function webdeveloper_openCSS()
{
var filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
var stringBundle = document.getElementById("webdeveloper-string-bundle");
filePicker.appendFilter(stringBundle.getString("webdeveloper_styleSheetDescription"), "*.css");
filePicker.init(window, stringBundle.getString("webdeveloper_openStyleSheet"), filePicker.modeOpen);
// If the user selected a style sheet
if(filePicker.show() == filePicker.returnOK)
{
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
var scriptableStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
inputStream.init(filePicker.file, 0x01, 00444, null);
scriptableStream.init(inputStream);
webdeveloper_getSelectedPanel().firstChild.value = scriptableStream.read(scriptableStream.available());
scriptableStream.close();
inputStream.close();
}
}
// Resets the edited CSS
function webdeveloper_resetCSS()
{
webdeveloper_removeAllChildElements(document.getElementById("webdeveloper-edit-css-tab-panels"));
webdeveloper_removeAllChildElements(document.getElementById("webdeveloper-edit-css-tabs"));
webdeveloper_resetDocument(webdeveloper_getContentDocument());
webdeveloper_retrieveCSS();
}
// Resets the specified document
function webdeveloper_resetDocument(contentDocument)
{
var styleElement = null;
var styleElements = contentDocument.getElementsByTagName("style");
var styleSheet = null;
var styleSheetList = webdeveloper_getStyleSheetsForDocument(contentDocument, true, false);
var styleSheetLength = styleSheetList.length;
// Loop through the style elements
for(var i = 0; i < styleElements.length; i++)
{
styleElement = styleElements[i];
// If the style element has an id starting with webdeveloper-edit-css-style-
if(styleElement.hasAttribute("id") && styleElement.getAttribute("id").indexOf("webdeveloper-edit-css-style-") == 0)
{
webdeveloper_removeElement(styleElement);
i--;
}
}
// Loop through the style sheets
for(i = 0; i < styleSheetLength; i++)
{
styleSheet = styleSheetList[i];
// If the style sheet is a valid style sheet, is for the screen and is not an alternate style sheet
if(webdeveloper_isValidStyleSheet(styleSheet) && webdeveloper_isMediaStyleSheet(styleSheet, "screen") && !webdeveloper_isAlternateStyleSheet(styleSheet))
{
styleSheet.disabled = false;
}
}
}
// Retrieves the CSS from the current page
function webdeveloper_retrieveCSS()
{
var contentDocument = webdeveloper_getContentDocument();
var documentURL = contentDocument.documentURI;
var inlineStylesText = "";
var result = null;
var results = new Array();
var resultsLength = null;
var stringBundle = document.getElementById("webdeveloper-string-bundle");
var styleElement = null;
var styleSheet = null;
var styleSheetList = webdeveloper_getStyleSheetsForDocument(contentDocument, true, false);
var styleSheetLength = styleSheetList.length;
var tab = null;
var tabPanel = null;
var tabs = document.getElementById("webdeveloper-edit-css-tabs");
var tabPanels = document.getElementById("webdeveloper-edit-css-tab-panels");
var textBox = null;
var textBoxStyle = "";
var url = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURL);
url.spec = documentURL;
// If the edit background color preference is set
if(webdeveloper_isPreferenceSet("webdeveloper.edit.color.background"))
{
textBoxStyle += "background-color: " + webdeveloper_getStringPreference("webdeveloper.edit.color.background", true) + " !important; ";
}
// If the edit text color preference is set
if(webdeveloper_isPreferenceSet("webdeveloper.edit.color.text"))
{
textBoxStyle += "color: " + webdeveloper_getStringPreference("webdeveloper.edit.color.text", true) + " !important; ";
}
// If the edit font preference is set
if(webdeveloper_isPreferenceSet("webdeveloper.edit.font.size"))
{
textBoxStyle += "font-size: " + webdeveloper_getIntegerPreference("webdeveloper.edit.font.size", true) + "px !important; ";
}
textBoxStyle = webdeveloper_trim(textBoxStyle);
// Loop through the style sheets
for(var i = 0; i < styleSheetLength; i++)
{
styleSheet = styleSheetList[i];
// If this is a valid style sheet, is for the screen, is not an alternate style sheet, is not disabled and is not an inline style sheet
if(webdeveloper_isValidStyleSheet(styleSheet) && webdeveloper_isMediaStyleSheet(styleSheet, "screen") && !webdeveloper_isAlternateStyleSheet(styleSheet) && !styleSheet.disabled && styleSheet.href && styleSheet.href != documentURL)
{
results = webdeveloper_retrieveStyleSheetDetails(styleSheet, textBoxStyle, results);
}
}
styleSheetList = contentDocument.getElementsByTagName("style");
styleSheetLength = styleSheetList.length;
// Loop through the inline style sheets
for(i = 0; i < styleSheetLength; i++)
{
styleElement = styleSheetList[i];
styleSheet = styleElement.sheet;
// If this is a valid style sheet, is for the screen and is not disabled
if(webdeveloper_isValidStyleSheet(styleSheet) && (!styleElement.hasAttribute("id") || styleElement.getAttribute("id").indexOf("webdeveloper-") != 0) && webdeveloper_isMediaStyleSheet(styleSheet, "screen") && !styleSheet.disabled)
{
inlineStylesText += webdeveloper_trim(styleElement.innerHTML) + "\n\n";
styleSheet.disabled = true;
}
}
// If there are inline styles
if(inlineStylesText != "")
{
tab = document.createElement("tab");
tabPanel = document.createElement("tabpanel");
textBox = document.createElement("textbox");
tab.setAttribute("label", stringBundle.getString("webdeveloper_embeddedStyles"));
textBox.setAttribute("flex", "1");
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
textBox.setAttribute("value", inlineStylesText);
textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
if(!webdeveloper_getBooleanPreference("webdeveloper.edit.wrap", true))
{
textBox.setAttribute("wrap", "off");
}
tabPanel.appendChild(textBox);
results.push(new Array(tab, tabPanel));
}
resultsLength = results.length;
// Loop through the results
for(i = 0; i < resultsLength; i++)
{
result = results[i];
tabPanels.appendChild(result[1]);
tabs.appendChild(result[0]);
}
// If there are no tabs
if(tabs.childNodes.length == 0)
{
tab = document.createElement("tab");
tabPanel = document.createElement("tabpanel");
textBox = document.createElement("textbox");
tab.setAttribute("label", stringBundle.getString("webdeveloper_editCSS"));
textBox.setAttribute("flex", "1");
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
if(!webdeveloper_getBooleanPreference("webdeveloper.edit.wrap", true))
{
textBox.setAttribute("wrap", "off");
}
tabPanel.appendChild(textBox);
tabPanels.appendChild(tabPanel);
tabs.appendChild(tab);
}
tabs.selectedIndex = 0;
webdeveloper_applyCSS();
}
// Retrieves the style sheet details
function webdeveloper_retrieveStyleSheetDetails(styleSheet, textBoxStyle, results)
{
var styleSheetHref = styleSheet.href;
var position = styleSheetHref.lastIndexOf("/");
var stylesText = webdeveloper_retrieveSource(styleSheetHref);
var tab = document.createElement("tab");
var tabPanel = document.createElement("tabpanel");
var textBox = document.createElement("textbox");
var url = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURL);
url.spec = styleSheetHref;
tab.setAttribute("label", url.fileName);
textBox.setAttribute("flex", "1");
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
textBox.setAttribute("value", stylesText);
textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
if(!webdeveloper_getBooleanPreference("webdeveloper.edit.wrap", true))
{
textBox.setAttribute("wrap", "off");
}
tabPanel.appendChild(textBox);
results.push(new Array(tab, tabPanel));
styleSheet.disabled = true;
return results;
}
// Saves the CSS
function webdeveloper_saveCSS()
{
var filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
var result = null;
var stringBundle = document.getElementById("webdeveloper-string-bundle");
var styleText = webdeveloper_getSelectedPanel().firstChild.value;
filePicker.defaultExtension = "css";
filePicker.defaultString = webdeveloper_getSelectedTab().getAttribute("label");
filePicker.appendFilter(stringBundle.getString("webdeveloper_styleSheetDescription"), "*.css");
filePicker.init(window, stringBundle.getString("webdeveloper_saveStyleSheet"), filePicker.modeSave);
result = filePicker.show();
// If the user selected a style sheet
if(result == filePicker.returnOK || result == filePicker.returnReplace)
{
var file = filePicker.file;
var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
// If the file does not exist
if(!file.exists())
{
file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 00644);
}
outputStream.init(file, 0x04 | 0x08 | 0x20, 00644, null);
outputStream.write(styleText, styleText.length);
outputStream.close();
}
}
// Searches the CSS
function webdeveloper_searchCSS()
{
var searchText = document.getElementById("webdeveloper-search-dashboard-text").value;
// If the search text is set
if(searchText)
{
webdeveloper_getSelectedPanel().firstChild.focus();
// If the search failed to find a match
if(!window.find(searchText, false, false, true, false, false, false))
{
webdeveloper_getSelectedPanel().firstChild.setSelectionRange(0, 0);
window.find(searchText, false, false, true, false, false, false);
}
}
}
// Searches the CSS when the enter key is pressed
function webdeveloper_searchTextKeyPress(event)
{
var keyCode = event.keyCode;
// If the key code is set and is 13
if(keyCode && keyCode == 13)
{
webdeveloper_searchCSS();
}
}
// Toggles sticking the CSS
function webdeveloper_toggleStickCSS()
{
webdeveloper_setBooleanPreference("webdeveloper.edit.stick", !webdeveloper_getBooleanPreference("webdeveloper.edit.stick", true));
webdeveloper_updateStickCSS();
}
// Uninitializes edit CSS
function webdeveloper_uninitializeEditCSS()
{
var windowContent = window.top.getBrowser();
webdeveloper_editCSSOldStyleText = new Array();
webdeveloper_resetDocument(webdeveloper_getContentDocument());
window.clearInterval(webdeveloper_editCSSIntervalId);
// Try to remove the event listener
try
{
document.getElementById("webdeveloper-search-dashboard-text").removeEventListener("keypress", webdeveloper_searchTextKeyPress, false);
}
catch(exception)
{
// Do nothing
}
// If the window content is set
if(windowContent)
{
var tabBox = windowContent.mTabBox;
// Try to remove the event listener
try
{
windowContent.removeEventListener("load", webdeveloper_editCSSPageLoad, true);
}
catch(exception)
{
// Do nothing
}
// If the tab box is set
if(tabBox)
{
// Try to remove the event listener
try
{
tabBox.removeEventListener("select", webdeveloper_editCSSTabSelect, false);
}
catch(exception)
{
// Do nothing
}
}
}
}
// Updates the stick CSS button
function webdeveloper_updateStickCSS()
{
var element = document.getElementById("webdeveloper-stick-dashboard");
var labelValue = null;
var stick = webdeveloper_getBooleanPreference("webdeveloper.edit.stick", true);
var stringBundle = document.getElementById("webdeveloper-string-bundle");
// If the element exists
if(element)
{
// If sticking the CSS
if(stick)
{
labelValue = stringBundle.getString("webdeveloper_unstick");
element.setAttribute("class", "unstick webdeveloper-dashboard-button");
}
else
{
labelValue = stringBundle.getString("webdeveloper_stick");
element.setAttribute("class", "webdeveloper-dashboard-button");
}
element.setAttribute("tooltiptext", labelValue);
}
}
--- edit_css-original.js 2011-01-05 10:41:32.000000000 +0100
+++ edit_css.js 2011-01-13 14:16:26.000000000 +0100
@@ -20,7 +20,15 @@
styleElement = contentDocument.getElementById("webdeveloper-edit-css-style-" + i);
textBox = textBoxes[i];
styleText = textBox.value;
+ styleDomain = textBox.getAttribute("webdeveloper-domain");
+ stylePath = textBox.getAttribute("webdeveloper-base");
+ // Replace absolute (root) URLs
+ styleText = styleText.replace(/url\((["']?)(\/[^"'\)]+)\1\)/g, 'url('+ styleDomain +'$2)');
+
+ // Relpace relative URLs
+ styleText = styleText.replace(/url\((["']?)(?!https?:\/\/)([^"'\)]+)\1\)/g, 'url('+ styleDomain + stylePath +'$2)');
+
// If the strip import preference is not set or is set to true
if(!webdeveloper_isPreferenceSet("webdeveloper.edit.css.import.strip") || webdeveloper_getBooleanPreference("webdeveloper.edit.css.import.strip", true))
{
@@ -34,7 +42,7 @@
styleElement.setAttribute("id", "webdeveloper-edit-css-style-" + i);
styleElement.setAttribute("type", "text/css");
- styleElement.setAttribute("xml:base", textBox.getAttribute("webdeveloper-base"));
+ styleElement.setAttribute("xml:base", styleDomain + stylePath);
headElement.appendChild(styleElement);
// Make the styles different to make sure they get written if not there already
@@ -315,6 +323,7 @@
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
textBox.setAttribute("value", inlineStylesText);
+ textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
@@ -349,6 +358,7 @@
textBox.setAttribute("flex", "1");
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
+ textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
@@ -385,6 +395,7 @@
textBox.setAttribute("multiline", "true");
textBox.setAttribute("style", textBoxStyle);
textBox.setAttribute("value", stylesText);
+ textBox.setAttribute("webdeveloper-domain", url.scheme + "://" + url.host + ((url.port !== -1)? ":" + url.port : ""));
textBox.setAttribute("webdeveloper-base", url.directory);
// If the edit CSS wrap preference is not set to true
@bpierre
Copy link
Author

bpierre commented Jan 13, 2011

  • Rename /chrome/webdeveloper.jar to /chrome/webdeveloper.zip
  • Unzip its content to /chrome/webdeveloper
  • Open the file /chrome/webdeveloper/content/webdeveloper/dashboard/edit_css.js.
  • Apply the patch (edit_css.js.patch) or just replace it with the new one (edit_css.js).
  • Zip the /chrome/webdeveloper subdirectories, name it /chrome/webdeveloper.jar
  • Restart Firefox

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment