First commit

This commit is contained in:
2025-12-25 11:16:59 +01:00
commit 0c5ca09a63
720 changed files with 329234 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
export default class ajaxSocket{
async send( message ) {
var json = JSON.parse( message );
json.sessionKey = new String( that.sessionKey );
message = JSON.stringify( json );
var result = await that.fetch( message );
var a = new Object();
a.data = result;
that.message( a )
}
}

View File

@@ -0,0 +1,163 @@
/*
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 keyFrame from "./animation.keyFrame.js";
export default class animation{
name;
element;
keyFrames = new Array();
animationManager;
duration;
createKeyFrame( percent ) {
var newKeyFrame = new keyFrame();
newKeyFrame.percent = percent;
this.keyFrames.push( newKeyFrame );
return newKeyFrame;
}
createPromiseFunction( id ) {
var that = this;
function promiseFunction( resolveFunction ){
var promiseObject = new Object;
promiseObject.id = id;
promiseObject.resolve = resolveFunction;
that.animationManager.addPromise( promiseObject );
}
return promiseFunction;
}
async stop() {
if( !this.element.classList.contains("keyFrameAnimations") ) {
var animationClassName = this.animationManager.getAnimationClassName();
this.element.classList.remove( animationClassName );
}
}
async pause() {
this.element.classList.add("pause-animation");
}
setDuration( duration ) {
this.duration = duration;
}
setDirection( direction ) {
this.direction = direction;
}
setIterationCount( iterationCount ) {
this.iterationCount = iterationCount;
}
setFillMode( fillMode ) {
this.fillMode = fillMode;
}
async play( duration ) {
if( this.element.classList.contains("pause-animation") ) {
this.element.classList.remove("pause-animation");
return true;
}
if( !this.element.classList.contains("keyFrameAnimations") ) {
var animationClassName = this.animationManager.getAnimationClassName();
this.element.classList.add( animationClassName );
}
if( duration ) {
this.duration = duration;
}
this.active = true;
var source = this.animationManager.composeCss();
this.writeStyleToDOM( source );
var promiseFunction = this.createPromiseFunction( this.id );
var promise = new Promise( promiseFunction );
this.animationManager.createEventListener();
await promise;
return true;
}
writeStyleToDOM( source ) {
var style = document.createElement("style")
style.type = 'text/css';
style.appendChild( document.createTextNode( source ) );
document.getElementsByTagName("head")[0].appendChild( style );
}
}

View File

@@ -0,0 +1,59 @@
/*
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 property from "./animation.property.js";
export default class keyFrame{
percent;
properties = new Array();
setProperty( name, value ) {
var newProperty = new property();
newProperty.name = name;
if(typeof value == "number") {
value += "px";
}
newProperty.value = value;
this.properties.push( newProperty );
}
composeCss() {
var properties = this.properties;
var propertyLines = "";
for (var i = 0; i < properties.length; i++) {
propertyLines += properties[i].composeCss();
}
return propertyLines;
}
}

View File

@@ -0,0 +1,38 @@
/*
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
*/
export default class property{
name;
value;
composeCss() {
var functionNames = new Array( "rotate", "translate", "scaleX", "scaleY", "scale", "skewX", "skewY", "skew", "matrix" );
if( functionNames.includes( this.name ) ) {
return "transform: " + this.name + "( " + this.value + " ); ";
} else {
return "\n " + this.name + " : " + this.value + ";\n";
}
}
}

View File

