Compare commits

...

24 Commits

Author SHA1 Message Date
chris c0171aa8d8 IMPRO,FEAT: added modifyChildren 1 month ago
chris 6933a89111 IMPRO,REFA,FEAT: extended distributeSpacingEvengly 1 month ago
chris 7a40c27712 REFA,IMPRO: select elements are InputComponents as well 1 month ago
chris 6de0aca195 REFA,FIX,IMPRO: changed default behaviour of text() 1 month ago
chris 02203a5dd0 CHORE: updated package version corresponding with git 2 months ago
chris a36190bde9 CHORE: updated package-lock.json 2 months ago
chris 41d71f1523 CHORE: fix dupplication of devdependencies introduced by git 2 months ago
chris 1a51451e82 DOC,REFA,LINT: implemented first couple of lint issues 2 months ago
chris 9fb347421d CHORE,REFA: introduced linter 2 months ago
chris 362d9f870c CHORE,REFA: introduced linter 2 months ago
chris cf6438d623 CHORE: updated version reference in package.json 2 months ago
chris c0b43e38d1 CHORE: adjusted licence to include exclusion of waranty 2 months ago
chris d361a1bbee FEAT,REFA: externalized extension base class 2 months ago
chris c25f9bb93e FEAT: added noselect modifier 2 months ago
chris aa65dc1e54 FIX,IMPRO,REFA: overriding all function for border 2 months ago
chris 5dab23dc14 FEAT,FIX,IMPRO,REFA: reworked overflow behaviour 2 months ago
chris 46f12f517d FIX,REFA: handling parameter given as string or function 2 months ago
chris ab4d39d55d IMPRO,MINOR,FIX: changed replacement order of empty string characters 2 months ago
chris 0496bb0295 FIX,IMPRO,REFA: removed shape invokation on border constructor 2 months ago
chris d578a56269 MINOR,FIX: lookup for existing key in object 2 months ago
chris 61a32a7bfe MINOR,IMPRO,FIX,REFA: changed to map approach 2 months ago
chris 27cc2d930d FIX: entries is a function of a map 2 months ago
chris 73c85f4d2e FIX: wrongfully created a dependend call loop 2 months ago
chris 025573a16c FIX: default values for parameters were wrongfully provided 2 months ago
  1. 26
      LICENCE.md
  2. 2
      README.md
  3. 15
      eslint.config.mjs
  4. 2143
      package-lock.json
  5. 14
      package.json
  6. 39
      src/base/extStore.js
  7. 18
      src/builder.js
  8. 4
      src/component/ChildbearerComponent.js
  9. 17
      src/component/Component.js
  10. 97
      src/component/FlexContainerComponent.js
  11. 18
      src/component/InputComponent.js
  12. 1
      src/context/context.js
  13. 5
      src/context/scriptAndStyleContext.js
  14. 37
      src/decorators/border.js
  15. 78
      src/extensions/extension.js
  16. 2
      src/generators/generator.js
  17. 4
      src/helper/general.js
  18. 6
      src/modifier/ChainableModifier.js
  19. 11
      src/modifier/Modifier.js

26
LICENCE.md

@ -1,5 +1,21 @@
Copyright (C) Christian Martin - All Rights Reserved
Unauthorized copying of this file,
via any medium is strictly prohibited
Proprietary and confidential
Written by Christian Martin, September 2024
Copyright (c) 2024-2025 Christian Martin
All rights reserved.
This software
and associated documentation files (the "Software")
are the exclusive property of Christian Martin.
You may not use, copy, modify, merge, publish,
distribute, sublicense, or sell copies of the Software,
in whole or in part,
without the express prior written permission of the copyright holder.
For inquiries regarding licensing, please contact:
christian.martin3(at)gmx.net.
THE SOFTWARE IS PROVIDED "AS IS",
WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

2
README.md

@ -45,3 +45,5 @@ you have been warned.
```sh
sh join_js_files.sh
```
https://eslint.org/docs/latest/use/getting-started

15
eslint.config.mjs

