forked from enviPath/enviPy
Current Dev State
This commit is contained in:
244
static/js/ketcher2/node_modules/reload-css/index.js
generated
vendored
Normal file
244
static/js/ketcher2/node_modules/reload-css/index.js
generated
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
var qs = require('query-string');
|
||||
var URL = require('./lib/url');
|
||||
var baseHosts = getBaseHosts();
|
||||
|
||||
module.exports = function (url, opt) {
|
||||
// by default, only reloads local style sheets
|
||||
var localOnly = true;
|
||||
if (opt && opt.local === false) {
|
||||
localOnly = false;
|
||||
}
|
||||
|
||||
// determine base URL
|
||||
var baseUrl = document.location.pathname;
|
||||
var baseTag = document.querySelector('base');
|
||||
if (baseTag) {
|
||||
baseUrl = baseTag.getAttribute('href');
|
||||
var parsedBase = URL.parse(baseUrl);
|
||||
parsedBase.pathname = '/';
|
||||
parsedBase.hash = null;
|
||||
parsedBase.query = null;
|
||||
parsedBase.search = null;
|
||||
baseUrl = URL.format(parsedBase);
|
||||
}
|
||||
|
||||
// Find all <link> and <style> tags
|
||||
var nodes = [ 'link', 'style' ]
|
||||
.map(elements)
|
||||
.reduce(function (a, b) {
|
||||
return a.concat(b);
|
||||
}, [])
|
||||
.filter(function (el) {
|
||||
return filterStyleSheet(el, localOnly);
|
||||
})
|
||||
.map(function (el) {
|
||||
var data = {
|
||||
element: el
|
||||
};
|
||||
var href = el.getAttribute('href');
|
||||
if (el.tagName === 'LINK' && href) {
|
||||
data.key = URL.key(href, baseUrl);
|
||||
}
|
||||
return data;
|
||||
});
|
||||
|
||||
// Now gather all imports in those tags
|
||||
var imports = [];
|
||||
nodes.forEach(function (node) {
|
||||
recursiveFindImports(node, node.element.sheet, imports, baseUrl);
|
||||
});
|
||||
|
||||
// Now try to update the matched URLs
|
||||
var keyToMatch = url ? URL.key(url, baseUrl) : null;
|
||||
var matchImports = imports;
|
||||
if (keyToMatch) {
|
||||
// only match target imports
|
||||
matchImports = matchImports.filter(function (imported) {
|
||||
return imported.key === keyToMatch;
|
||||
});
|
||||
}
|
||||
|
||||
// Map them to the "top most" import that needs update
|
||||
// This isn't actually the root, just the most shallow
|
||||
// style sheet we need to update for it to work in Chrome/FF/Safari
|
||||
// (Chrome has an issue where updating a deep import will break)
|
||||
matchImports = matchImports.map(getTopmostImport);
|
||||
|
||||
// Filter out any potential duplicate top most imports
|
||||
// And reverse so we update deep to shallow
|
||||
matchImports = uniq(matchImports).reverse();
|
||||
|
||||
// Now cache bust each import
|
||||
matchImports.forEach(bust);
|
||||
|
||||
// Now find any URLs referenced by a <link> tag
|
||||
var matchLinks = nodes.filter(function (node) {
|
||||
// no keyToMatch just means bust all link tags
|
||||
var isMatch = keyToMatch
|
||||
? node.key === keyToMatch
|
||||
: true;
|
||||
return node.element.tagName === 'LINK' && isMatch;
|
||||
});
|
||||
|
||||
// And re-attach each link tag
|
||||
matchLinks.forEach(function (node) {
|
||||
node.element = reattachLink(node.element);
|
||||
});
|
||||
};
|
||||
|
||||
function bust (imported) {
|
||||
if (!imported.busted) {
|
||||
imported.rule = cacheBustImportRule(imported.rule, imported.index);
|
||||
}
|
||||
imported.busted = true;
|
||||
return imported;
|
||||
}
|
||||
|
||||
function reattachLink (link, cb) {
|
||||
var href = link.getAttribute('href');
|
||||
|
||||
var cloned = link.cloneNode(false);
|
||||
cloned.href = getCacheBustUrl(href);
|
||||
|
||||
var parent = link.parentNode;
|
||||
if (parent.lastChild === link) {
|
||||
parent.appendChild(cloned);
|
||||
} else {
|
||||
parent.insertBefore(cloned, link.nextSibling);
|
||||
}
|
||||
|
||||
cloned.onload = function () {
|
||||
if (link.parentNode) link.parentNode.removeChild(link);
|
||||
if (cb) cb();
|
||||
};
|
||||
return cloned;
|
||||
}
|
||||
|
||||
function filterStyleSheet (element, localOnly) {
|
||||
if (isPrintMedia(element)) return false;
|
||||
if (element.tagName === 'LINK') {
|
||||
if (!element.getAttribute('href')) return false;
|
||||
if (localOnly && !isLocalStylesheet(element)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isLocalStylesheet (link) {
|
||||
var href = link.getAttribute('href');
|
||||
if (!href || link.getAttribute('rel') !== 'stylesheet') return false;
|
||||
var parsed = URL.parse(href);
|
||||
if (parsed.protocol && parsed.protocol !== window.document.location.protocol) {
|
||||
// different protocol, let's assume not local
|
||||
return false;
|
||||
}
|
||||
if (parsed.host) {
|
||||
// see if domain matches
|
||||
return baseHosts.indexOf(parsed.host.toLowerCase()) >= 0;
|
||||
}
|
||||
// no host / protocol... assume relative and thus local
|
||||
return true;
|
||||
}
|
||||
|
||||
function uniq (list) {
|
||||
var result = [];
|
||||
list.forEach(function (item) {
|
||||
if (result.indexOf(item) === -1) {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function isPrintMedia (link) {
|
||||
return link.getAttribute('media') === 'print';
|
||||
}
|
||||
|
||||
function elements (tag) {
|
||||
return Array.prototype.slice.call(document.getElementsByTagName(tag));
|
||||
}
|
||||
|
||||
function getBaseHosts () {
|
||||
var baseHosts = [
|
||||
'localhost', '127.0.0.1'
|
||||
].map(function (h) {
|
||||
return h + ':' + window.document.location.port;
|
||||
});
|
||||
|
||||
// handle current
|
||||
if (window.document.location.hostname !== 'localhost') {
|
||||
baseHosts = baseHosts.concat([ window.document.location.host ]);
|
||||
}
|
||||
|
||||
// normalize case
|
||||
return baseHosts.map(function (h) {
|
||||
return h.toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
function cacheBustImportRule (rule, index) {
|
||||
var parent = rule.parentStyleSheet;
|
||||
var newHref = getCacheBustUrl(rule.href);
|
||||
|
||||
var media = '';
|
||||
try {
|
||||
media = rule.media.length
|
||||
? Array.prototype.join.call(rule.media, ', ')
|
||||
: '';
|
||||
} catch (err) {
|
||||
// might get here if permission is denied for some reason
|
||||
}
|
||||
|
||||
var newRule = '@import url("' + newHref + '") ' + media + ';';
|
||||
parent.insertRule(newRule, index);
|
||||
parent.deleteRule(index + 1);
|
||||
return parent.cssRules[index];
|
||||
}
|
||||
|
||||
function getTopmostImport (imported) {
|
||||
var topmost = imported;
|
||||
while (topmost.parentImport) {
|
||||
topmost = topmost.parentImport;
|
||||
}
|
||||
return topmost;
|
||||
}
|
||||
|
||||
function recursiveFindImports (node, styleSheet, result, baseUrl, lastImport) {
|
||||
if (!styleSheet) return;
|
||||
var rules;
|
||||
try {
|
||||
rules = styleSheet.cssRules;
|
||||
} catch (err) {
|
||||
// some sort of security error
|
||||
}
|
||||
if (!rules || rules.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (rule.type === window.CSSRule.IMPORT_RULE) {
|
||||
var parentHref = rule.parentStyleSheet.href || document.location.href;
|
||||
var absoluteHref = URL.resolve(parentHref, rule.href);
|
||||
var key = URL.key(absoluteHref, baseUrl);
|
||||
|
||||
var newImport = {
|
||||
index: i,
|
||||
rule: rule,
|
||||
parentImport: lastImport,
|
||||
key: key,
|
||||
href: rule.href
|
||||
};
|
||||
result.push(newImport);
|
||||
recursiveFindImports(node, rule.styleSheet, result, baseUrl, newImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCacheBustUrl (href) {
|
||||
var parsed = URL.parse(href);
|
||||
var qsObj = qs.parse(parsed.search);
|
||||
qsObj._livereload = String(Date.now());
|
||||
parsed.query = undefined;
|
||||
parsed.search = qs.stringify(qsObj);
|
||||
return URL.format(parsed);
|
||||
}
|
||||
Reference in New Issue
Block a user