@@ -0,0 +1,454 @@
/*
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 animation from "./animation.js";
export default class animationManager{
id = 0;
start = 0;
animations = new Array();
element = document.querySelector(".test");
promises = new Array();
eventListener;
constructor() {
this.id = document.animationID++;
}
createAnimation( name ) {
var newAnimation = new animation();
newAnimation.animationManager = this
newAnimation.id = document.keyframeID++;
newAnimation.name = name + newAnimation.id;
newAnimation.element = this.element;
newAnimation.created = false;
this.animations[ newAnimation.name ] = newAnimation;
this.createListeners( newAnimation );
return newAnimation;
}
getAnimationClassName() {
return "keyFrameAnimation" + this.id;
}
createListeners( animation ) {
if( !animation.direction ) {
animation.__direction = "normal"
} else {
animation.__direction = animation.direction;
}
var that = this;
animation.__defineSetter__( "direction", function( value ){
animation.__direction = value;
var animationManager = animation.animationManager;
var source = that.composeCss();
animation.writeStyleToDOM( source );
});
animation.__defineGetter__( "direction", function(){
return animation.__direction;
});
}
composeKeyFrameCss( source ) {
var animations = this.animations;
for ( var i in animations ) {
var currentAnimation = animations[i];
//if( !currentAnimation.active ) {
source += "@keyframes " + currentAnimation.name + "{ \n";
var keyFrames = currentAnimation.keyFrames;
for (var i = 0; i < keyFrames.length; i++) {
var currentKeyFrame = keyFrames[i];
source += "\t" + currentKeyFrame.percent + "% {";
source += currentKeyFrame.composeCss();
source += "}\n";
}
source += "} \n";
currentAnimation.created = true;
//}
}
return source;
}
composeAnimationCss( source ) {
var names = new Array();
var durations = new Array();
var interationCounts = new Array();
var fillModes = new Array();
var directions = new Array();
var animations = this.animations;
for ( var i in animations ) {
var currentAnimation = animations[i];
if( currentAnimation.active ) {
if( currentAnimation.duration ) {
names.push( currentAnimation.name );
durations.push( currentAnimation.duration );
directions.push( currentAnimation.direction );
if( !currentAnimation.iterationCount ) {
currentAnimation.iterationCount = 1;
}
interationCounts.push( currentAnimation.iterationCount );
if( !currentAnimation.fillMode ) {
currentAnimation.fillMode = "none";
}
fillModes.push( currentAnimation.fillMode );
}
}
}
source += ".keyFrameAnimation" + this.id + "{\n";
source += "\tanimation-name: " + names.join(",") + ";\n";
source += "\tanimation-duration: " + durations.join(",") + ";\n";
source += "\tanimation-iteration-count: " + interationCounts.join(",") + ";\n";
source += "\tanimation-fill-mode: " + fillModes.join(",") + ";\n";
source += "\tanimation-direction: " + directions.join(",") + ";\n";
source += "}";
return source;
}
composeCss() {
var source = "";
source += this.composeKeyFrameCss( source );
source += this.composeAnimationCss( source );
return source;
}
addPromise( promiseObject ) {
this.promises[ promiseObject.id ] = promiseObject;
}
getPromiseByID( id ) {
return this.promises[ id ];
}
createPromiseFunction( animationID ) {
var that = this;
function promiseFunction( resolveFunction ){
var promiseObject = {};
promiseObject.id = animationID;
promiseObject.resolve = resolveFunction;
that.addPromise( promiseObject );
}
return promiseFunction;
}
attach( object ){
object.__proto__.animate = this.createCallback( object );
var animationManager = this;
object.createAnimation = function( name ) {
return object.animationManager.createAnimation( name );
}
this.element = object.element;
}
createCallback( object ) {
object.animationManager.object = object;
return async function( from, to, callback ) {
return object.animationManager.animate( from, to, callback );
}
}
async animate( from, to, callback, firstTick = true, animationID, value = false, start = false ) {
var object = this.object;
if( firstTick ) {
animationID = document.animationID++;
}
var sign = Math.sign( from - to );
var stop = false;
if( sign > 0) {
value = from - value;
if( value < to ) {
var stop = true;
}
} else {
value = from + value;
if( value > to ) {
var stop = true;
}
}
if( firstTick ) {
this.object[ "animationCallback" + animationID ] = callback;
}
if( !stop ) {
this.object[ "animationCallback" + animationID ]( value );
window.requestAnimationFrame( function( timestamp ) {
if( !start ) {
start = timestamp;
}
var progress = ( timestamp - start );
object.animationManager.animate( from, to, callback, false, animationID, progress, start );
});
} else {
var promise = this.getPromiseByID( animationID );
promise.resolve();
}
if( firstTick ) {
this.object[ "animationCallback" + animationID ]( value );
var promiseFunction = this.createPromiseFunction( animationID );
await new Promise( promiseFunction )
return true;
}
}
createEventListener() {
var that = this;
if( this.element.keyFrameEventListener ) {
canvas.removeEventListener('click', this.element.keyFrameEventListener);
}
this.element.keyFrameEventListener = this.element.addEventListener("animationend", async function( event ) {
var animations = that.animations;
var animationName = event.animationName;
//console.log(animationName, that.promises);
//console.log(animations, animationName)
var currentAnimation = animations[ animationName ];
console.log("turn off animation", currentAnimation);
currentAnimation.active = false;
//console.log("promise with animationName", animationName, "and animationID", currentAnimation.animationID, "removed");
if( currentAnimation ) {
var promise = that.promises[currentAnimation.id];
if( promise ) {
promise.resolve();
} else {
return false;
}
}
//console.log("ended animation", currentAnimation);
that.promises.splice( currentAnimation.id, 1, false )
for (var i = 0; i < that.promises.length; i++) {
if( that.promises[i] ) {
return false
}
}
//console.log("all promises are resolved resetting animation");
//that.resetAnimation();
var animationClassName = that.getAnimationClassName();
that.element.classList.remove(animationClassName);
}, false);
return true;
}
resetAnimation() {
//if( this.element.classList.contains("keyFrameAnimations") ) {
this.element.classList.remove("keyFrameAnimations")
//}
}
}

View File

@@ -0,0 +1,702 @@
/*
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 core from './core.js';
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 collection from './collection.js';
import codePreview from './codePreview.js';
import themeLoader from './themeLoader.js';
import tools from '../unify/tools.js';
import defaultObject from '../unify/defaultObject.js';
//import cookieManager from '../unify/cookieManager.js';
import cacheManager from "../unify/cacheManager.js";
import config from "../configs/config.js";
import applicationImport from './import.js';
import progressBar from './progressBar.js';
import applications from '../configs/applications.js';
import simplePath from "../unify/simplePath.js";
// For Benchmarking
//document.timer.lap("before");
//document.timer.lap("after");
document.promises = new Array();
document.cacheManager = new cacheManager();
document.cacheManager.useDB = false;
document.debugALL = false;
export default class applicationManager{
socketPort = 5002;
defaultSocketPort = 5002;
loadEditor = true;
defaultObject = new defaultObject();
themeLoader = new themeLoader();
mode = "development";
serverAddress = "localhost";
serverPort = 8090;
application;
applications;
applicationInstances = new Array();
ssl = false;
themeObjects = new Array();
connectPromise;
signinPromise;
constructor() {
this.themeLoader.applicationManager = this;
}
setParameters( config ) {
this.mode = config.mode;
this.ssl = config.ssl;
this.socketPort = config.socketPort;
this.loadThemes = config.loadThemes;
this.os = tools.CamelCase( config.os );
this.tint = tools.CamelCase( config.tint );
this.device = tools.CamelCase( config.device );
if( config.serverAddress ) {
this.serverAddress = config.serverAddress;
} else {
this.serverAddress = "localhost";
}
if( config.port ) {
this.port = config.port;
} else {
this.port = 3000;
}
}
setGlobal() {
document.mode = this.mode;
document.config = new Object();
document.config.os = this.os;
document.config.tint = this.tint;
document.config.device = this.device;
}
logConfig( config ) {
console.log( config );
console.log("set socket port", this.socketPort );
console.log( "running in ", config.mode, " mode.", "address : " + this.serverAddress );
}
parseConfig() {
this.setParameters( config );
this.setGlobal();
this.logConfig( config );
}
createApplicationPath( path ) {
var device = tools.CamelCase( this.device );
var os = tools.CamelCase( this.os );
var tint = tools.CamelCase( this.tint );
var applicationPath = '/framework/cache/platforms/' + os + '/' + device + '/' + tint + '/' + path + '/application.js';
return applicationPath;
}
async getApplicationInstance( path, applicationID ) {
if( this.mode == "development" ) {
var applicationPath = this.createApplicationPath( path );
var importObject = await import( applicationPath );
this.application = new importObject.default();
} else {
var currentBundle = applicationImport[ applicationID ];
//console.log("loading application with id", applicationID);
if( currentBundle ) {
this.application = new currentBundle();
}
}
return this.application;
}
getUserObject( core, application, username, sessionKey ) {
if( !username ) {
var userObject = core.getFirstByClassName( "signin", application );
} else {
var userObject = core.getFirstByClassName( "signin", application );
if( !userObject ){
return false;
}
if( sessionKey ) {
userObject.sessionKey.value = sessionKey;
}
}
return userObject;
}
async singinUser( core, socketManager, userObject ) {
//var user = await socketManager.get( "settings", "signIn", userObject );
var user = await userObject.process();
//await userObject.socketManager.get( "table", "process", userObject );
//var user = await userObject.process();
core.user = user;
await core.setUser( user, application );
console.log( "update user permissions", user );
if( !user.permissionObjects ) {
return false;
}
core.updatePermissions( user.permissionObjects );
}
configurePath() {
this.url = window.location;
this.pathName = this.url.pathname;
}
parseUrlByID( core, tableName, id ) {
var objects = core.getObjectsByPropertyName( tableName );
if( objects.length > 0 ) {
var object = objects[0];
if( object.parent.create ) {
object.parent.create();
}
object.id = parseFloat( id );
if( object.loadPage ) {
object.loadPage();
}
object.showParents();
}
}
async parseUrl( core, application ) {
this.configurePath();
var pathName = this.pathName;
var pathParts = pathName.split("/");
pathParts.shift();
var tableName = pathParts[0];
var id = pathParts[1];
if( id ) {
this.parseUrlByID( core, tableName, id );
} else {
document.stateMachine.composeState()
core.runDefault( application );
}
}
createBaseUrl() {
var base = document.createElement("base");
if( this.ssl ) {
base.href = "https://" + this.serverAddress;
} else {
base.href = "http://" + this.serverAddress + ":" + this.port;
}
document.head.appendChild( base );
}
createMetaDescription() {
if( this.application.description ) {
document.querySelector(".metaDescription").setAttribute("content", this.application.description );
} else {
document.querySelector(".metaDescription").setAttribute("content", "A unifyJS application." );
}
}
async initializeSocketManager( core, application ) {
var socket = new socketManager( this.socketPort );
socket.ssl = this.ssl;
socket.serverAddress = this.serverAddress;
this.connectPromise = socket.connect();
document.connectPromise = this.connectPromise;
await this.connectPromise;
socket.addClient();
return socket;
}
async createApplicationInstances() {
for( var applicationID = 0; applicationID < this.applications.length; applicationID++ ) {
var applicationFile = this.applications[ applicationID ];
this.applicationInstances[ applicationID ] = await this.getApplicationInstance( applicationFile.path, applicationID );
}
}
bindApplications() {
this.applications = applications;
document.applications = applications;
}
getApplication() {
var applicationFile = this.applications[ 0 ];
applicationFile.socket = socket;
}
async start() {
var unifyCore = new core();
this.parseConfig();
this.bindApplications();
this.createBaseUrl();
await this.createApplicationInstances();
var socket = this.initializeSocketManager( unifyCore, this.applicationInstances[0] );
await this.runApplication( socket, 0, unifyCore );
this.createMetaDescription();
document.timer.lap("Everything is loaded");
console.log( this.applicationInstances[0] );
}
async updateApplications() {
for( var applicationID = 1; applicationID < this.applications.length; applicationID++) {
var applicationFile = this.applications[ applicationID ];
var unifyCore = new core();
this.runApplication( applicationFile.socket, applicationID, unifyCore );
}
}
async attachSocket( applicationFile, socket, applicationID ) {
if( !applicationFile.socket ) {
applicationFile.socket = await new socketManager( this.defaultSocketPort + applicationID );
if( this.serverAddress ) {
applicationFile.socket.serverAddress = this.serverAddress;
}
await applicationFile.socket.connect();
}
return applicationFile.socket;
}
preventDoubleLoading( element ) {
if( element && element.childElementCount != 0 ) {
return true;
}
}
createCodeEditor( app, applicationID ) {
if( applicationID != 0 ) {
new codePreview( app );
}
}
getDomElement( application ) {
if( this.applications.length == 1) {
application.selector = "#application";
}
var element = document.querySelector( application.selector );
if( document.querySelectorAll( application.selector ).length == 0 ) {
return true;
} else {
if( this.preventDoubleLoading( element ) ) {
return true;
}
}
return false;
}
configureCore( core ) {
core.device = this.device;
core.os = this.os;
core.tint = this.tint;
}
setGlobalCore( unifyCore, applicationID ) {
if( !document.cores ) {
document.cores = new Array();
}
document.cores[ applicationID ] = unifyCore;
}
async parseApplication( core, application, applicationID ) {
this.defaultObject.agregateDefaultObject( application );
this.setGlobalCore( core, applicationID );
await core.prepareObjects( application );
await document.connectPromise;
this.configureCore( core );
core.setTheme();
application.core = core;
await core.parse( application, true );
core.createDependencyMap();
}
hidePreloader() {
if( document.querySelector(".loadingBarPanel, .preloader, #preloader" )) {
document.querySelector(".loadingBarPanel, .preloader, #preloader").style.opacity = "0%";
}
setTimeout(function(){
document.querySelector(".loadingBarPanel, .preloader, #preloader").style.display = "none";
}, 1000)
}
logApplication( application, unifyCore ) {
if( document.debugALL ) {
console.log( "" );
console.log( "run application", application.selector );
console.log( "Core", unifyCore );
console.log( "Application", application );
console.log( "" );
}
}
setServerPort( port ) {
if( application.port ) {
this.serverPort = application.port;
}
}
prepareApplication(applicationID) {
var application = this.applicationInstances[ applicationID ];
application.applicationID = applicationID;
this.setServerPort( application.port );
return application;
}
bindObjectsToSocket( socket, application, unifyCore, applicationID ) {
if( applicationID == 0 ) {
socket.application = application;
socket.core = unifyCore;
}
}
async runApplication( socket = false, applicationID, unifyCore ) {
if ( this.applicationInstances[ applicationID ] ) {
var application = this.prepareApplication( applicationID );
this.bindObjectsToSocket( socket, application, unifyCore, applicationID );
if( this.getDomElement( application ) ) {
return true;
}
unifyCore.socketManager = await socket;
this.hidePreloader();
this.createCodeEditor( application, applicationID );
await this.parseApplication( unifyCore, application, applicationID );
//this.signinPromise = this.checkSignIn( socket, unifyCore, application );
//console.log("after signin");
if( applicationID == 0 ) {
//this.parseUrl( unifyCore, application );
}
//await Promise.all( document.promises );
await unifyCore.callAfterLoad( application );
this.logApplication( application, unifyCore );
if( this.loadThemes ) {
await this.themeLoader.loadThemes( application, applicationID, unifyCore );
}
this.setGlobals();
await unifyCore.callAfterThemeLoad( application );
}
return true;
}
setGlobals() {
document.timer.initialising = false;
document.themeObjects = this.themeObjects;
}
}

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,80 @@
/*
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
*/
export default class codePreview{
constructor( application ) {
return this.createPreviewApplication( application );
}
createPreviewApplication( app ) {
// Create those light blue preview applications on the right side of the code blocks
var id = app.selector;
var element = document.querySelector( id );
if( element && element.children.length == 0 ) {
this.stylePreviewApplication( element, id );
}
return element;
}
stylePreviewApplication( element, id ) {
var examplePre = element.previousElementSibling;
if( examplePre && examplePre.firstChild ) {
var codeElement = examplePre.firstChild;
codeElement.className = codeElement.className + " halfCodeElement";
examplePre.className = "examplePre";
element.remove();
var examplePanel = document.createElement("div");
examplePanel.className = "examplePanel";
examplePanel.id = id.replace("#", "").replace(".", "");
examplePre.appendChild( examplePanel );
}
}
createPreviewLabel( element ) {
var previewLabel = document.createElement("div");
previewLabel.className = "previewLabel";
previewLabel.innerHTML = "preview";
element.appendChild( previewLabel );
}
}

View File

@@ -0,0 +1,46 @@
/*
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 tools from '../unify/tools.js';
import baseCollection from '../unify/collection.js';
export default class collection extends baseCollection{
__className = "collection";
clearCollection() {
var rows = this.rows;
console.log("clear collection", rows, this);
for( var c = 0; c < rows.length; c++ ) {
var object = rows[c];
object.remove();
}
this.rows = new Array();
}
}

View File

@@ -0,0 +1 @@
{"mode":"development","serverAddress":"localhost","ssl":false,"socketPort":5000,"port":3000}

1523
framework/client/core.js Normal file
View File

File diff suppressed because it is too large Load Diff

637
framework/client/css.js Normal file
View 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;
}
}
}

View File

@@ -0,0 +1,63 @@
/*
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 tools from '../unify/tools.js';
export default class cssManager{
rules = new Array();
addRule( selector, body ) {
var rule = new Object();
rule.selector = selector;
rule.body = body;
this.rules[ selector ] = body;
}
composeCss( selector, body ) {
if( body == "") {
return "";
}
return "\n" + selector + "{ " + "\n" + body + "\n" + " } " + "\n";
}
getRule( selector, body ) {
selector = tools.cleanRollup( selector );
if( this.rules[ selector ] ) {
return "";
} else {
this.addRule( selector, body );
return this.composeCss( selector, body );
}
}
}

View File

@@ -0,0 +1,39 @@
/*
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
*/
export default class cssRules{
style = "";
styleTypes = new Array();
addStyleListener( propertyTerm, cssSuffix ) {
var styleType = new Object();
styleType.propertyTerm = propertyTerm;
styleType.cssSuffix = cssSuffix;
styleType.css = "";
this.styleTypes.push( styleType );
}
}

40
framework/client/debug.js Normal file
View File

@@ -0,0 +1,40 @@
import socketManager from './socketManager.js';
//import highlight from '../node_modules/highlight.js/lib/index.js';
//import core from './core.js';
async function run() {
var socket = new socketManager();
socket.mode = "debug";
await socket.connect();
socket.registerClientType("debug");
//var unifyCore = new core();
//unifyCore.parseServer( app, true );
//unifyCore.loadModulesFromFiles( "./application/" );
//console.log( unifyCore );
//socket.debugMessage();
}
run();

View File

