Skip to content

Instantly share code, notes, and snippets.

@mmastrac
Created July 5, 2020 19:12
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 mmastrac/6d148c42fe4db832025aa05ef8dbaed1 to your computer and use it in GitHub Desktop.
Save mmastrac/6d148c42fe4db832025aa05ef8dbaed1 to your computer and use it in GitHub Desktop.
var Stylus = {
inject: function(what, loadCallback) {
return createInjector(what, loadCallback);
},
};
var STYLUS_STATUS_ID = '__STYLUS_style_el';
var Injector = function() {};
Injector.prototype = {
remove: function() {
throw "remove() is not yet implemented";
},
_trackLoad: function(elem, cb) {
var self = this;
elem.addEventListener('load', function() {
self._inject(cb());
});
elem.addEventListener('DOMContentLoaded', function() {
self._inject(cb());
});
self._inject(cb());
},
_inject: function(doc) {
if (!doc || doc === this._currentDoc) {
return;
}
this._currentDoc = doc;
if (this._loadCallback) {
try {
this._loadCallback(doc);
} catch (e) {
console.log("Load callback failure", e);
}
}
this._refreshCss(doc);
},
_refreshCss: function(doc) {
var self = this;
if (!doc || doc !== this._currentDoc) {
console.log("Document is no longer valid, stopping updates.");
return;
}
var wnd = doc.defaultView;
// Figure out if we've already injected a style
var old = doc.getElementById(STYLUS_STATUS_ID);
// Create our new, pending style (use the XHTML namespace for SVG + HTML)
var css = doc.createElementNS('http://www.w3.org/1999/xhtml', 'link');
css.rel = "stylesheet";
css.href = "/style.css?t=" + new Date().valueOf();
css.onload = function() {
if (old) {
old.remove();
}
css.id = STYLUS_STATUS_ID;
wnd.setTimeout(function() {
self._refreshCss(doc);
}, 1000);
}
css.onerror = function() {
css.remove();
wnd.setTimeout(function() {
self._refreshCss(doc);
}, 1000);
}
if (old) {
// Place the new style next to the old one if it exists
old.insertAdjacentElement("afterend", css);
} else {
// Otherwise insert a new element
var parent = (doc.head || doc.body || doc.documentElement);
if (parent) {
console.log("Inserting new CSS link, parent = " + parent.tagName + " namespace = " + parent.namespaceURI);
parent.appendChild(css);
} else {
throw "Invalid parent element";
}
}
}
};
function createInjector(what, loadCallback) {
var injector = new Injector();
injector._loadCallback = loadCallback;
if (!what) {
throw "Invalid null argument to createInjector";
}
if (what instanceof HTMLElement) {
if (what.tagName === "OBJECT" || what.tagName === "IFRAME") {
injector._trackLoad(what, function() { return what.contentDocument; });
return injector;
}
}
if (what instanceof HTMLDocument) {
injector._inject(what);
return injector;
}
if (what instanceof Window && what.document) {
injector._inject(what.document);
return injector;
}
throw "Invalid argument to createInjector: must be a document/window or an <OBJECT>/<IFRAME> element";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment