638 lines
12 KiB
JavaScript
638 lines
12 KiB
JavaScript
|
|
/*
|
||
|
|
|
||
|
|
Copyright (c) 2020, 2023, The Unified Company.
|
||
|
|
|
||
|
|
This code is part of Unify.
|
||
|
|
|
||
|
|
This program is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE,
|
||
|
|
as published by the Free Software Foundation.
|
||
|
|
See the GNU AFFERO GENERAL PUBLIC LICENSE, for more details.
|
||
|
|
|
||
|
|
https://unifyjs.org
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
import cssRules from './cssRules.js';
|
||
|
|
|
||
|
|
import document from '../unify/document.js';
|
||
|
|
|
||
|
|
import cssManager from './cssManager.js';
|
||
|
|
|
||
|
|
import tools from '../unify/tools.js';
|
||
|
|
|
||
|
|
import definitions from '../unify/definitions.js';
|
||
|
|
|
||
|
|
|
||
|
|
export default class css{
|
||
|
|
|
||
|
|
cssCache = new cssManager();
|
||
|
|
|
||
|
|
global_css = "";
|
||
|
|
|
||
|
|
skipBoxTerms = new Array( "box-sizing", "box-shadow", "box-reflect", "box-decoration-break" );
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
|
||
|
|
this.boxTermWithoutPrefix = new Array();
|
||
|
|
|
||
|
|
for (var i = 0; i < this.skipBoxTerms.length; i++) {
|
||
|
|
|
||
|
|
var boxTerm = this.skipBoxTerms[i]
|
||
|
|
|
||
|
|
this.boxTermWithoutPrefix[i] = boxTerm.replace("box-")
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
PerformPropertyGridCorrection( property ) {
|
||
|
|
|
||
|
|
for ( var i = 0; i < this.skipBoxTerms.length; i++ ) {
|
||
|
|
|
||
|
|
if( this.boxTermWithoutPrefix[ i ].includes( property ) ) {
|
||
|
|
|
||
|
|
property = this.skipBoxTerms[ i ];
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return property;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseObject( object ){
|
||
|
|
|
||
|
|
var objectName = object.propertyName;
|
||
|
|
|
||
|
|
object.__proto__.css = new cssRules();
|
||
|
|
|
||
|
|
object.__proto__.boxRules = new cssRules();
|
||
|
|
|
||
|
|
object.__proto__.cssRules = new cssRules();
|
||
|
|
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "hover", ":hover" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "visited", ":visited" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "link", ":link" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "active", ":active" );
|
||
|
|
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "placeholder", "::placeholder" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "scrollbar", "::-webkit-scrollbar" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "scrollbarTrack", "::-webkit-scrollbar-track" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "scrollbarThumb", "::-webkit-scrollbar-thumb" );
|
||
|
|
|
||
|
|
object.cssRules.addStyleListener( "scrollbarThumbHover", "::-webkit-scrollbar-thumb:hover" );
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseCSSValue( value ) {
|
||
|
|
|
||
|
|
if( typeof value == "number" ) {
|
||
|
|
|
||
|
|
value += "px";
|
||
|
|
}
|
||
|
|
|
||
|
|
return value;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createStyleRule( normalizedProperty, value ){
|
||
|
|
|
||
|
|
if( !value ) {
|
||
|
|
|
||
|
|
return "";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
value = this.parseCSSValue( value );
|
||
|
|
|
||
|
|
normalizedProperty = this.PerformPropertyGridCorrection( normalizedProperty );
|
||
|
|
|
||
|
|
return "\t" + normalizedProperty + ":" + value + "; \n";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
compareUpperCase( term ) {
|
||
|
|
|
||
|
|
const compare = function( current ){ if( term.indexOf( current ) != -1 ){ return true; } }
|
||
|
|
|
||
|
|
const n = definitions.alphabet;
|
||
|
|
|
||
|
|
var map = n.map( compare );
|
||
|
|
|
||
|
|
return map; // [false, false, true, false] where true is where higher case is
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
hasUpperCase( a ) {
|
||
|
|
|
||
|
|
let regExp = /[A-Z]/;
|
||
|
|
|
||
|
|
return regExp.test( a );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
replaceUpperCase( word ) {
|
||
|
|
|
||
|
|
var map = this.compareUpperCase( word );
|
||
|
|
|
||
|
|
var letter = definitions.alphabet[ map.indexOf( true ) ];
|
||
|
|
|
||
|
|
return word.replace( letter, "-" + letter.toLowerCase() );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
normalizePropertyName( name ) {
|
||
|
|
|
||
|
|
return tools.firstLowerCase( name.replace("__", "").replace("box", "") );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// needs caching
|
||
|
|
normalizeProperty( name ) {
|
||
|
|
|
||
|
|
// webkit -> -webkit
|
||
|
|
if( name.slice( 0, 6 ) == "webkit" ) {
|
||
|
|
|
||
|
|
name = "-" + name;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
for (var i = 0; i < 6; i++) {
|
||
|
|
|
||
|
|
if( this.hasUpperCase( name ) ) {
|
||
|
|
|
||
|
|
name = this.replaceUpperCase( name ); // backgroundColor -> background-color-and-something
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return name;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
setter( object, domStyleObject, propertyName, property, value ) {
|
||
|
|
|
||
|
|
object[ "__" + propertyName ] = value;
|
||
|
|
|
||
|
|
value = this.parseCSSValue( value );
|
||
|
|
|
||
|
|
property = this.PerformPropertyGridCorrection( property );
|
||
|
|
|
||
|
|
var NSTabNames = new Array("svg", "circle")
|
||
|
|
|
||
|
|
// todo : doesnt work properly
|
||
|
|
//if( NSTabNames.includes( object.element.tagName ) ) {
|
||
|
|
|
||
|
|
// domStyleObject.setAttributeNS( null, property, value );
|
||
|
|
|
||
|
|
//} else {
|
||
|
|
|
||
|
|
domStyleObject.setProperty( property, value );
|
||
|
|
|
||
|
|
//}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createSetter( property, objectProperty, object, domStyleObject ) {
|
||
|
|
|
||
|
|
var css = this;
|
||
|
|
|
||
|
|
object[ "__" + objectProperty ] = object[ objectProperty ];
|
||
|
|
|
||
|
|
object.__defineSetter__( objectProperty, this.setter.bind( this, object, domStyleObject, objectProperty, property ) );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
getter( object, objectProperty, value ) {
|
||
|
|
|
||
|
|
var newValue = object[ "__" + objectProperty ];
|
||
|
|
|
||
|
|
if(typeof newValue == "string") {
|
||
|
|
|
||
|
|
var chars = newValue.split();
|
||
|
|
|
||
|
|
if( chars[chars.length-2] == "p" && chars[chars.length-1] == "x" ) {
|
||
|
|
|
||
|
|
chars = chars.slice(0, -2);
|
||
|
|
|
||
|
|
newValue = chars.join();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( tools.isCustomNumber( newValue ) ) {
|
||
|
|
|
||
|
|
return parseFloat( newValue );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return newValue;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createGetter( property, objectProperty, object, domStyleObject ) {
|
||
|
|
|
||
|
|
object.__defineGetter__( objectProperty, this.getter.bind( this, object, objectProperty ) );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseProperty( property, object ) {
|
||
|
|
|
||
|
|
var propertyName = property.name;
|
||
|
|
|
||
|
|
var propertyValue = property.value;
|
||
|
|
|
||
|
|
var normalizedProperty = this.normalizeProperty( propertyName );
|
||
|
|
|
||
|
|
//if( propertyName == "gridArea" && propertyValue == "none" ) {
|
||
|
|
|
||
|
|
// return false;
|
||
|
|
|
||
|
|
//}
|
||
|
|
|
||
|
|
var slicedProperty = propertyName.toLowerCase().slice( 0, 3 );
|
||
|
|
|
||
|
|
if( slicedProperty == "box" ) {
|
||
|
|
|
||
|
|
object.boxRules.style += this.parseCssTerm( object, propertyName, propertyValue, object.elements[0], "box" );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
object.css.style += this.parseCssTerm( object, propertyName, propertyValue, object.element )
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
this.parseExtraStyleSuffixes( object, propertyName, propertyValue );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseExtraStyleSuffixes( object, propertyName, propertyValue ) {
|
||
|
|
|
||
|
|
var styleTypes = object.cssRules.styleTypes;
|
||
|
|
|
||
|
|
for ( var i = 0; i < styleTypes.length; i++ ) {
|
||
|
|
|
||
|
|
var cssType = styleTypes[i];
|
||
|
|
|
||
|
|
var propertyTerm = cssType.propertyTerm;
|
||
|
|
|
||
|
|
var slicedProperty = propertyName.slice( 0, propertyTerm.length );
|
||
|
|
|
||
|
|
|
||
|
|
if( slicedProperty == propertyTerm && propertyName.length > slicedProperty.length ) {
|
||
|
|
|
||
|
|
cssType.css += this.parseCssTerm( object, propertyName, propertyValue, object.elements[0], propertyTerm );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseCssTerm( object, propertyName, propertyValue, element, term = "" ) {
|
||
|
|
|
||
|
|
var cssPropertyName = tools.firstLowerCase( propertyName.replace( term, "" ) );
|
||
|
|
|
||
|
|
var normalizedProperty = this.normalizeProperty( cssPropertyName );
|
||
|
|
|
||
|
|
if( this.propertyIsStyle( normalizedProperty ) ) {
|
||
|
|
|
||
|
|
// Setters and getters don't work yet for special suffixes.
|
||
|
|
if( !term || term == "box" ) {
|
||
|
|
|
||
|
|
this.createSetter( normalizedProperty, propertyName, object, element.style );
|
||
|
|
|
||
|
|
this.createGetter( normalizedProperty, propertyName, object, element.style );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.createStyleRule( normalizedProperty, propertyValue );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return "";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
clearCache() {
|
||
|
|
|
||
|
|
this.cssCache.rules = new Array();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
parseCssRule( object, objectPropertyName, propertyName, propertyValue ) {
|
||
|
|
|
||
|
|
var normalizedProperty = this.normalizeProperty( objectPropertyName );
|
||
|
|
|
||
|
|
object.boxRules.style += this.createStyleRule( normalizedProperty, propertyValue );
|
||
|
|
|
||
|
|
|
||
|
|
this.createSetter( objectPropertyName, propertyName, object, object.elements[0].style );
|
||
|
|
|
||
|
|
this.createGetter( objectPropertyName, propertyName, object, object.elements[0].style );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createSelector( className, afterTerm ) {
|
||
|
|
|
||
|
|
var selector = "." + className;
|
||
|
|
|
||
|
|
selector += "." + this.device;
|
||
|
|
|
||
|
|
selector += "." + this.os;
|
||
|
|
|
||
|
|
selector += "." + this.tint;
|
||
|
|
|
||
|
|
// this doesnt work yet.
|
||
|
|
if( afterTerm ) {
|
||
|
|
|
||
|
|
selector += afterTerm;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
//selector += "," + selector.replace( "_" + id, "" );
|
||
|
|
|
||
|
|
return selector;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createStyleSheet( object ){
|
||
|
|
|
||
|
|
var objectName = tools.createCSSClassName( object );
|
||
|
|
|
||
|
|
var body = object.css.style;
|
||
|
|
|
||
|
|
|
||
|
|
if( object.customElement ) {
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Element" );
|
||
|
|
|
||
|
|
this.global_css += this.cssCache.getRule( selector, body );
|
||
|
|
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Grid" );
|
||
|
|
|
||
|
|
this.global_css += this.cssCache.getRule( selector, body );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Grid" );
|
||
|
|
|
||
|
|
this.global_css += this.cssCache.getRule( selector, body );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( object.boxRules ) {
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Box" );
|
||
|
|
|
||
|
|
var body = object.boxRules.style;
|
||
|
|
|
||
|
|
this.global_css += this.cssCache.getRule( selector, body );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
var styleTypes = object.cssRules.styleTypes;
|
||
|
|
|
||
|
|
for (var i = 0; i < styleTypes.length; i++) {
|
||
|
|
|
||
|
|
var cssType = styleTypes[i];
|
||
|
|
|
||
|
|
if( object.useCustomElement ) {
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Element", cssType.cssSuffix );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
var selector = this.createSelector( objectName + "Grid", cssType.cssSuffix );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
var body = cssType.css;
|
||
|
|
|
||
|
|
if( body != "" ) {
|
||
|
|
|
||
|
|
//console.log("cssType.cssSuffix", cssType.cssSuffix);
|
||
|
|
|
||
|
|
this.global_css += this.cssCache.getRule( selector, body );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
if( !object.parent ) {
|
||
|
|
|
||
|
|
this.writeCssToPage( this.global_css );
|
||
|
|
|
||
|
|
this.global_css = "";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( object.dynamic ) {
|
||
|
|
|
||
|
|
this.writeCssToPage( this.global_css );
|
||
|
|
|
||
|
|
this.global_css = "";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
writeCssToPage( css ) {
|
||
|
|
|
||
|
|
if( css == "" ) {
|
||
|
|
|
||
|
|
return false;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
var style = document.createElement("style");
|
||
|
|
|
||
|
|
style.innerHTML = css;
|
||
|
|
|
||
|
|
document.head.appendChild( style );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
removeStripe( name ) {
|
||
|
|
|
||
|
|
var splitName = name.split("-");
|
||
|
|
|
||
|
|
if( splitName.length > 1 ) {
|
||
|
|
|
||
|
|
return splitName[1].toLowerCase();
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return name;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
getStyleSheetObject(){
|
||
|
|
|
||
|
|
if( !document.body ) {
|
||
|
|
|
||
|
|
return definitions.css;
|
||
|
|
/*
|
||
|
|
var array = JSON.parse(cssDef);
|
||
|
|
|
||
|
|
var object = new Object();
|
||
|
|
|
||
|
|
for (var i = 0; i < array.length; i++) {
|
||
|
|
|
||
|
|
var def = array[i];
|
||
|
|
|
||
|
|
if( this.hasUpperCase( def ) ) {
|
||
|
|
|
||
|
|
object[ this.replaceUpperCase( def ) ] = '';
|
||
|
|
|
||
|
|
console.log( this.replaceUpperCase( def ) );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
object[ def ] = '';
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
return object;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( document.body.style ) {
|
||
|
|
|
||
|
|
var bodyStyle = document.body.style;
|
||
|
|
|
||
|
|
bodyStyle.webkitBoxShadow = "";
|
||
|
|
|
||
|
|
return bodyStyle;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( document.body.styleSheets ) {
|
||
|
|
|
||
|
|
// fix please!!!! not allowed
|
||
|
|
return document.styleSheets[1].cssRules[0].style;
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return document.customStyleTerms;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
camelCaseToDash( name ) {
|
||
|
|
|
||
|
|
for ( var i = 0; i < 4; i++ ) {
|
||
|
|
|
||
|
|
if( this.hasUpperCase( name ) ) {
|
||
|
|
|
||
|
|
name = this.replaceUpperCase( name ); // backgroundColor -> background-color
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return name;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
removeBoxPrefix( name ) {
|
||
|
|
|
||
|
|
if( !name.includes("webkit-box") ) {
|
||
|
|
|
||
|
|
name = name.replace("box", "").toLowerCase();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return name;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
checkBoxSpecialCase( name ) {
|
||
|
|
|
||
|
|
for (var i = 0; i < this.boxTermWithoutPrefix.length; i++) {
|
||
|
|
|
||
|
|
if( this.boxTermWithoutPrefix[ i ].includes( name ) ) {
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
propertyIsStyle( name ){
|
||
|
|
|
||
|
|
name = this.camelCaseToDash( name );
|
||
|
|
|
||
|
|
name = this.removeBoxPrefix( name );
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
if( this.checkBoxSpecialCase( name ) ) {
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
var styleTerms = this.getStyleSheetObject();
|
||
|
|
|
||
|
|
if( typeof styleTerms[ name ] == "string" ) {
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return false;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
propertyHasStyle( name ){
|
||
|
|
|
||
|
|
var styleTerms = Object.keys( definitions.css );
|
||
|
|
|
||
|
|
if( styleTerms.includes( name.toLowerCase() ) ) {
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return false;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|