@@ -0,0 +1,314 @@
import tools from '../unify/tools.js';
import socketMessage from '../unify/socketMessage.js';
import unify from '../unify/unify.js';
import groupsFlat from '../server/themeGroups.js';
export default class debug {
objects = new Array();
socketManager = false;
parseFilename( filename ) {
if( filename[0] == "-" ) {
return false;
}
if( !filename ) {
filename = "Unknown";
}
var emtpySpaces = 28 - filename.length;
for( var c = 0; c < emtpySpaces; c++) {
filename += " ";
}
return filename;
}
processDebugMessage( message ) {
switch( message.parameters.action ) {
case "log":
this.logDebugMessage( message );
break;
case "addObject":
this.addDebugObject( message );
break;
case "updateFile":
this.updateFile( message );
break;
}
}
checkVisible( element ) {
return element.offsetWidth > 0 || element.offsetHeight > 0;
}
getVisibleInherites( className, visible ) {
var core = document.cores[0];
this.cacheArray = new Array();
var objects = core.dependencieMap[className];
if( !objects ) {
return false;
}
for (var b = 0; b < objects.length; b++) {
var object = objects[b];
if( tools.isVisible( object.element ) || visible ) {
this.cacheArray.push( object );
}
}
console.log("created cache array", this.cacheArray);
}
async updateFile( message ) {
var parameters = message.parameters;
var file = parameters.file;
var fullPath = file.path + "/" + file.name;
var currentPath = "../cache/platforms/"+document.config.os+"/"+document.config.device+"/"+document.config.tint+"/" + fullPath + "?disableCache=" + Math.random();
console.log("message", message);
console.log("currentPath", currentPath);
var newImport = await import(currentPath);
var newInstance = new newImport.default();
unify.extend( newInstance );
console.log("newInstance", newInstance);
var className = newInstance.getClassName();
this.getVisibleInherites( className, false );
newInstance.create = false;
this.updateMainObjects( newInstance );
this.updateInherites( newInstance );
var that = this;
setTimeout(function(){
that.getVisibleInherites( className, true );
that.updateInherites( newInstance );
}, 1000);
//function () {
//this.getVisibleInherites( className, true );
//this.updateInherites( newInstance );
//}
}
updateInherites() {
var objects = this.cacheArray;
for ( var c = 0; c < objects.length; c++ ) {
var object = objects[c];
this.instantiateInheritence( object );
}
}
updateMainObjects( newInstance ) {
var core = document.cores[0];
var idObjects = core.classObjects[ newInstance.getClassName() ];
if( idObjects ) {
idObjects = idObjects.filter( n => n );
console.log( idObjects );
for ( var i = 0; i < idObjects.length; i++ ) {
var object = idObjects[i];
object.updateProperties( newInstance );
}
}
}
async instantiateInheritence( object ) {
var newConstructor = object.constructor;
if( object.__sourcePath ) {
var currentPath = "../cache/platforms/" + document.config.os + "/" + document.config.device + "/" + document.config.tint +"/" + object.__sourcePath + "?disableCache=" + Math.random();
var newImport = await import( currentPath );
if( newImport.default ) {
var newInstance = new newImport.default();
unify.extend( newInstance );
console.log("Hot swap Unify Object", object.getClassName(), object.element, newInstance["background"]);
var reload = object.updateProperties( newInstance );
}
} else {
console.log("error object doesnt have sourcePath", object);
}
}
addDebugObject( message ) {
var object = cycle.retrocycle( message.parameters.object );
if( object.applicationPathString ) {
console.log( "add object", object );
var div = document.createElement("div");
div.innerHTML = object.applicationPathString;
var socket = this.socketManager.socket;
div.onclick = function(){
console.log( object.applicationPathString );
var message = new socketMessage();
message.controller = "settings";
message.method = "debugObject";
message.object = object.applicationPathString;
socket.send( JSON.stringify( message ) );
this.style.color = "green";
console.log( this.style.color );
};
document.body.appendChild( div );
}
}
logDebugMessage( message ) {
var parameters = message.parameters;
var parameter1 = cycle.retrocycle( parameters.parameter1 );
var parameter2 = cycle.retrocycle( parameters.parameter2 );
var parameter3 = cycle.retrocycle( parameters.parameter3 );
if(parameter1 == "clear_console") {
console.clear();
}
var filename = parameters.filename;
if( parameters.lineNumber ) {
filename += ":" + parameters.lineNumber;
}
filename = this.parseFilename( filename );
if( parameters.parameter3 ) {
console.log( filename, parameter1, parameter2, parameter3 );
} else if( parameters.parameter2 ) {
console.log( filename, parameter1, parameter2 );
} else {
console.log( filename, parameter1 );
}
}
}

291
framework/client/dom.js Normal file
View File

@@ -0,0 +1,291 @@
/*
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 document from '../unify/document.js';
import tools from '../unify/tools.js';
export default class dom{
addDOMToSelector = true;
setElement() {
var objectName = tools.createCSSClassName( object );
element.className = this.getClassName( object.editable, objectName ); //tools.cleanRollup( objectName )
}
getClassName( editable, objectName ) {
if( editable ) {
return objectName + "Element";
} else {
return objectName + "Grid grid";
}
}
createSetter( object ) {
object.__defineSetter__( "text", function( value ){
if( typeof value == "number" ) {
value = value.toString();
}
object.__text = value;
object.updateElementContent();
});
}
createGetter( object ) {
object.__defineGetter__( "text", function(){
return object.__text;
});
}
createSetterAndGetters( object ) {
object.__text = object.text;
this.createSetter( object );
this.createGetter( object );
}
createDOMElements( object, objectName ) {
object.elements = [];
if( object.layers == 2 ) {
object.boxElement = this.createDiv( objectName, "box", object.id );
object.elements.push( object.boxElement );
}
object.defaultElement = this.createDiv( objectName, "grid", object.id );
if( object.useCustomElement ) {
object.element = object.customElement;
} else {
object.element = object.defaultElement;
}
object.elements.push( object.element );
}
addClasses( object, objectName ) {
var type = "Element";
var mainClassName = objectName; //tools.cleanRollup( );
object.customElement.classList.add( mainClassName + type );
object.customElement.classList.add( type );
object.customElement.classList.add( this.device );
object.customElement.classList.add( this.tint );
object.customElement.classList.add( this.os );
}
updateZIndex( object ) {
if( !object.zIndex && object.setZIndex ) {
object.element.style["z-index"] = tools.getApplicationDepth( object );
if( object.inverseZIndex ) {
object.element.style["z-index"] = 1000 - tools.getApplicationDepth( object )
}
}
}
attachUnifyObjectToElements( object ) {
for( var c = 0; c < object.elements.length; c++ ) {
object.elements[ c ].object = object;
}
}
parseObject( object ) {
var objectName = tools.createCSSClassName( object );
this.createDOMElements( object, objectName );
if( object.customElement ) {
this.addClasses( object, objectName );
} else {
object.customElement = object.defaultElement;
}
this.createSetterAndGetters( object );
object.updateElementContent();
this.updateZIndex( object );
this.attachUnifyObjectToElements( object );
if( !object.selector && object.parent && object.addToDom ) {
this.parseProperty( objectName, object, object.parent );
}
}
addElementToDOMParent( object, propertyValue ) {
if( propertyValue.propertyName[0] == "_" ) {
object.elements[ object.elements.length - 1 ].prepend( propertyValue.elements[0] );
} else {
if( object.elements ) {
object.elements[ object.elements.length - 1 ].appendChild( propertyValue.elements[0] );
}
}
}
addElementToBody( propertyValue ) {
document.body.appendChild( propertyValue.elements[0] );
}
parseProperty( propertyName, propertyValue, object ) {
if( tools.isUnifyObject( propertyName, propertyValue ) ) {
if( propertyValue.absolute ) {
this.addElementToBody( propertyValue );
return true;
}
this.addElementToDOMParent( object, propertyValue );
}
}
parseInnerElements( object ){
var elements = object.elements;
for( var c = elements.length - 1; c > 0; c--) {
elements[ c - 1 ].appendChild( elements[c] );
}
if( object.selector && this.addDOMToSelector ) {
this.appendToSelector( object, elements );
}
}
appendToSelector( object, elements ) {
var selector = object.selector;
var element = document.querySelector( selector );
if( element ) {
element.appendChild( elements[0] );
}
}
createDiv( divName, type, id ){
var div = document.createElement("div");
var mainClassName = divName + tools.CamelCase( type.toUpperCase() ); //tools.cleanRollup(
div.classList.add( mainClassName );
if( id ) {
div.classList.add( mainClassName.replace( "_" + id, "" ).replace(id, "") );
}
div.classList.add( type );
div.classList.add( this.device );
div.classList.add( this.tint );
div.classList.add( this.os );
return div;
}
}

216
framework/client/editor.js Normal file
View File

@@ -0,0 +1,216 @@
class editor{
create( applicationThree, selector ) {
//var selector =
//var id = app.selector.replace("#", "");
var playground = document.createElement("div");
playground.className = "playground";
var fileTree = document.createElement("div");
fileTree.className = "_fileTree fileTree";
var textarea = document.createElement("textarea");
playground.appendChild( textarea );
selector.appendChild( playground );
textarea.value = applicationThree.files[0].source;
/*
editor
*/
var filetree = this.createFileTreeMenu( applicationThree, editor );
//filetree = document.createElement("div");
//filetree.className = "";
fileTree.appendChild( filetree );
var outputDiv = document.createElement("div");
outputDiv.className = "outputDiv";
//outputDiv.id = id;
console.log( "applicationThree", applicationThree );
console.log("textarea", textarea);
playground.prepend( fileTree );
//playground.appendChild( outputDiv );
//this.createTreeJS( applicationThree, editor, app.selector );
document.querySelector(".CodeMirror").style.height = "900px";//document.body.clientHeight - 46 + "px";
document.querySelector(".fileTree").style.height = "569px";//document.body.clientHeight - 46 + "px";
//document.querySelector(".outputDiv").style.height = "569px";//document.body.clientHeight - 46 + "px";
var documentWidth = document.body.clientWidth;
var editorWidth = document.querySelector(".CodeMirror").clientWidth;
var fileTreeWidth = document.querySelector(".fileTree").clientWidth;
//document.querySelector(".outputDiv").style.width = documentWidth - ( fileTreeWidth + editorWidth ) - 12 + "px";
var outputDiv = document.createElement("div");
outputDiv.className = "outputDiv";
//outputDiv.id = id;
selector.appendChild( outputDiv );
/*
const ps = new PerfectScrollbar(selector, {
wheelSpeed: 2,
wheelPropagation: true,
minScrollbarLength: 20
});
*/
return editor;
}
createFileTreeMenu( applicationThree, editor ) {
var fileList = this.createFileTreeMenuItem( applicationThree, true, editor );
return fileList;
}
createFileTreeMenuItem( file, first, editor ) {
var files = file.files;
var fileList = document.createElement("li");
var row = document.createElement("div");
var label = document.createElement("div");
if( file.type == "directory" ) {
row.className = "caret";
row.state = "closed";
row.onclick = function() {
this.parentElement.querySelector(".nested").classList.toggle("active");
this.querySelector(".directory_icon").classList.toggle("open_directory");
if( this.state == "closed" ) {
this.state = "open";
} else {
this.state = "closed";
}
}
var icon = document.createElement("div");
icon.className = "directory_icon";
row.prepend( icon );
} else {
var icon = document.createElement("div");
icon.className = "file_icon";
row.prepend( icon );
}
row.className = "file_row";
label.innerText = file.name;
row.appendChild( label );
if( file.type == "file" ) {
row.onclick = function() {
if(document.querySelectorAll(".file_row.highlighted").length > 0) {
document.querySelector(".file_row.highlighted").classList.toggle("highlighted");
}
this.classList.toggle("highlighted");
var mode = {name: "javascript"};
var codeMirrorDocument = CodeMirror.Doc( file.source, mode );
//editor.swapDoc( codeMirrorDocument );
// alternative
}
}
fileList.appendChild( row );
var treeMenu = document.createElement("ul");
if( !first ) {
treeMenu.className = "nested"
}
for( var c = 0; c<files.length;c++ ) {
var childFile = files[c];
var childList = this.createFileTreeMenuItem( childFile, false, editor );
treeMenu.appendChild( childList );
}
fileList.appendChild( treeMenu );
if(first) {
return treeMenu;
}
return fileList;
}
}
export default new editor();

