Skip to content

Instantly share code, notes, and snippets.

@shallaa
Created September 14, 2017 13:03
Show Gist options
  • Save shallaa/32060827bddbdb8582bf56cacb49b5df to your computer and use it in GitHub Desktop.
Save shallaa/32060827bddbdb8582bf56cacb49b5df to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
@keyframes ani {
from { width: 0; }
to { width: 100%; }
}
</style>
</head>
<body>
<div id="test" class="test"></div>
<script>
const Style =(_=>{
const prop = new Map(); // runtime cache
const prefix = 'webkit,moz,ms,chrome,o,khtml'.split(',');
const NONE = {};
const getKey = k => {
let key = prop.get(k);
if(!key){
const s = document.body.style;
if(k in s) prop.set(k, key = k);
else if(!prefix.some(v=>{
const newKey = v + k[0].toUpperCase() + k.substr(1);
if(newKey in s) return prop.set(k, key = newKey);
})) prop.set(k, key = NONE);
}
return key;
};
return class{
constructor(style){
this._style = style;
}
set(k, v){
const key = getKey(k);
if(key !== NONE) this._style[key] = v;
}
get(k){
const key = getKey(k);
return key === NONE ? null : this._style[key];
}
};
})();
// const test = new Style(document.getElementById('test').style);
// test.set('cssText', 'width:300px;background:red;height:20px');
const Rule =(_=>{
const trap = {
get(rule, key){return rule._style.get(key);},
set(rule, key, val){rule._style.set(key, val);}
};
return class{
constructor(rule){
this._rule = rule;
this._style = new Style(rule.style);
return new Proxy(this, trap);
}
};
})();
// const rule = new Rule(document.getElementById('test'));
// rule.cssText = 'width:200px;background:blue;height:50px';
const keyframes =(_=>{
const key = {
KEYFRAME_RULE:'@keyframes',
WEBKIT_KEYFRAME_RULE:'@-webkit-keyframes',
MOZ_KEYFRAME_RULE:'@-moz-keyframes'
};
for(const k in key) if(CSSRule[k]) return key[k];
})();
const KeyFramesRule = class{
constructor(rule){
this._keyframe = rule;
this._rules = new Map();
}
add(selector, index = -1){
const keyframe = this._keyframe, rules = keyframe.cssRules;
keyframe.appendRule(`${selector}{}`);
const rule = rules[rules.length - 1];
const ret = new Rule(rule);
this._rules.set(rule, ret);
return ret;
}
}
const CSS = class{
constructor(sheet){
this._sheet = sheet;
this._rules = new WeakMap();
}
log() {
console.log(Array.from(this._sheet.cssRules).reduce(
(prev, curr) => {
return prev + `${curr.cssText}\n`;
}, ''
));
}
add(selector, index = -1){
const sheet = this._sheet, rules = sheet.cssRules;
if(index == -1) index = rules.length;
if(selector[0] == '@') switch(true){
case selector.startsWith('@keyframes'):
selector = selector.split(' ');
selector[0] = keyframes;
if(! selector[0]) return;
selector = selector.join(' ');
const rule = rules[sheet.insertRule(`${selector}{}`, index)];
const ret = new KeyFramesRule(rule);
this._rules.set(rule, ret);
return ret;
}else{
const rule = rules[sheet.insertRule(`${selector}{}`, index)];
const ret = new Rule(rule);
this._rules.set(rule, ret);
return ret;
}
}
remove(key = null){
const sheet = this._sheet, rules = sheet.cssRules;
if(key === null){
let i = rules.length;
while(i--) sheet.deleteRule(i);
}else switch(typeof key){
case'number': sheet.deleteRule(i); break;
case'string':
let i = rules.length;
while(i--) if(rules[i].selectorText == key) sheet.deleteRule(i);
break;
}
}
};
const css = new CSS(document.styleSheets[0]);
const ani = css.add('@keyframes ani');
ani.add('from').cssText = 'margin-left:0;';
ani.add('to').cssText = 'margin-left: 300px';
const test = css.add('.test');
test.cssText = 'width:200px;background:green;height:50px';
test.animation = 'ani 2s linear infinite';
css.log();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment