/* 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 dom from './dom.js'; import css from './css.js'; import eventManager from './eventManager.js'; import socketManager from './socketManager.js'; import animationManager from './animation/animationManager.js'; import themeSwitcher from './themeSwitcher.js'; import fileLoader from './fileLoader.js'; import collection from './collection.js'; import tools from '../unify/tools.js'; import defaultObject from '../unify/defaultObject.js'; import vector2 from '../unify/math/vector2.js'; import definitions from "../unify/definitions.js" import stateMachine from './stateMachine.js'; document.stateMachine = new stateMachine(); var objectsPendingToCreate = new Array(); export default class core { dom = new dom(); css = new css(); eventManager = new eventManager(); themeSwitcher = new themeSwitcher(); fileLoader = new fileLoader(); stateMachine = document.stateMachine; type = "core"; objects = new Array(); pathObjects = new Array(); root = false; user = false; wait = false; addDOMToSelector = true; loadAnimations = true; createStyleSheet = true; initializeRenderLoop = true; parseEvents = true; executeMethods = true; classObjects = []; sourcePathObjects = []; visibleObjectClassNames = ""; constructor() { this.themeSwitcher.setCore( this ); } setUser( user ) { this.user = user; for (var i = 0; i < this.objects.length; i++) { this.objects[i].user = user; } } clearCache() { this.css.clearCache(); } mapClassDependencies( idObjects ) { idObjects = idObjects.filter( function() { return true; } ); if( idObjects.length > 0 ) { for ( var i = 0; i < idObjects.length; i++ ) { var currentClass = idObjects[i]; var extendObjects = currentClass.getExtends(); this.mapExtendsDependencies( extendObjects, currentClass ); } } } mapExtendsDependencies( extendObjects, currentClass ) { for ( var c = 0; c < extendObjects.length; c++ ) { var extendName = extendObjects[c]; if( !this.dependencieMap[ extendName ] ) { this.dependencieMap[ extendName ] = new Array(); } else { this.dependencieMap[ extendName ].push( currentClass ); } } } createDependencyMap() { var classObjects = this.classObjects; var keys = Object.keys( classObjects ); this.dependencieMap = new Array(); for ( let className of keys ) { //console.log("create map for key: ", className); var idObjects = classObjects[ className ]; this.mapClassDependencies( idObjects ); } } getFirstByClassName( classname, object = false ) { this.extendDefaultObject( object ); if( object.getClassName( ) == classname ) { //console.log("found object", object.getClassName( ) ); return object; } var children = object.getChildren(); for( var c = 0; c < children.length; c++ ) { var child = children[c]; var result = this.getFirstByClassName( classname, child ) ; if( result ) { return result; } } } getObjectByPath( applicationPath, application = false ) { if( !application ) { application = this.root; } var objectName = applicationPath.pop(); var currentApplication = application[ objectName ]; if( applicationPath.length > 0 ) { return this.getObjectByPath( applicationPath, currentApplication ); } else { return currentApplication; } } removeCollection( collection ) { var rows = collection.rows; for( var b = 0; b < object.rows.length; b++ ) { var row = object.rows[b]; if( row.getClassName ) { this.removeObject( row.getClassName(), row.id ); } } } removeChildren( object ) { var children = object.getChildren(); for( var b = 0; b 1 ) { if( !object.boxGridArea ) { object.boxGridArea = object.propertyName; } } else { if( !object.gridArea ) { object.gridArea = object.propertyName; } } if( typeof object.showValue == "undefined" ) { object.showValue = true; } if( !object.display ) { object.display = "flex"; } if( !object.user ) { if( this.user ) { object.user = this.user; } } if( typeof object.renderToDOM != "boolean" ) { if( object.datatype ) { object.renderToDOM = false; } else { object.renderToDOM = true; } } object.callbacks = new Array(); } createCustomMethod( object, nodeMethod ) { object[ nodeMethod ] = async function( ...nodeArguments ) { this.nodeMethodArguments = JSON.stringify( nodeArguments ); return this.socketManager.get( "object", "callNodeMethod", this, nodeMethod ); } } parseStateMethods( object ) { var stateMethodString = object.__stateMethods; if( stateMethodString ) { var stateMethods = stateMethodString.split(",") for (var i = 0; i < stateMethods.length; i++) { const stateMethod = stateMethods[i]; //console.log("found state method", object, stateMethod ) var originalMethod = object[ stateMethod ]; object["__" + stateMethod] = originalMethod; var stateMachine = this.stateMachine; object[ stateMethod ] = function( ...args ) { //console.log( "this function is now also mocked", args, object, stateMethod ); // register in stateMachine stateMachine.registerEvent( object, stateMethod, args ); object["__" + stateMethod]( args[0], args[1], args[2], args[3], args[4] ); } } } } createObjectCustomMethods( object ) { var nodeMethodsString = object.__nodeMethods; if( nodeMethodsString ) { var nodeMethods = nodeMethodsString.split(",") for (var i = 0; i < nodeMethods.length; i++) { const nodeMethod = nodeMethods[i]; //const index = i; this.createCustomMethod( object, nodeMethod ); } } object.save = async function() { return this.socketManager.get( "table", "save", this, "save" ); } object.delete = async function() { return this.socketManager.get( "table", "delete", this, "delete" ); } object.process = async function() { return this.socketManager.get( "table", "process", this, this.lastEvent ); } } attachAnimationManager(object) { //object.animationManager.attach( object ); } createRenderTimer( object ) { if(!object.mouse) { object.mouse = new vector2(0,0); } if( !object.createdTimer ) { object.createdTimer = true; object.filterStrength = 60; object.frameTime = 0; object.lastLoop = performance.timing.navigationStart + performance.now(); object.timeID = 0; object.thisLoop; } } renderLoop( start, previousProgress ) { var object = this; object.requestAnimationFrameID = window.requestAnimationFrame( function( timestamp ) { var thisFrameTime = ( object.thisLoop = performance.timing.navigationStart + performance.now() ) - object.lastLoop; object.frameTime += ( thisFrameTime - object.frameTime ) / object.filterStrength; object.lastLoop = object.thisLoop; if( object.showFps ) { object.customElement.innerHTML = ( 1000 / object.frameTime ).toFixed(1) + " fps"; } if( !start ) { start = timestamp; } var progress = ( timestamp - start ) / 10; if( !previousProgress ) { var delta = 0; } else { var delta = progress - previousProgress; } object.render( delta, progress ); object.renderLoop( start, progress ); }); } attachRenderLoop( object ) { this.createRenderTimer( object ); if( object.create && !object.isCreated ) { object.create(); object.isCreated = true; } object.renderLoop = this.renderLoop; object.renderLoop(); } createObjects() { var objects = objectsPendingToCreate console.log("objectsPendingToCreate", objectsPendingToCreate.length); //for (var i = 0; i < objects.length; i++) { while( objects.length > 0 ) { var object = objects.pop(); if( object.create && object.type != "renderCollection" ) { //object.create(); } } console.log("finished", objectsPendingToCreate); } callObjectMethods( object ) { if( object.sync ) { //object.sync(); // await } if( typeof object.render == "function" && this.initializeRenderLoop ) { this.attachRenderLoop( object ); var that = this; object.startRenderLoop = function() { that.attachRenderLoop( object ); } } if( this.loadAnimations ) { object.animationManager.attach( object ); } if( object.create && this.executeMethods ) { if( object.type != "renderCollection" && !object.isCreated ) { object.create(); object.isCreated = true; } else { if( !object.isHidden() ) { object.create(); } } } if( object.setup ) { object.setup(); } if( object.permissions ) { object.updatePermissions( object.permissions ); } if( object.windowResize && this.executeMethods ) { object.windowResize(); } } validateUser( object ) { if( object.permitted ) { if( object.allowed ) { object.allowed(); } } else { if( object.denied ) { object.denied(); } } } async prepareObject( object ) { this.setObjectClasses( object ); this.createObjectCustomVariables( object ); } parseObject( object ) { if( object.type != "collection" && object.renderToDOM ) { this.dom.parseObject( object ); this.css.parseObject( object ); if( this.parseEvents ) { this.eventManager.parseEvents( object ); } } } parseRows( object ) { if( object.type == "renderCollection" ) { var childRows = object.rows; for( var c = 0; c < childRows.length; c++ ) { object.addRow( childRows[ c ] ); } } } acceptObject( object ) { if( object.scope == "private" ) { return false; } if( object.enabled == false ) { return false; } if( object.disable == true ) { return false; } if( object.getClassName() == "signed" ) { return false; } return true; } getClassObjects() { var classObjects = this.classObjects; var keys = Object.keys( classObjects ); var array = new Array(); for ( let x of keys ) { var idObjects = classObjects[x]; idObjects = idObjects.filter(function() { return true; }); if( idObjects.length > 0 ) { array.push( idObjects ); } } return array; } getClassObjectsOrdered() { if(!this.classObjectsOrdered) { this.classObjectsOrdered = this.getClassObjects(); } return this.classObjectsOrdered; } addObjects( object, addToObjects ) { if( addToObjects ) { this.objects.push( object ); this.pathObjects[object.getApplicationPathString()] = object; } if( !this.getObjectByClassName( object.getClassName(), object.id ) ) { if( !this.classObjects[ object.getClassName() ] ) { this.classObjects[ object.getClassName() ] = new Array(); } if( object.id ) { this.classObjects[ object.getClassName() ][ object.id ] = object; } else { this.classObjects[ object.getClassName() ].push( object ); } } this.classObjects[ object.getClassName() ].push( object ); if( !this.sourcePathObjects[ object["__sourcePath"] ] ) { this.sourcePathObjects[ object["__sourcePath"] ] = new Array(); } this.sourcePathObjects[ object["__sourcePath"] ].push( object ); } updateCore( object, addToObjects ) { if( !this.root ) { this.root = object; } this.extendDefaultObject( object ); if( object.getClassName ) { this.addObjects( object, addToObjects ); } } async prepareObjects( object ) { this.setObjectClasses( object ); var children = object.getChildren(); for( var c = 0; c < children.length; c++ ) { var child = children[c]; await this.prepareObjects( child ); } } runDefault( object ) { if( object.default ) { //object.showParents(); object.default(); } if( object.getChildren ) { var children = object.getChildren(); for( var c = 0; c < children.length; c++ ) { var child = children[c]; this.runDefault( child ); } } } appendAllToSelector( object = this.root ) { /* if( object.appendToSelector ) { object.appendToSelector(); } if( object.getChildren ) { var children = object.getChildren(); for( var c = 0; c < children.length; c++ ) { var child = children[c]; this.appendAllToSelector( child ); } } */ } fixCustomElementInheritence( object ) { // multi extend fixed this } removeUnifyElement( object, depth = 0 ) { var extended = tools.getExtendedClass( object ); this.extendDefaultObject( object ); if( extended ) { var extendConstructor = extended.constructor; var instance = new extendConstructor(); depth++; if( instance.customElement && instance.getClassName ) { return this.removeUnifyElement( extended, depth ) } else { return depth; } } else { return depth; } } setTheme() { this.dom.tint = this.tint; this.dom.device = this.device; this.dom.os = this.os; this.dom.addDOMToSelector = this.addDOMToSelector; this.css.tint = this.tint; this.css.device = this.device; this.css.os = this.os; } createDefaultStyleProperties( object ) { // if developer mode const array = Object.entries( definitions.css ); for (var i = 0; i < array.length; i++) { var propertyName = array[i][0]; if( !object[propertyName] && propertyName != "gridArea" ) { object.__proto__[propertyName] = ""; } } console.log( object ); // end if developer mode } createCustomEvents( object ) { object.submit = function( event ) { event.preventDefault(); } document.body.addEventListener('mousemove', function( event ) { object.mouse = document.mouse; object.mouseVelocity = document.mouseVelocity; }); } async parse( object, addToObjects = true ) { if( !this.acceptObject( object ) ) { return false; } this.createCustomEvents( object ); this.fixCustomElementInheritence( object ); //this.createDefaultStyleProperties( object ); this.createObjectCustomMethods( object ); this.parseStateMethods( object ); this.updateCore( object, addToObjects ); this.prepareObject( object ); this.parseObject( object ); this.attachAnimationManager( object ); if( object.parseChildren ) { this.parseChildren( object ); } this.callObjectMethods( object ); if( object.type != "collection" ) { this.createHTML( object ); } this.themeSwitcher.parseObject( object ); if( object.prepare ) { object.prepare( this.socketManager ); } } parseCSSProperties( object ) { var properties = object.getProperties(); for( var c = 0; c < properties.length; c++ ) { var property = properties[c]; this.css.parseProperty( property, object ); } } addObjectToDOM( object ) { this.dom.parseInnerElements( object ); if( this.createStyleSheet ) { this.css.createStyleSheet( object ); } } createHTML( object ) { if( object.renderToDOM ) { this.parseCSSProperties( object ); if( ( object.isActive || object.type != "collection" ) || object.enabled ) { this.addObjectToDOM( object ); } } } parseRenderCollectionObject( child, index ) { if( child.getCollection ) { if( child.object ) { var newObject = new child.object(); this.extendDefaultObject( newObject ); newObject.addToDom = false; newObject.parent = child; newObject.order = index; newObject.propertyName = newObject.getClassName(); //this.parse( newObject ); } } } async parseChildren( object ) { var children = object.getChildren(); for( var c = 0; c < children.length; c++ ) { var child = children[c]; child.order = c; child.parent = object; //this.extendDefaultObject( child ); if( this.allowParseChild( object, child ) ) { this.parse( child ); } if( child.type == "renderCollection" ) { this.parseRenderCollectionObject( child, c ); } } } allowParseChild( parent, child ) { if( !child.extendsClass ) { this.extendDefaultObject( child ); } // If class doesnt extend table and thus is not a tableObject. if( child.constructor.name != "Object" && !child.extendsClass( "table" ) ) { // If the object is table and child a collumn but the table's parsetable property is not true // allow parsing, If parsetable is not set, it is automatically set to true. so then // allow parsing. if( !( !parent.parseTable && child.datatype ) ) { return true; } } return false; } updatePermissions( objectPermissions ) { //console.log("objectPermissions", objectPermissions); for(var c = 0; c