26
framework/client/event.js Normal file
View File

@@ -0,0 +1,26 @@
/*
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
*/
export default class event {
name;
className;
callback;
}

View File

@@ -0,0 +1,440 @@
/*
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 vector2 from '../unify/math/vector2.js';
import event from './event.js';
import tools from '../unify/tools.js';
export default class eventManager{
events = new Array();
eventTerms = new Array();
constructor() {
var prototype = Object.getPrototypeOf( document.body );
var innerPrototype = Object.getPrototypeOf( prototype );
var objectProperties = Object.getOwnPropertyNames( innerPrototype );
var eventProperties = objectProperties.filter( this.filterEvent );
var properEventTerms = eventProperties.map( this.removeOn );
// console.log( "properEventTerms", JSON.stringify( properEventTerms ) );
this.eventTerms = properEventTerms;
}
filterEvent( name ) {
if( name[0] == "o" && name[1] == "n" ){
return true;
} else {
return false;
}
}
removeOn( name ) {
return name.substr( 2, name.length );
}
addClientEvent( className, eventName, callback ) {
var newEvent = new event();
newEvent.className = className;
newEvent.name = eventName;
newEvent.callback = callback;
this.events.push(newEvent);
}
getClientEvents( classname, eventName ){
var events = [];
for(var c = 0; c<this.events.length; c++) {
var event = this.events[c];
if( event.className == classname && event.name == eventName ) {
events.push( event );
}
}
return events;
}
parentHasEvent( object, eventTerm ) {
if( !object ) {
return false;
}
if( object[ eventTerm ] ) {
return true;
}
if( object.parent ){
return this.parentHasEvent( object.parent, eventTerm );
} else {
return false;
}
}
update_value( object ) {
if( object.value && object.value != "undefined" ) {
object._value = object.value;
}
}
createInputSetter( object, element ) {
object.__defineSetter__( "value", function( value ){
if( object.datatype == "BOOLEAN" ) {
object._value = value;
element.value = object._value;
}
if( value && value != undefined && value != "undefined" ) {
object._value = value;
element.value = object._value;
}
if( value == "" ) {
object._value = "";
element.value = "";
}
if( typeof value == "number" ) {
object._value = value;
element.value = object._value;
}
});
}
createUploadSetter( object, element ) {
object.__defineSetter__( "value", function( value ){
if( value != "undefined" ) {
object._value = value;
}
if( element.value ) {
//element.value = value;
}
});
}
createSetter( object, element ) {
this.update_value( object );
if( object.inputType != "file" ) {
this.createInputSetter( object, element );
} else {
this.createUploadSetter( object, element );
}
}
createGetter( object ) {
object.__defineGetter__( "value", function( value ){
if( typeof object._value == "undefined" ) {
return "";
} else {
return object._value;
}
});
}
parseEvents( object ){
if( object.defaultElement ) {
this.createSetter( object, object.defaultElement );
this.createGetter( object );
}
if( object.customElement ) {
this.createSetter( object, object.customElement );
this.createGetter( object );
}
var eventTerms = this.eventTerms;
for(var c = 0; c<eventTerms.length; c++) {
var eventTerm = eventTerms[ c ];
this.parseEvent( object, eventTerm );
}
}
defineEventCallback( object, element, eventTerm ) {
var eventManager = this;
if( !this.parentHasEvent( object.parent, eventTerm ) || object.selector ) {
var eventNormalized = eventTerm.replace("box", "");
if( object.getClassName() != "fileChooserSelectButton" ){
element[ "on" + eventNormalized ] = function( event ) { eventManager.createEventCallback( event, eventManager ); };
}
}
}
createWindowResizeEventListener( object ) {
/*
if( object.parent && object.parent["windowResize"] ) {
window.addEventListener("resize", function(){
object.parent.windowResize();
})
object.parent.windowResize();
}
if( object["windowResize"] ) {
window.onresize = function() {
object.windowResize();
}
object.windowResize();
}
*/
}
parseElement( object, element, eventTerm, box = false ) {
element.object = object;
element.eventTerm = eventTerm;
this.defineEventCallback( object, element, eventTerm );
//this.createWindowResizeEventListener( object );
}
parseDefaultElement( object, eventTerm ) {
if( object[ eventTerm ] ) {
this.parseElement( object, object.defaultElement, eventTerm );
if( object.customElement ) {
this.parseElement( object, object.customElement, eventTerm );
}
}
}
parseBoxElement( object, eventTerm ) {
if( object[ "box" + tools.CamelCase( eventTerm ) ] ) {
if( object.boxElement ) {
var element = object.boxElement;
} else {
var element = object.defaultElement;
}
this.parseElement( object, element, "box" + tools.CamelCase( eventTerm ), true );
}
}
parseEvent( object, eventTerm ) {
this.parseDefaultElement( object, eventTerm );
this.parseBoxElement( object, eventTerm );
}
callMethod( object, event, eventTerm ) {
if( object[ eventTerm ] ) {
object.lastEvent = eventTerm;
object[ eventTerm ]( event, object );
}
}
createEventListener( event, object, box = false ) {
var eventTerm = event.type.replace("on", "");
if( box ) {
eventTerm = "box" + tools.CamelCase( eventTerm );
}
this.callMethod( object, event, eventTerm );
if( !object.isRoot && object.parent ) {
if( object.propegateEvent ) {
this.createEventListener( event, object.parent );
}
}
}
createEventListeners( event, target, eventManager, object ) {
if( object.boxElement && target.className == object.boxElement.className ) {
eventManager.createEventListener( event, object, true );
} else if( target.className == object.defaultElement.className ) {
eventManager.createEventListener( event, object );
} else if( target.className == object.customElement.className ) {
eventManager.createEventListener( event, object );
}
}
logEvent( event, target ) {
//console.log( "Event triggered", event.type.replace("on", ""), target, target.object );
}
createEventCallback( event, eventManager ) {
var target = event.target;
var object = target.object;
if( !object ) {
console.error("This element does not have an object", target);
return false;
}
this.logEvent( event, target );
this.createEventListeners( event, target, eventManager, object );
}
}

View File

@@ -0,0 +1,75 @@
/*
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
*/
export default class fileLoader{
files = new Array();
filesExists = new Array();
async get( url ) {
return await this.getFile( url );
}
exists( url )
{
if( this.filesExists[ url ] ) {
return this.filesExists[ url ];
}
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
this.filesExists[ url ] = http.status != 404;
return http.status != 404;
}
async getFile( url ) {
if( this.files[ url ] ) {
return this.files[ url ];
} else {
var response = await fetch( url );
var json = await response.json();
this.addFile( url, json );
return json;
}
}
addFile( url, json ) {
this.files[ url ] = json;
}
}

View File

@@ -0,0 +1,2 @@
import bundle0 from "../../framework/cache/platforms/Windows/Pc/Dark/demo/application.js"
export default [bundle0];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../android/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../ios/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../windows/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1,2 @@
export default [];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../../platform_cache/android/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../../platform_cache/ios/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1,3 @@
import bundle0 from "../../platform_cache/windows/news/application.js"
export default [bundle0];

View File

@@ -0,0 +1 @@
export default {};

126
framework/client/index.js Normal file
View File

