First commit
This commit is contained in:
637
framework/client/css.js
Normal file
637
framework/client/css.js
Normal file
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user