@ -0,0 +1,15 @@
import js from "@eslint/js";
import globals from "globals";
import json from "@eslint/json";
import css from "@eslint/css";
import { defineConfig } from "eslint/config";
export default defineConfig([
{ files: ["**/*.{js,mjs,cjs}"], plugins: { js }, extends: ["js/recommended"] },
{ files: ["**/*.js"], languageOptions: { sourceType: "script" } },
{ files: ["**/*.{js,mjs,cjs}"], languageOptions: { globals: globals.browser } },
{ files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] },
{ files: ["**/*.jsonc"], plugins: { json }, language: "json/jsonc", extends: ["json/recommended"] },
{ files: ["**/*.css"], plugins: { css }, language: "css/css", extends: ["css/recommended"] },
]);

2143
package-lock.json

File diff suppressed because it is too large

14
package.json

@ -1,6 +1,6 @@
{
"name": "jpc-like-websites",
"version": "1.0.0",
"version": "1.9.13.34",
"description": "Framework to build websites in a Jetpack Compose like manner, as well as an extensive use of method-chaingin.",
"main": "jpc-like-websites.js",
"exports": {
@ -17,5 +17,15 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "cm",
"license": "ISC"
"license": "SEE LICENCE.md",
"dependencies": {
"jpclw-extension": "git+https://git.labos.goip.de/chris/jpclw-extension.git"
},
"devDependencies": {
"@eslint/css": "^0.7.0",
"@eslint/js": "^9.26.0",
"@eslint/json": "^0.12.0",
"eslint": "^9.26.0",
"globals": "^16.1.0"
}
}

39
src/base/extStore.js

@ -54,27 +54,35 @@ function clearFunctionDeclarationText(func) {
}
return shrinkEmptyStrings(
func.toString()
.replaceAll('\n', ' ')
.replaceAll('\r\n', ' ')
.replaceAll('\n\r', ' ')
.replaceAll('\n', ' ')
.replaceAll('\r', ' ')
);
}
/**
* @todo when ExtStorage-feature/logic is reevaluated
* the resolvement of functions (as basically major or main target)
* needs to be overlooked improved and simplified.
*
* @param {Function} func
* @param {string} registrationName
* @returns {string}
*/
function getScriptTagInjectionText(func, registrationName) {
let funcHasName = func.name && func.name.trim() !== '';
if (func.startWith('function')) {
let funcHasName;
if (typeof func === 'function') {
funcHasName = ((func.name) && func.name.trim() !== '');
}
if (func.startsWith('function')) {
let label = ` function ${registrationName}`;
let isNameInFuncText = func.startWith(label);
if (funcHasName && isNameInFuncText) {
let isNameInFuncText = func.startsWith(label);
if (isNameInFuncText) {
return func;
} else {
return [label, '(', func.split('(', 1)[1]].join('')
return [label, '(', func.split('(').slice(1).join('(')].join('')
}
} else {
return ` const ${registrationName} = ${func}; `;
@ -522,18 +530,21 @@ class SStoreDefinition {
*/
function resolveOverwrite(key, container, overwriteBehaviour) {
let dealAsMap = container instanceof Map;
let occurances = (dealAsMap
? container.keys
let occurances = [...(
dealAsMap
? container.keys()
: Object.keys(container)
)
.filter(e => e.includes(key))
.length;
.filter(e => e.includes(key)
)].length;
switch (overwriteBehaviour) {
case OverwriteBehaviour.REPLACE:
case OverwriteBehaviour.REPLACE: {
break;
case OverwriteBehaviour.RENAME_OLD:
nameForOld = `${key}${occurances}`;
}
case OverwriteBehaviour.RENAME_OLD: {
let nameForOld = `${key}${occurances}`;
if (dealAsMap) {
container.set(nameForOld, container.get(key));
container.delete(key);
@ -542,6 +553,8 @@ function resolveOverwrite(key, container, overwriteBehaviour) {
delete container[key];
}
break;
}
case OverwriteBehaviour.RENAME:
default:
key = `${key}${occurances}`;

18
src/builder.js

@ -181,7 +181,7 @@ const builder = {
input: function (type, attr = {}, modifier = null) {
let comp = new InputComponent(
document.createElement("input"),
Object.assign({ "type": type }, attr),
Object.assign({ "type": (type || "text") }, attr),
modifier
)
.addStyleClass(`el-input`);
@ -272,7 +272,21 @@ const builder = {
* @param {Modifier} modifier
* @returns {Component}
*/
select: function (attr = {}, modifier = null) { return builder.genTag("select", attr, modifier); },
select: function (attr = {}, modifier = null) {
let comp = new InputComponent(
document.createElement("select"),
attr,
modifier
)
.addStyleClass(`el-input`);
if (this.components.previous) {
comp._parentComponent = this.components.previous;
this.components.previous = null;
}
return comp;
},
/**
*

4
src/component/ChildbearerComponent.js

@ -61,11 +61,7 @@ class ElementWrapper {
* @returns {Component} this component object
*/
text(text) {
if (this._element instanceof HTMLInputElement && this._element.type === "text") {
this._element.value = text;
} else {
this._element.innerText = text;
}
return this;
}

17
src/component/Component.js

@ -83,13 +83,20 @@ class Component extends StyleAndScriptStoringComponent {
* @returns {Component}
*/
overflow(vertical = true, horizontal = false ) {
if (vertical) {
if (vertical || horizontal) {
this._modifier.join(
new Modifier()
.removeStyleRule("flex")
.setStyleRule("overflow", "hidden auto")
);
this.subscribeOnGenerate(CommonCompelGroups.OVERFLOWING);
this._modifier._modifications["overflow-y"] = "auto";
}
if (vertical) {
this._modifier._modifications["overflow-y"] = "hidden auto";
}
if (horizontal) {
this.subscribeOnGenerate(CommonCompelGroups.OVERFLOWING);
this._modifier._modifications["overflow-x"] = "auto";
this._modifier._modifications["overflow-x"] = "hidden auto";
}
return this;
}
@ -314,7 +321,7 @@ class Component extends StyleAndScriptStoringComponent {
let parent = this._parentComponent;
this._parentComponent = null;
return parent.childContext(this)
.generate(generator, modifier, styleStore, functionStore);
.generate(generator, styleStore, functionStore);
}
return generator.generate(this, styleStore, functionStore);

97
src/component/FlexContainerComponent.js

@ -9,6 +9,15 @@ class FlexContainerComponent extends Component {
* @type {boolean}
*/
_distributeEvenglyAfterGenerate;
/**
* @type {number} the amount that should be left out of the total space before the children
* space is set.
*/
#distributionRecess;
/**
* @type {number} the additional gap that should be left for children before their space is set
*/
#distributionGapPerChild;
/**
* @type {string}
*/
@ -60,9 +69,8 @@ class FlexContainerComponent extends Component {
})
.forEach(icomp => {
icomp._modifier = new Modifier()
.setStyleRule("flex", "none")
.removeStyleRule("flex")
.join(icomp._modifier);
});
}
return super.childContext(innerComponent);
@ -70,25 +78,18 @@ class FlexContainerComponent extends Component {
/**
*
* @returns {FlexContainerComponent}
*/
distibuteSpacingEvenly() {
this._distributeEvenglyAfterGenerate = true;
return this;
}
/**
* @override
* @inheritdoc
* @extends Component.generate()
* @param {number} [recessFraction=0.0] recessFraction a fraction/percentage of the recess
* that should be left out before distributing the remaining space.
* @param {number} [gapPerChild=1] gapPerChild the gap per child, therefore inbetween children
* that shouldn't be distributed to the children
*/
generate(generator = singlepage, styleStore = null, functionStore = null) {
_distributingSpacing(recessFraction = 0.0, gapPerChild = 1) {
if (this._children && this._children.length > 1) {
if (this._distributeEvenglyAfterGenerate) {
let distributableSpace = 100 - 100 * recessFraction - (this._children.length - 1) * gapPerChild;
let childDistributionFraction = Math.floor(
((100 - this._children.length) / this._children.length) * 100
(distributableSpace / this._children.length) * 100
) / 100;
let direction = (this._flexDirection === 'column' ? 'height' : "width");
@ -105,6 +106,68 @@ class FlexContainerComponent extends Component {
}
}
/**
* Distributes the spacing of the childrens evengly,
* according to the flexdirection of this component.
* By default this will be executed imediately when called.
*
* @param {boolean} [rightNow=true] if set to false it will set properties accordingly
* so that the distribution will be executed on generate
* @param {number} [recessFraction=0.0] recessFraction a fraction/percentage of the recess
* that should be left out before distributing the remaining space.
* @param {number} [gapPerChild=1] gapPerChild the gap per child, therefore inbetween children
* that shouldn't be distributed to the children
* @returns {FlexContainerComponent}
*/
distibuteSpacingEvenly(rightNow = true, recessFraction = 0.0, gapPerChild = 1) {
if (rightNow) {
this._distributingSpacing(recessFraction, gapPerChild);
} else {
this.#distributionRecess = recessFraction;
this.#distributionGapPerChild = gapPerChild;
this._distributeEvenglyAfterGenerate = true;
}
return this;
}
/**
* Adds, sets, updates or overwrites the Modification of/for the children of this component.
* Just calls .modifier(modifier) on each child.
*
* @param {Modifier} modifier
* @param {boolean|ExtStorage|ExtStoreType|OverwriteBehaviour} [extStore=null]
* @returns {FlexContainerComponent} this component object
*/
modifyChildren(modifier, underTheName = "", extStore = false) {
if (underTheName === "") {
underTheName = `.${this._compName}-style-children`;
}
if (!extStore) {
for (const child of this._children) {
child.modifier(modifier)
}
} else {
this.addStyleClass(underTheName);
this._styles.push(
new SStoreDefinition(
underTheName,
modifier.ensureModifier()
)
);
}
return this;
}
/**
* @override
* @inheritdoc
* @extends Component.generate()
*/
generate(generator = singlepage, styleStore = null, functionStore = null) {
if (this._distributeEvenglyAfterGenerate) {
this._distributingSpacing(this.#distributionRecess, this.#distributionGapPerChild);
}
return super.generate(generator, styleStore, functionStore);
}
}

18
src/component/InputComponent.js

@ -18,6 +18,24 @@ class InputComponent extends Component {
}
}
/**
* This overrides the text() method in such a way,
* that it sets the value attribute for input elements instead.
*
* @override
* @inheritdoc
* @param {string} text
* @returns {InputComponent}
*/
text(text){
if (this._element instanceof HTMLInputElement) {
this._element.value = text;
} else {
super.text(text);
}
return this;
}
/**
* The parameter makes it optional to trigger the state by a variable
* @param {boolean} readonly

1
src/context/context.js

@ -192,4 +192,5 @@ const CommonCompelGroups = Object.freeze({
DROP_TARGET: "droptarget",
});
const Page = new PageBuilder();

5
src/context/scriptAndStyleContext.js

@ -50,8 +50,7 @@ class ScriptAndStyleContext {
].find(e => e !== '');
/* deal with name already present */
let functionNames = this.#functions.keys;
if (functionNames.includes(registrationName)) {
if (this.#functions.has(registrationName)) {
registrationName = resolveOverwrite(registrationName, this.#functions, overwriteBehaviour);
}
@ -174,7 +173,7 @@ class ScriptAndStyleContext {
if (this.#functions.size > 0) {
let funcTag = document.createElement('script');
for (const tuple of this.#functions.entries) {
for (const tuple of this.#functions.entries()) {
let regName = tuple[0];
let fsb = tuple[1];
funcTag.innerText += getScriptTagInjectionText(fsb.func, regName);

37
src/decorators/border.js

@ -77,20 +77,25 @@ const Define = Object.freeze({
* @extends Sides
*/
class Border extends Sides {
constructor(width = 0, color = Colors.black, style = LineStyles.solid, defaultUnit = SizeUnits.PIXEL, shape = Shapes.Rectangle) {
constructor(width = 0, color = Colors.black, style = LineStyles.solid, defaultUnit = SizeUnits.PIXEL) {
super('border', 0, defaultUnit);
this._fFirst = new BorderDefinition(width, color, style);
this._fSecond = new BorderDefinition(width, color, style);
this._fThird = new BorderDefinition(width, color, style);
this._fForth = new BorderDefinition(width, color, style);
this._shape = shape;
}
/**
* @override
* @param {number} index
* @param {number} value
* @returns {Border}
*/
setByIndex(index, value) {
if (value instanceof BorderDefinition) {
this.getByIndex(index).join(value)
this.getByIndex(index).join(value);
} else {
this.getByIndex(index)._width = value
this.getByIndex(index)._width = value;
}
return this;
}
@ -201,6 +206,30 @@ class Border extends Sides {
]
});
}
/**
* If the given amount is a number this method calls width(amount).
* If amount is instanceof BorderDefinition it will set the BorderDefinition
* to all sides.
* If neither it will do nothing and return this Border object.
*
* @inheritdoc
* @override
* @param {number|BorderDefinition} amount value to set for all directions
* @returns {typeof Sides} this
*/
all(amount) {
if(amount instanceof Number){
return this.width(amount);
}
if(amount instanceof BorderDefinition){
return super.all(amount);
}
return this;
}
}
/**

78
src/extensions/extension.js

@ -1,78 +0,0 @@
/**
* Defines an extension that can be added to the jpclw-framework
*/
class CompelExtension {
/**
* @type {string}
*/
name;
/**
* @type {string}
*/
diplayTitle;
/**
* @type {Array<SStoreDefinition>}
*/
stylings;
/**
* @type {Array<SStoreDefinition>}
*/
functions;
/**
* Predefined components. Usually of a higher (constructed) kind.
* @type {Object}
*/
components;
/**
* Extensions for/to the Page or the framework in general.
* @type {Object}
*/
frameworkControls;
/**
* Additional elements for the builder (likely referencing components)
* @type {Object}
*/
builderElements;
/**
* Additional helper functions
* @type {{*:Function}}
*/
helperFun;
/**
* functions that are supposed to be executed after install,
* to extend it that way.
* @type {Array<Function>}
*/
funAfterInstall
/**
* defines how jpc-like-websites is to be extended and executes that extension
*/
install() {
if (this.helperFun) {
helperFun.extensions = Object.assign(helperFun.extensions, this.helperFun);
}
if (this.builderElements) {
builder.extensions = Object.assign(builder.extensions, this.builderElements);
}
if (this.frameworkControls) {
Page.extensions = Object.assign(Page.extensions, this.frameworkControls);
}
if (this.stylings) {
for (const key of Object.keys(this.stylings)) {
Page.registerStyling(key, this.stylings[key]);
}
}
if (this.funAfterInstall) {
for (const fun of this.funAfterInstall) {
fun();
}
}
}
}

2
src/generators/generator.js

@ -58,7 +58,7 @@ class CompelGenerator {
*/
let curExtStore = extStore;
if (Object.hasOwn(ssd, "_extStore") && ssd._extStore) {
if (ssd.hasOwnProperty("_extStore") && ssd._extStore) {
curExtStore = ssd._extStore.setupForGeneralStyling();
}

4
src/helper/general.js

@ -69,7 +69,7 @@ const helperFun = {
*
* @param {HTMLElement} element
* @param {boolean} ensureHidden
* @returns {boolean}
* @returns {boolean} true if element is now hidden
*/
toggleElementVisibility: function (element, ensureHidden = false) {
element.classList.toggle("compel-mech-hidden");
@ -87,7 +87,7 @@ const helperFun = {
}
if (ensureHidden && !isNowHidden) {
return helperFun.toggleSelectorElementVisibility(selector)
return helperFun.toggleElementVisibility(element);
} else {
return isNowHidden;
}

6
src/modifier/ChainableModifier.js

@ -23,7 +23,7 @@ class ChainableModifier extends Modifier {
* @returns {ChainableModifier}
*/
fillMaxSize(widthFraction = 1, heightFraction = 1) {
return super.fillMaxSize(widthFraction = 1, heightFraction = 1);
return super.fillMaxSize(widthFraction, heightFraction);
}
/**
* @inheritdoc
@ -31,7 +31,7 @@ class ChainableModifier extends Modifier {
* @returns {ChainableModifier}
*/
fillMaxWidth(fraction = 1) {
return super.fillMaxWidth(fraction = 1);
return super.fillMaxWidth(fraction);
}
/**
* @inheritdoc
@ -39,7 +39,7 @@ class ChainableModifier extends Modifier {
* @returns {ChainableModifier}
*/
fillMaxHeight(fraction = 1) {
return super.fillMaxHeight(fraction = 1);
return super.fillMaxHeight(fraction);
}
/**
* @inheritdoc

11
src/modifier/Modifier.js

@ -272,6 +272,17 @@ class Modifier {
return this;
}
/**
* Sets the style rules to deactivate text-selection in the component.
* @returns {Modifier}
*/
noneSelect() {
return this
.setStyleRule("user-select", "none")
.setStyleRule("-ms-user-select", "none")
.setStyleRule("-webkit-user-select", "none")
}
/**
*
* @param {StylePropertyMap} rulemap

Loading…
Cancel
Save