@@ -0,0 +1,126 @@
/*
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 applicationManager from './applicationManager.js';
import timer from './timer.js';
import tools from '../unify/tools.js';
import vector2 from '../unify/math/vector2.js';
document.states = new Array();
window.addEventListener('popstate', function( event ) {
console.log( "popstate tiggered", event, event.state.id );
var stateMachine = document.stateMachine;
console.log( stateMachine );
var state = stateMachine.getState( event.state.id );
console.log( "stateMachine.getState", state, state.id );
state.triggerEvents();
//var table = state.table;
//table.id = state.id;
//table.sync( false, true, false );
}, false);
// Set globals
document.globalZIndex = 2000;
document.animationID = 0;
document.keyframeID = 0;
document.timer = new timer();
if( !document.extendMap ) {
document.extendMap = new Array();
}
function main() {
document.timer.lap("start");
//createGlobalMouseEventListener() {
document.mouse = new vector2(0,0);
document.mouseVelocity = new vector2(0,0);
var lastMouseUpdate = Date.now();
var previousMouse = new vector2(0,0);
document.body.addEventListener('mousemove', function( bodyEvent ) {
if( document.mouse ) {
previousMouse = document.mouse;
document.mouse = new vector2( bodyEvent.clientX, bodyEvent.clientY );
var delta = Date.now() - lastMouseUpdate;
var differenceX = document.mouse.x - previousMouse.x;
var differenceY = document.mouse.y - previousMouse.y;
document.mouseVelocity = new vector2( differenceX / delta, differenceY / delta );
lastMouseUpdate = Date.now();
} else {
document.mouse = new vector2( bodyEvent.screenX, bodyEvent.screenY );
}
});
//}
var applications = new applicationManager();
applications.start();
document.launcher = applications;
}
document.onload = main();

View File

@@ -0,0 +1,146 @@
/*
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 tools from '../../unify/tools.js';
import unify from '../../unify/unify.js';
//import unParsedObjects from '../unparsed.js'
export default class processManagerAdd{
createPath( sourcePath, random = false ) {
var currentPath = "../cache/platforms/" + document.config.os + "/" + document.config.device + "/" + document.config.tint + "/" + sourcePath;
if( random ) {
currentPath += "?disableCache=" + Math.random();
}
return currentPath;
}
async createObject( objectData ) {
if( document.mode == "development" ) {
var currentPath = "../" + this.createPath( objectData.__sourcePath, true );
console.log("loading???", currentPath);
var newImport = await import( currentPath );
var object = new newImport.default();
} else {
var currentPath = this.createPath( objectData.__sourcePath );
//var object = new unParsedObjects[currentPath]();
}
return object;
}
configureObject( object, applicationPath, objectData ) {
var core = document.cores[0];
var propertyName = applicationPath.shift();
var parent = core.getObjectByPath( applicationPath );
unify.extend( object );
object.serialize( objectData );
object.propertyName = propertyName;
object.dynamic = true;
object.parent = parent;
parent[ propertyName ] = object;
}
logObject( message ) {
var className = tools.getClassNameByObject( message.data );
var type = message.type;
console.log("--------------------- recieved message: " + className + " : "+ type +"---------------------");
}
parseObject( object ) {
var core = document.cores[0];
core.executeMethods = true;
core.parse( object );
object.show();
}
setObjectID( object ) {
if( !object.id ) {
console.log("debug", this);
object.id = object.getChildren().length;
}
}
async process( message ) {
var objectData = tools.getFirstChild( message.data );
this.logObject( message );
var object = await this.createObject( objectData );
var applicationPath = message.applicationPath;
this.configureObject( object, applicationPath, objectData );
this.setObjectID( object );
this.parseObject( object );
}
}

View File

@@ -0,0 +1,84 @@
/*
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 processManagerAdd from "./processManager.add.js";
import processManagerUpdate from "./processManager.update.js";
import processManagerPromise from "./processManager.promise.js";
import debugManager from "../debugManager.js";
export default class processManager{
add = new processManagerAdd();
update = new processManagerUpdate();
promise = new processManagerPromise();
debugger = new debugManager();
process( content ) {
var message = JSON.parse( content.data );
switch( message.type ) {
case "promise":
this.promise.process( message );
break;
case "clientUpdate":
this.update.process( message );
break;
case "addObject":
this.add.process( message );
break;
case "debug":
console.log( "debug", message,this.mode );
//if( this.mode == "debug" ) {
this.debugger.processDebugMessage( message );
//}
break;
case "logClient":
console.log( "----------------- Log client", this.application.selector, message );
break;
default:
}
}
}

View File

@@ -0,0 +1,44 @@
/*
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 tools from '../../unify/tools.js';
export default class processManagerPromise{
process( message ) {
var promise = this.promiseManager.getPromiseByID( message.id );
this.promiseManager.addMessage( message );
promise.resolve();
var object = message.data;
if( object && typeof object == "object" && !Array.isArray( object ) ) {
var className = tools.getClassNameByObject( object );
if( promise.object.debug | document.debugALL ) {
console.log( "%c recieved message: ", "background: #8bc34a;", this.port, message, className );
}
}
}
}

View File

@@ -0,0 +1,170 @@
/*
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 unify from '../../unify/unify.js';
export default class processManagerUpdate{
process( message ) {
var object = message.data;
var className = tools.getClassNameByObject( object );
console.log("--------------------- recieved message: " + className + " : "+ message.type +"---------------------");
switch( className ) {
case "collection":
this.parseCollection( message );
break;
default:
this.parseObject( message );
}
console.log("--------------------- /recieved message: " + className + " ----------------------");
}
filter( objects ) {
var objectCollection = new collection();
objectCollection.set( this.core.objects );
objectCollection.filter( "type", "renderCollection" );
objectCollection.filter( "custom", function( object ){
var collection = object.getCollection();
if( collection.applicationPathString == applicationPathString ) {
return true;
}
});
return objectCollection.rows;
}
fetchRenderCollections( renderCollections ) {
for( var c = 0; c < renderCollections.length; c++ ) {
var renderCollection = renderCollections[c];
console.log( "renderCollection", renderCollection );
renderCollection.clear();
renderCollection.fetch();
}
}
logRenderCollection( message, objectCollection ) {
console.log( "parse collection", message );
console.log( "search renderCollection", objectCollection );
}
parseCollection( message ) {
var applicationPath = message.applicationPath;
//var objectCollection = this.core.getObjectByPath( applicationPath );
var collectionName = applicationPath[ 0 ];
var applicationPathString = applicationPath.join("/");
var renderCollections = this.filter( this.core.objects );
this.fetchRenderCollections( renderCollections );
this.logRenderCollection( message, objectCollection );
}
getObject( message ) {
var entry = tools.parseObject( message.data );
var className = tools.getClassNameByEntry( entry );
var object = tools.getObjectByEntry( entry );
unify.extend( object );
return object;
}
callMethod( application, eventName, object ) {
application[ "server" + tools.CamelCase( eventName ) ]( object );
}
filterApplication( objects, className, id ) {
var objectCollection = new collection();
objectCollection.set( objects );
objectCollection.filter( "class", className );
objectCollection.filter( "id", id );
var application = objectCollection.getFirstRow();
return application;
}
parseObject( message ) {
var object = this.getObject( message );
// Can be optimized client->core
var className = object.getClassName();
var id = object.id;
var eventName = message.eventName;
this.filterApplication( this.core.objects, className, id )
application.serialize( object );
this.callMethod( application, eventName, object );
this.logRecieveMessage( message );
}
}

View File

@@ -0,0 +1,49 @@
/*
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
*/
export default class progressBar{
progress = 0;
element = document.querySelector(".progressBar");
set( newProgress ) {
var difference = newProgress - this.progress;
this.progress = newProgress;
//console.log("difference", difference, newProgress);
}
setApplicationProgress( newProgress, applicationID ) {
var beforeProgress = 40;
var currentApplicationProgress = ( newProgress / document.applications.length );
var currentProgress = currentApplicationProgress * applicationID;
var progress = beforeProgress + currentProgress;
this.set( progress )
this.progress = progress;
}
}

View File

@@ -0,0 +1,98 @@
/*
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
*/
export default class promiseManager{
promises = new Array();
messages = new Array();
socketManager;
addPromise( promiseObject ) {
this.promises.push( promiseObject );
}
addMessage( message ) {
this.messages.push( message );
}
getPromiseByID( id ) {
var promises = this.promises;
for(var c = 0; c<promises.length; c++) {
var currentPromise = promises[c];
if( currentPromise.id == id ) {
return currentPromise;
}
}
console.error("Promise with id " + id + " not found:", this);
return false;
}
getMessageByID( id ) {
var messages = this.messages;
for(var c = 0; c<messages.length; c++) {
var message = messages[c];
if( message.id == id ) {
return message;
}
}
}
createPromiseFunction( messageID, object = false ) {
var promiseManager = this;
function promiseFunction( resolveFunction ){
var promiseObject = {};
promiseObject.id = messageID;
promiseObject.resolve = resolveFunction;
promiseObject.object = object;
promiseManager.addPromise( promiseObject );
}
return promiseFunction;
}
}

View File

@@ -0,0 +1,418 @@
export default class queryManager{
selectors = new Array();
createSelector( character, name ) {
var selector = new Object();
selector.character = character;
selector.name = name;
this.selectors.push( selector );
}
constructor() {
this.createSelector( "#", "id" )
this.createSelector( ":", "selector" )
this.createSelector( "@", "propertyName" )
}
query( query, unifyObject ) {
var terms = query.split(" ");
var objectSelection = new Array( unifyObject );
for ( var i = 0; i < terms.length; i++ ) {
var term = terms[i];
objectSelection = this.processTerm( term, objectSelection );
}
//console.log( objectSelection );
return objectSelection;
}
clone( object ) {
return JSON.parse( JSON.stringify( object ) )
}
processTerm( term, objectSelection ) {
//console.log("\n\n" )
//console.log( "process term", term );
var newSelection = new Array();
for (var j = 0; j < objectSelection.length; j++) {
var currentObjectSelection = objectSelection[j];
var selected = this.processSelector( term, currentObjectSelection );
newSelection = [...newSelection, ...selected]
}
return newSelection;
}
processSelector( term, objectSelection ) {
var allSelectors = new Array();
for ( var j = 0; j < this.selectors.length; j++ ) {
var selector = this.selectors[j];
var indices = this.getIndicesOf( selector.character, term );
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
var uniuqeSelector = this.clone( selector );
uniuqeSelector.startIndex = index;
allSelectors.push( uniuqeSelector );
}
}
var sortedSelectors = allSelectors.sort( function ( a, b ) { return a.startIndex - b.startIndex } );
var firstSelector = sortedSelectors[0];
//console.log(allSelectors);
if( firstSelector ) {
var startIndex = firstSelector.startIndex;
} else {
var createFirstSelector = true;
}
if( createFirstSelector || startIndex != 0 ) {
var selector = new Object();
selector.character = "";
selector.name = "className";
selector.startIndex = 0;
sortedSelectors = this.addItemToStartOfArray( sortedSelectors, selector );
}
for (var i = 0; i < sortedSelectors.length; i++) {
var selector = sortedSelectors[i];
var nextSelector = sortedSelectors[i+1];
var currentStartIndex = selector.startIndex;
if( nextSelector ) {
var nextStartIndex = nextSelector.startIndex;
} else {
var nextStartIndex = term.length;
}
selector.term = term.substr( currentStartIndex + selector.character.length, nextStartIndex - currentStartIndex - selector.character.length );
}
var objectSelection = new Array( objectSelection );
//console.log(" process selector", term, sortedSelectors)
for ( var i = 0; i < sortedSelectors.length; i++ ) {
//console.log(" executeSelector", objectSelection);
var selector = sortedSelectors[i];
objectSelection = this.executeSelector( selector, objectSelection );
//console.log( " objectSelection", objectSelection );
}
//console.log( " objectSelection", objectSelection );
return objectSelection;
}
executeSelector( selector, ObjectSelection ) {
var name = selector.name;
switch( name ) {
case "className":
var allSelectors = new Array();
for (var i = 0; i < ObjectSelection.length; i++) {
var currentUnifyObject = ObjectSelection[i];
//console.log(currentUnifyObject);
//console.log(" currentUnifyObject.findAll( selector.term )", selector.term);
// by class name
var results = currentUnifyObject.findAll( selector.term );
allSelectors = [...allSelectors, ...results]
}
ObjectSelection = allSelectors
//console.log(" afterObjectSelection", ObjectSelection);
break;
case "propertyName":
if( selector.startIndex == 0 ) {
var allSelectors = new Array();
for (var i = 0; i < ObjectSelection.length; i++) {
var currentUnifyObject = ObjectSelection[i];
var results = currentUnifyObject.getByPropertyName( selector.term );
allSelectors = [...allSelectors, ...results]
}
ObjectSelection = allSelectors
} else {
for (var i = 0; i < ObjectSelection.length; i++) {
var currentUnifyObject = ObjectSelection[i];
//console.log("currentUnifyObject.findChildByID( selector.term )", selector.term);
if( currentUnifyObject.propertyName == selector.term ) {
return new Array( currentUnifyObject );
} else {
return new Array( );
}
// by class name
//ObjectSelection = currentUnifyObject.getChildById( selector.term );
}
}
break;
case "id":
if( selector.startIndex == 0 ) {
var allSelectors = new Array();
for (var i = 0; i < ObjectSelection.length; i++) {
var currentUnifyObject = ObjectSelection[i];
var results = currentUnifyObject.getByID( selector.term );
allSelectors = [...allSelectors, ...results]
}
ObjectSelection = allSelectors
} else {
for (var i = 0; i < ObjectSelection.length; i++) {
var currentUnifyObject = ObjectSelection[i];
//console.log("currentUnifyObject.findChildByID( selector.term )", selector.term);
if( currentUnifyObject.id == selector.term ) {
return new Array( currentUnifyObject );
} else {
return new Array( );
}
// by class name
//ObjectSelection = currentUnifyObject.getChildById( selector.term );
}
}
break;
case "selector":
var term = selector.term;
switch( term ) {
case "first-child":
//console.log("return ObjectSelection[0];", term);
if( ObjectSelection[0] ) {
return new Array( ObjectSelection[0] );
} else {
return new Array( );
}
break;
case "last-child":
//console.log("return ObjectSelection[ObjectSelection.length-1]", term);
var lastObject = ObjectSelection[ObjectSelection.length-1];
if( lastObject ) {
return new Array( lastObject );
} else {
return new Array( );
}
break;
}
break;
}
return ObjectSelection;
}
addItemToStartOfArray( array, newFirstElement ) {
return [ newFirstElement ].concat( array )
}
getIndicesOf( searchStr, str, caseSensitive ) {
var searchStrLen = searchStr.length;
if ( searchStrLen == 0 ) {
return new Array();
}
var startIndex = 0;
var index;
var indices = new Array();
if ( !caseSensitive ) {
str = str.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ( ( index = str.indexOf( searchStr, startIndex ) ) > -1 ) {
indices.push( index );
startIndex = index + searchStrLen;
}
return indices;
}
}

View File

@@ -0,0 +1,504 @@
/*
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 tools from '../unify/tools.js';
import defaultObject from '../unify/defaultObject.js';
import omitMethods from "../unify/omitMethodNames.js";
import unify from '../unify/unify.js';
//import cacheString from '../../assets/cache/cache.js'
var cache;
async function loadCache() {
var randomInt = Math.floor( Math.random() * 100000 );
var cacheString = await import('../../assets/cache/cache.js?random=' +randomInt );
cache = JSON.parse( cacheString.default );
}
loadCache();
export default class renderCollection{
__className = "renderCollection";
methodCache = new Array();
//create() {
// this.fetch();
//}
synced = false;
clearOnSync = true;
cache = false;
cacheLastModified = false;
useCache = false;
async updateCache() {
var randomInt = Math.floor( Math.random() * 100000 );
var cacheString = await import('../../assets/cache/cache.js?random=' +randomInt );
cache = JSON.parse( cacheString.default );
}
clearRenderCollection() {
var collection = this.getCollection();
if( collection ) {
collection.clear();
}
var children = this.getChildren();
for( var c = 0; c < children.length; c++ ) {
var child = children[ c ];
child.remove();
}
this.defaultElement.innerHTML = "";
}
async sync() {
await this.fetch();
this.getCore().createDependencyMap();
return true;
}
hasURL() {
var hasUrl = false
if( this.parent.type != "table" ) {
hasUrl = true;
}
if( this.parent.type == "renderCollection" ) {
hasUrl = false;
}
if( this.title && this.title.value == "" ) {
hasUrl = false;
}
if( !this.title ) {
hasUrl = false;
}
return hasUrl;
}
composePath() {
var urlPath = new Array();
urlPath.push( this.propertyName );
if( this.id ) {
urlPath.push( this.id );
}
if( this.title ) {
if( this.title.value == "" ) {
urlPath.push( this.propertyName.replaceAll(" ", "_") + ".html" );
} else {
urlPath.push( this.title.value.replaceAll(" ", "_") + ".html" );
}
} else {
urlPath.push( this.propertyName.replaceAll(" ", "_") + ".html" );
}
return urlPath.join("/");
}
async createUrl( pass ) {
var hasURL = this.hasURL();
if( hasURL || pass ) {
var path = this.composePath();
var state = new Object();
state.id = this.id;
state.applicationPath = this.applicationPath;
var url = window.location;
await history.pushState( state, "Unify", "/" + path );
}
}
cleanChildren( object ) {
if( this.rows ) {
this.rows = new Array();
}
if( object.getChildren ) {
var children = object.getChildren();
for (var i = 0; i < children.length; i++) {
var child = children[i];
if( child.rowID ) {
console.log("delete", child.propertyName);
delete this[ child.propertyName ];
}
this.cleanChildren( child );
}
}
}
logRenderCollection() {
if( this.debug || document.debugALL ) {
console.log( "" );
console.log("%c renderCollection::fetch", "background: #a6e22e;", this.getClassName() );
console.log( this );
}
}
async recreateCache() {
var cacheDateTime = await this.core.socketManager.get( "settings", "recreateCache", this, "recreateCache", false );
this.core.socketManager.get( "table", "get", this, "fetch", false );
}
async fetch( ) {
this.logRenderCollection();
this.rows = new Array();
if( this.core ) {
//var result = await this.core.socketManager.get( "table", "get", this, "fetch" );
if( this.useCache && !this.id ) {
var cacheDateTime = await this.core.socketManager.get( "settings", "getCacheDateTime", this, "fetch", false );
if( !this.cacheLastModified ) {
this.cacheLastModified = cacheDateTime;
}
if( this.cacheLastModified != cacheDateTime ) {
console.log("cache has been modified, reloading cache.");
await this.updateCache();
this.cacheLastModified = cacheDateTime;
} else {
console.log("Use old cache because cache has not been modified.");
}
var currentCache = cache[ this.getClassName() ];
if( currentCache ) {
this.core.socketManager.get( "table", "get", this, "fetch", false );
result = currentCache;
} else {
console.log("dont use cache, await fetch");
var result = await this.core.socketManager.get( "table", "get", this, "fetch" );
}
} else {
var result = await this.core.socketManager.get( "table", "get", this, "fetch" );
}
this.synced = true;
if( this.clearOnSync ) {
this.empty();
console.log("empty renderCollection");
this.rows = new Array();
}
await this.parseRows( result.rows );
this.getCore().communicateVisibleElements();
}
return true;
}
remapCurrentMethod( object ) {
var className = object.__className;
var methods = this.methodCache[ className ];
if( methods ){
const keys = Object.keys(methods);
for (var i = 0; i < keys.length; i++) {
var methodName = keys[i]
object[ methodName ] = this.methodCache[className][methodName];
}
}
}
remapMethods( object ) {
unify.extend( object, true );
this.remapCurrentMethod( object );
var children = object.getChildren();
for( var c = 0; c < children.length; c++ ) {
var child = children[c];
this.remapMethods( child );
}
}
deleteProperties() {
if( object.elements ) {
for (var i = 0; i < object.elements.length; i++) {
delete object.elements[i];
}
}
delete object.element;
delete object.customElement;
delete object.boxElement;
delete object.defaultElement;
delete object.user;
delete object.fileLoader;
}
copyMethods() {
var properties = Object.getOwnPropertyNames( object )
for (var j = 0; j < properties.length; j++) {
var methodName = properties[ j ]
if( typeof object[ methodName ] == "function" ) {
this.methodCache[ className ][ methodName ] = object[ methodName ];
object[ methodName ] = false;
}
}
var methods = tools.getAllFuncs( object );
for (var i = 0; i < methods.length; i++) {
methodName = methods[ i ];
this.methodCache[ className ][ methodName ] = object[ methodName ];
}
}
removeDOM( object ) {
var className = object.getClassName();
if( !this.methodCache[className] ) {
this.methodCache[ className ] = new Array();
}
this.deleteProperties();
this.copyMethods();
var children = object.getChildren();
for( var c = 0; c < children.length; c++ ) {
var child = children[c];
this.removeDOM( child );
}
}
async parseRows( rows ) {
var promises = new Array();
if( !rows || !Array.isArray(rows) ) {
console.log("rows doesnt contain an array.", rows, this);
return false;
}
for( var c = 0; c < rows.length; c++ ) {
var object = rows[ c ];
object = this.addRowSync( object, false, c );
this.rows.push( object );
}
await Promise.all( promises );
return true;
}
serializeRenderCollection( object ) {
if( object.rows && tools.isArray( object.rows ) ) {
var rows = object.rows;
var rows = new Array();
for( var c = 0; c < rows.length; c++ ) {
var object = rows[ c ];
var object = targetObject.addRow( object, false, c );
rows.push( object );
}
}
}
}

View File

@@ -0,0 +1,4 @@
import simplePathBase from "../unify/simplePath.js";

View File

@@ -0,0 +1,691 @@
/*
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 tools from '../unify/tools.js';
import socketMessage from '../unify/socketMessage.js';
import promiseManager from './promiseManager.js';
import collection from './collection.js';
//import debugManager from './debugManager.js';
import unify from '../unify/unify.js';
import defaultObject from '../unify/defaultObject.js';
//import unParsedObjects from './unparsed.js'
import processManager from "./processManager/processManager.js"
import ajaxSocket from './ajaxSocket.js'
document.requests = new Array();
export default class socketManager{
promiseManager = new promiseManager();
//debugger = new debugManager();
processManager = new processManager();
socket = false;
mode = "client";
state = "disconnected";
serverAddress = "localhost";
messageID = 0;
tries = 0;
port = 5002;
ssl = false;
promises = new Array();
constructor( port ) {
this.promiseManager.socketManager = this;
this.processManager.promise.promiseManager = this.promiseManager;
//this.debugger.socketManager = this;
document.socketManager = this;
if( port ) {
this.port = port;
}
}
getSocketAddress() {
if( !this.ssl ) {
console.log( "%c Trying to connect with server on host: ws://" + this.serverAddress + ":" + this.port, "background: yellow;" );
var socketAddress = "ws://" + this.serverAddress + ":" + this.port;
} else {
console.log( "%c Ssl set to true, Tying to create Secure connection with server on host: wss://" + this.serverAddress.split(":")[0], "background: yellow;" );
var socketAddress = "wss://" + this.serverAddress.split(":")[0] + ":" + this.port ;// + ":" + this.port
}
return socketAddress;
}
createSocket() {
var socketManager = this;
var socketAddress = this.getSocketAddress()
this.socket = new WebSocket( socketAddress );
var promiseManager = this.promiseManager;
this.socket.onclose = function(){ socketManager.onClose() };
this.socket.onopen = function(){ socketManager.onOpen() };
}
pingServer() {
var message = new socketMessage();
message.controller = "ping";
this.socket.send( JSON.stringify( message ) );
var that = this;
setTimeout( function(){ that.pingServer() }, 5000 );
}
async connect() {
var promiseManager = this.promiseManager;
promiseManager.promises = new Array();
promiseManager.messages = new Array();
this.messageID = 0;
this.createSocket();
var promiseFunction = promiseManager.createPromiseFunction( this.messageID );
var promise = new Promise( promiseFunction );
await promise;
var message = promiseManager.getMessageByID( this.messageID );
this.logRecieveMessage( message );
this.messageID++;
this.pingServer();
return message.applications;
}
logRecieveMessage( message ) {
//console.log( "Client recieved message via socket: ", message );
var className = tools.getClassNameByObject( message );
if( document.debugALL ) {
console.log("");
console.log( "%c recieved message: ", "background: #8bc34a;" );
console.log( "className: ", className);
console.log( message );
console.log("");
}
}
onOpen() {
console.log("%c Connected to Socket server", "background: green;");
this.state = "connected";
this.registerClientType( this.mode );
this.createEventListeners();
}
logAjaxConnection( data ) {
console.log( "first message recieved", data );
console.log( "sessionKey", this.sessionKey );
}
async registerClient( sessionKey ) {
var promiseManager = this.promiseManager;
var promiseFunction = promiseManager.createPromiseFunction( this.messageID );
var promise = new Promise( promiseFunction );
var message = new socketMessage();
message.id = this.messageID;
if( this.sessionKey ) {
message.type = "reconnectClient";
message.object = this.sessionKey;
} else {
message.type = "registerClient";
message.object = "none";
}
console.log("message", message);
this.socket.send( JSON.stringify( message ) );
console.log("awaiting promise");
await promise;
var message = promiseManager.getMessageByID( this.messageID );
this.messageID++
console.log("promise recieved", message);
}
disconnect() {
this.socket.close();
}
async addClient() {
var promiseManager = this.promiseManager;
this.messageID++;
var messageID = this.messageID;
var data = await this.registerClient( );
var message = promiseManager.getMessageByID( messageID );
this.sessionKey = message.data.sessionKey;
return message;
}
createAjaxSocketClass() {
var that = this;
return class ajaxSocket{
async send( message ) {
var json = JSON.parse( message );
json.sessionKey = new String( that.sessionKey );
message = JSON.stringify( json );
var result = await that.fetch( message );
var a = new Object();
a.data = result;
that.message( a )
}
}
}
async connectAjax() {
var message = new Object();
message.eventName = "connect";
var data = await this.fetch( JSON.stringify( message ) );
this.sessionKey = new String( JSON.parse( data ).sessionKey );
this.logAjaxConnection( data );
//this.socket = new ajaxSocket();
this.socket = this.createAjaxSocketClass();
this.registerClientType( this.mode );
}
async fetch( jsonString ) {
const response = await fetch(
"/api/",
{
body: jsonString,
method:'post',
headers:{
"Accept": "application/json, text/plain, */*",
"Content-type": "application/json; charset = UTF-8"
},
}
);
return response.json();
}
onClose() {
this.state = "disconnected";
this.tries++;
this.reconnect();
this.retry();
}
retry() {
// Ajax fallback
// todo disabled because android requires reconnection
/*
if( this.tries < 1 ) {
this.reconnect();
} else {
console.log("connect ajax");
var message = this.connectAjax();
//this.message( content );
}
*/
}
async reconnect() {
await this.connect();
this.registerClient( this.sessionKey );
}
createEventListeners() {
var socketManager = this;
this.socket.onmessage = function( content ) { socketManager.message( content ) }
}
registerClientType( type ) {
this.mode = type;
var message = new socketMessage();
message.controller = "settings";
message.method = "setType";
message.path = new Array();
message.object = type;
this.socket.send( JSON.stringify( message ) );
}
signin( user ) {
var message = new socketMessage();
message.controller = "settings";
message.method = "signIn";
message.object = user;
this.socket.send( JSON.stringify( message ) );
}
async signOut() {
var message = new socketMessage();
message.controller = "settings";
message.method = "signOut";
this.get( "settings", "signOut", new Object() );
}
message( content ) {
this.processManager.process( content );
}
createMessage( messageID, controller, method, eventName, object, data ) {
var message = new socketMessage();
message.id = messageID;
message.controller = controller;
message.method = method;
message.parse = object.parse;
message.data = data;
message.eventName = eventName;
if( object.getClassName ) {
message.object = object.clean( method )[ object.getClassName() ];
if( object.nodeMethodArguments && method == "callNodeMethod" ) {
message.object.nodeMethodName = tools.validateValue( object.nodeMethodName );
message.object.nodeMethodArguments = tools.validateValue( object.nodeMethodArguments );
}
message.applicationPath = tools.getApplicationPath( object );
} else {
message.object = object;
}
if( typeof object == "string" ) {
message.object = object;
}
return message;
}
createPromise( promiseFunction ) {
var promise = new Promise( promiseFunction )
document.promises.push( promise );
return promise;
}
async get( controller, method, object, eventName, data ) {
var messageID = ++this.messageID;
var promiseFunction = this.promiseManager.createPromiseFunction( messageID, object );
var message = this.createMessage( messageID, controller, method, eventName, object, data );
this.logSendMessage( message, object );
console.log("send raw message", JSON.stringify( message ));
if( document.requestsObject ) {
document.requestsObject.addRequest(controller, method, object, eventName, message);
} else {
document.requests.push({ controller, method, object, eventName, message });
}
this.socket.send( JSON.stringify( message ) );
var promise = this.createPromise( promiseFunction );
await promise;
return this.processMessage( method, messageID );
}
async getRaw( message ) {
var messageID = ++this.messageID;
var promiseFunction = this.promiseManager.createPromiseFunction( messageID );
console.log( "" );
console.log("messageID", messageID)
console.log( "%c send message: ", "background: #11db33;", message );
console.log( "" );
message.id = messageID;
this.socket.send( JSON.stringify( message ) );
var promise = this.createPromise( promiseFunction );
await promise;
console.log("promise fulfilled");
var data = this.promiseManager.getMessageByID( messageID );
return JSON.stringify( data, null, 4 );
}
processMessage( method, messageID ) {
var data = this.promiseManager.getMessageByID( messageID ).data;
switch( method ) {
case "count":
if( !tools.getFirstChild( data ) ) {
return 0;
}
return tools.getFirstChild( data ).count;
break;
default:
if( Object.prototype.toString.call( data ) === '[object Array]' ) {
return data;
}
if( typeof data == "object" ) {
return tools.getFirstChild( data );
} else {
return data;
}
}
}
logInjection( message ) {
var path = message.applicationPath.join("/");
console.log( "socketMessage", message.id );
console.log( "" );
console.log( "%c send message: ", "background: #eb2666;", path, message );
console.log( "" );
}
handleInjection( messageID, data ) {
var data = this.promiseManager.getMessageByID( messageID ).data;
switch( method ) {
case "count":
return tools.getFirstChild( data ).count;
break;
default:
return tools.getFirstChild( data );
}
}
async inject( message ) {
var promiseFunction = this.promiseManager.createPromiseFunction( message.id );
var messageID = message.id;
var method = message.method;
this.logInjection( message );
this.socket.send( JSON.stringify( message ) );
await new Promise( promiseFunction );
return this.handleInjection( messageID, data );
}
logSendMessage( message, object ) {
var path = "";
if( message.applicationPath ) {
path = message.applicationPath.join("/");
}
if( ( object.getClassName && object.debug ) || document.debugALL ) {
console.log( "" );
console.log( "%c send message: ", "background: #11db33;", path, message );
//console.log( object.getClassName() );
//console.log( path );
//console.log( message );
console.log( "" );
}
}
async update( eventName, object ) {
var result = await this.get( "column", "update", object, eventName );
}
}

View File

@@ -0,0 +1,154 @@
class stateEvent{
object;
method;
args;
}
class state{
events = new Array();
registerEvent( object, method, args ) {
var event = new stateEvent();
event.object = object;
event.method = method;
event.args = args;
this.events.push( event );
}
async triggerEvents() {
var events = this.events;
for ( var i = 0; i < events.length; i++ ) {
var event = events[ i ];
var object = event.object;
var method = event.method;
var args = event.args;
object["__" + method]( args[0], args[1], args[2], args[3], args[4] );
//object[ method ]()
}
}
}
export default class stateMachine{
states = new Array();
currentState;
stateID = 0;
constructor() {
var state = this.createState();
//history.pushState( { id: state.id }, "Unify" );
}
createState() {
var newState = new state();
newState.id = this.stateID++;
this.states.push( newState );
this.currentState = newState;
return newState;
}
registerEvent( object, method, args ) {
var state = this.currentState;
state.registerEvent( object, method, args )
//console.log( "event registered in stateMachine", this );
}
async composeState( ...args ) {
this.createState();
var state = this.currentState;
if( args.length == 0 ) {
history.pushState( { id: state.id }, "Unify" );
} else if( args.length == 1 ) {
var title = args.pop().replaceAll( " ", "_" );
//if( !title ) {
history.pushState( { id: state.id }, "localhost", title + "/" );
//} else {
// history.pushState( { id: state.id }, "Unify", "/" + title + ".html" );
//}
} else {
var title = args.pop();
title = title.toString().replaceAll( " ", "_" )
if(title == "") {
title = "page"
}
history.pushState( { id: state.id }, "Unify", "/" + args.join("/") + "/" + title + ".html" );
}
}
generateUrl( ...args ) {
var title = args.pop().replaceAll( " ", "_" );
return "https://unifyjs.org" + "/" + args.join("/") + "/" + title + ".html";
}
getState( id ) {
return this.states[ id ];
}
}

427
framework/client/table.js Normal file
View File

@@ -0,0 +1,427 @@
/*
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 tools from "../unify/tools.js";
export default class table{
__className = "table";
type = "table";
id = 0;
collection = false;
collections = new Array();
load = true;
synced = false;
useCustomElement = false;
useCache = false;
createOnSync = true;
deleteProperty( child ) {
if( child.rowID ) {
delete this[ child.propertyName ];
}
}
cleanChildren( object ) {
if( object.getChildren ) {
var children = object.getChildren();
for (var i = 0; i < children.length; i++) {
var child = children[i];
if( child.rows ) {
child.rows = new Array();
}
this.deleteProperty( child );
this.cleanChildren( child );
}
}
}
destroyEventListener( object ) {
if( object.render ) {
// this could be enabled to destory the render functions still running.
// But this causes problems when loading a new page, and then
// loading the old one again, The render method is not called.
if( object.autoDestroyRenderLoop ) {
window.cancelAnimationFrame( object.requestAnimationFrameID );
}
}
if( object.destroy ) {
object.destroy();
}
}
destroyEventListeners( element ) {
if( element.object ) {
var object = element.object;
this.destroyEventListener( object );
}
var children = element.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children[i];
this.destroyEventListeners(child);
}
}
logSync() {
if( this.debug | document.debugALL ) {
console.log( "" );
console.log("%ctable::sync", "background: #5dc2d6;" );
console.log( "className: ", this.getClassName() );
console.log( "Path: ", this.applicationPathString );
console.log( this );
}
}
async loadObject( sign ) {
if( this.load ) {
//this.cleanChildren( this );
//this.destroyEventListeners( this.element );
if( !this.id ) {
await this.createObject( sign );
} else {
await this.updateObject();
}
}
}
scrollPage( show ) {
if( show ) {
this.show();
if( this.element ) {
this.element.scrollTo( 0, 0 );
}
if( this.boxElement ) {
this.boxElement.scrollTo( 0, 0 );
}
}
}
hasURL() {
var hasUrl = false
if( this.parent.type != "table" ) {
hasUrl = true;
}
if( this.parent.type == "renderCollection" ) {
hasUrl = false;
}
if( this.title && this.title.value == "" ) {
hasUrl = false;
}
if( !this.title ) {
hasUrl = false;
}
return hasUrl;
}
composePath() {
var urlPath = new Array();
urlPath.push( this.propertyName );
if( this.id ) {
urlPath.push( this.id );
}
if( this.title ) {
if( this.title.value == "" ) {
urlPath.push( this.propertyName.replaceAll(" ", "_") + ".html" );
} else {
urlPath.push( this.title.value.replaceAll(" ", "_") + ".html" );
}
} else {
urlPath.push( this.propertyName.replaceAll(" ", "_") + ".html" );
}
return urlPath.join("/");
}
async createUrl( pass ) {
var hasURL = this.hasURL();
if( hasURL || pass ) {
var path = this.composePath();
var state = new Object();
state.id = this.id;
state.applicationPath = this.applicationPath;
state.table = this;
document.states.push( state );
var url = window.location;
await history.pushState( { id: document.states.length-1 }, "Unify", "/" + path );
}
}
async sync( sign = false, show = true, createUrl = true ) {
var sign = true;
this.setApplicationPath();
this.logSync();
await this.loadObject( sign );
if( createUrl ) {
//this.createUrl();
}
this.scrollPage( show );
this.getCore().communicateVisibleElements();
return true;
}
async createObject( sign ) {
if( sign ) {
var table = await this.socketManager.get( "table", "create", this, "sign" );
} else {
var table = await this.socketManager.get( "table", "create", this );
}
this.setID( table.id );
this.updatePermissions( table.permissions );
return true;
}
async getObject() {
if( this.useCache ) {
var object = document.cacheManager.getLocalObject( this, this.id, tools.getTableName( this ) );
} else {
var object = false;
}
if( !object ) {
var object = await this.socketManager.get( "table", "get", this );
//document.cacheManager.addObject( object, this.id, tools.getTableName( this ) );
}
return object;
}
updateChildrenPermissionsClient( object ) {
if( object.permissions && object.updatePermissions ) {
object.updatePermissions( object.permissions );
}
if( object.getChildren ) {
var children = object.getChildren();
for (var i = 0; i < children.length; i++) {
var child = children[i]
console.log( "updateChildrenPermissions", child.propertyName);
this.updateChildrenPermissionsClient( child );
}
}
}
async prepareObject( object ) {
this.setID( object.id );
this.serialize( object );
console.log("after serialize", this);
//this.updatePermissions( object.permissions );
this.updateChildrenPermissionsClient( this );
await this.setupChildren();
if( this.create && this.createOnSync ) {
await this.create();
}
}
async updateObject() {
var object = await this.getObject();
await this.prepareObject( object );
this.getCore().appendAllToSelector();
return true;
}
async setupChildren() {
var children = this.getChildren();
for( var c = 0; c < children.length; c++ ) {
var child = children[c];
if( child.setup ) {
await child.setup();
}
}
}
}

View File

@@ -0,0 +1,217 @@
/*
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 defaultObject from '../unify/defaultObject.js';
import tools from '../unify/tools.js';
import core from './core.js';
import themeImports from './imports/themeImports.js';
export default class themeLoader{
defaultObject = new defaultObject();
prepareThemeCore( themeCore, socketManager, os, device, tint ) {
themeCore.addDOMToSelector = false;
themeCore.parseEvents = false;
themeCore.executeMethods = false;
themeCore.initializeRenderLoop = false;
themeCore.socketManager = socketManager;
themeCore.os = os;
themeCore.device = device;
themeCore.tint = tint;
if( os == this.os && device == this.device && tint == this.tint ) {
themeCore.createStyleSheet = false;
}
}
async loadCustomThemes( os, device, tint ) {
var customThemes = new Array();
var applications = this.applicationManager.applications;
for( var applicationID = 0; applicationID < applications.length; applicationID++ ) {
var applicationFile = applications[ applicationID ];
//console.log(applicationFile.path, applicationID, os, device, tint);
customThemes[ applicationID ] = await this.loadCustomTheme( applicationFile.path, applicationID, os, device, tint );
}
return customThemes;
}
async createObject( applicationPath ) {
if( document.mode == "production" ) {
var importObject = themeImports[ applicationPath ];
return new importObject();
} else {
var importObject = await import( "/" + applicationPath );
return new importObject.default();
}
}
createApplicationPath( path, os, device, tint ) {
device = tools.CamelCase( device );
os = tools.CamelCase( os );
tint = tools.CamelCase( tint );
var applicationPath = 'framework/cache/platforms/' + os + '/' + device + '/' + tint + '/' + path + '/application.js';
return applicationPath;
}
async loadCustomTheme( path, applicationID, os, device, tint ) {
//console.log(path, applicationID, os, device, tint);
var applicationPath = this.createApplicationPath( path, os, device, tint );
//console.log( "load custom theme from url", applicationPath );
return await this.createObject( applicationPath );
}
setThemeObjects( themeCore, os, device, tint ) {
var applicationManager = this.applicationManager;
if( !applicationManager.themeObjects ) {
applicationManager.themeObjects = new Array();
}
if( !applicationManager.themeObjects[os] ) {
applicationManager.themeObjects[os] = new Array();
}
if( !applicationManager.themeObjects[os][device] ) {
applicationManager.themeObjects[os][device] = new Array();
}
applicationManager.themeObjects[os][device][tint] = themeCore.classObjects;
}
async setupApplication( unifyCore, themeCore, application ) {
this.defaultObject.agregateDefaultObject( application );
this.applicationManager.getDomElement( application )
themeCore.setTheme();
application.core = themeCore;
await unifyCore.prepareObjects( application );
themeCore.parse( application, true );
themeCore.callAfterLoad( application );
}
async parseTheme( unifyCore, os, device, tint ) {
var themeApplications = await this.loadCustomThemes( os, device, tint );
var themeCore = new core();
var application = themeApplications[0];
this.prepareThemeCore( themeCore, unifyCore.socketManager, os, device, tint );
await this.setupApplication( unifyCore, themeCore, application );
console.log("setThemeObjects", themeCore, os, device, tint);
this.setThemeObjects( themeCore, os, device, tint )
}
async loadThemes( application, applicationID, core ) {
if( application.loadThemes && applicationID == 0 ) {
var osList = new Array("Windows", "Macos", "Android");
var deviceList = new Array("Pc");
var tintList = new Array("Light", "Dark");
for ( var i = 0; i < osList.length; i++ ) {
var os = osList[i];
for ( var j = 0; j < deviceList.length; j++ ) {
var device = deviceList[j];
for ( var k = 0; k < tintList.length; k++ ) {
var tint = tintList[k];
await this.parseTheme( core, os, device, tint );
}
}
}
}
}
}

View File

@@ -0,0 +1,389 @@
/*
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 omitMethods from "../unify/omitMethodNames.js";
import tools from '../unify/tools.js';
import definitions from '../unify/definitions.js';
export default class themeSwitcher{
setCore( core ) {
this.core = core;
}
communicateTheme( os, device, tint ) {
var themeProfile = new Object();
themeProfile.os = os;
themeProfile.device = device;
themeProfile.tint = tint;
this.core.socketManager.get( "settings", "setTheme", JSON.stringify( themeProfile ) );
}
parseObject( object ) {
if( !object.parent ) {
if( object.device ) {
object.__os = object.os;
object.__tint = object.tint;
object.__device = object.device;
this.createSetters( object );
}
}
}
updateClassName( oldValue, newValue ) {
var elements = document.querySelectorAll( "." + oldValue )
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
//var display = element.style.display;
//element.setAttribute('style', '');
//element.style.display = display;
element.classList.remove( oldValue );
element.classList.add( newValue );
}
}
delayUpdateThemeProperties() {
var that = this;
setTimeout(function() {
that.updateThemeProperties();
}, 1000 );
}
updateCoreOS( newValue ) {
var core = this.core;
core.os = newValue;
core.setTheme();
core.os = newValue;
}
osSetter( newValue, object ) {
var core = this.core;
var oldValue = object.__os;
object.__os = newValue;
this.updateCoreOS( newValue );
this.updateClassName( oldValue, newValue )
core.callAfterLoad( object.getRoot() );
this.delayUpdateThemeProperties( themeSwitcher );
core.communicateTheme( object.__os, object.__device, object.__tint );
console.log( "this is the setter of os, changed value from", oldValue, "to", newValue );
}
createOSSetter( object ) {
var themeSwitcher = this;
object.__defineSetter__( "os", function( value ) { themeSwitcher.osSetter( value, object ); });
}
createOSGetter( object ) {
object.__defineGetter__( "os", function( value ){
return object.__os;
});
}
updateCoreTint( newValue ) {
var core = this.core;
core.tint = newValue;
core.setTheme();
core.tint = newValue;
}
tintSetter( newValue, object ){
var core = this.core;
var oldValue = object.__tint;
object.__tint = newValue;
this.updateCoreTint( newValue );
this.updateClassName( oldValue, newValue );
document.config.tint = newValue;
this.delayUpdateThemeProperties();
core.communicateTheme( object.__os, object.__device, object.__tint );
}
createTintSetter( object ) {
var themeSwitcher = this;
object.__defineSetter__( "tint", function( value ){ themeSwitcher.tintSetter( value, object ); } );
}
createTintGetter( object ) {
object.__defineGetter__( "tint", function( value ){
return object.__tint;
});
}
createSetters( object ) {
this.createOSSetter( object );
this.createOSGetter( object );
this.createTintSetter( object );
this.createTintGetter( object );
}
updateMethodA( object, themeObject ) {
var properties = Object.getOwnPropertyNames( object )
for (var j = 0; j < properties.length; j++) {
var methodName = properties[j]
if( !omitMethods.includes( methodName ) ){
if( themeObject[ methodName ] && typeof themeObject[ methodName ] == "function" ) {
// todo this destroys the all events
//object[ methodName ] = themeObject[methodName];
}
}
}
}
updateMethodB( object, themeObject ) {
Object.getOwnPropertyNames( Object.getPrototypeOf( object ) ).forEach( methodName => {
if( !omitMethods.includes(methodName) ){
if( themeObject[methodName] && typeof themeObject[methodName] == "function" ) {
// todo this destroys the all events
//object[methodName] = themeObject[methodName];
}
}
});
}
updateMethods( object, themeObject ) {
this.updateMethodA( object, themeObject );
this.updateMethodB( object, themeObject );
}
updateRenderCollection( object, themeObject ) {
if( object.type == "renderCollection" ) {
if( object.object ) {
object.object = themeObject.object;
}
}
}
updateProperty( object, themeObject, name ) {
var objectString = object["__" + name ];
var themeString = themeObject[ name ];
if( themeString != objectString ) {
var css = this.core.css;
var cssPropertyName = css.normalizePropertyName( name );
var normalizedProperty = css.normalizeProperty( cssPropertyName );
var isCSS = css.propertyIsStyle( normalizedProperty );
if( !isCSS && !definitions.invalid.includes( name ) ) {
object[name] = themeObject[name];
}
//object[name] = themeObject[name];
}
}
updateCustomProperties( object, themeObject ) {
var properties = themeObject.getProperties();
for (var j = 0; j < properties.length; j++) {
var name = properties[j].name;
var value = properties[j].value;
if( typeof value == "string" ) {
if( !definitions.invalid.includes( name ) ) {
this.updateProperty( object, themeObject, name );
}
}
}
}
getThemeObject( themeObjects, className ) {
var themeByClass = themeObjects[ className ];
themeByClass = themeByClass.filter( n => n );
var themeObject = themeByClass[ 0 ];
return themeObject;
}
updateObject( object, className, themeObjects ) {
var themeObject = this.getThemeObject( themeObjects, className );
if( themeObject ){
this.updateMethods( object, themeObject );
}
this.updateRenderCollection( object, themeObject );
if( themeObject ) {
this.updateCustomProperties( object, themeObject );
}
}
updateThemeProperties() {
var themeObjects = document.themeObjects[ this.core.os ][ this.core.device ][ this.core.tint ];
console.log("themeObjects", themeObjects);
for ( var i = 0; i < this.core.objects.length; i++ ) {
var object = this.core.objects[i];
var className = object.getClassName();
if( themeObjects[ className ] ) {
this.updateObject( object, className, themeObjects );
}
}
}
}

54
framework/client/timer.js Normal file
View File

@@ -0,0 +1,54 @@
/*
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
*/
export default class timer{
timings = new Array();
initialising = true;
lap( name ) {
var timing = new Object();
timing.time = new Date().getTime();
timing.name = name;
if( this.timings.length > 0 ) {
var previouseTiming = this.timings[this.timings.length - 1].time;
var timeBetweenPrev = ( timing.time - previouseTiming ) / 1000 ;
var firstTiming = this.timings[0].time;
var timeSinceFirst = ( timing.time - firstTiming ) / 1000 ;
//console.log("TimeBetween", timeBetweenPrev);
console.log("Time: ", timeSinceFirst, name);
}
this.timings.push( timing );
//console.log("TimeBetween", this.timings);
}
}

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -0,0 +1,61 @@
//import applications from '../configs/applications.js';
import core from './core.js';
//import applicationImports from './imports.js';
console.log("spawned webworker");
console.log(core);
postMessage("webworker");
/*
class main{
applicationInstances = new Array();
async createApplicationInstances() {
for( var applicationID = 0; applicationID < applications.length; applicationID++ ) {
var applicationFile = applications[ applicationID ];
this.applicationInstances[ applicationID ] = await this.getApplication( applicationFile.path, applicationID );
}
}
async getApplication( path, applicationID ) {
var currentBundle = applicationImports[ applicationID ];
if( currentBundle ) {
this.application = new currentBundle();
}
return this.application;
}
application() {
this.createApplicationInstances();
//console.log(this.applicationInstances);
postMessage("webworker");
}
}
var treadWorker = new main();
treadWorker.application();
*/