commit 0c5ca09a63d80f0ba22fc4df72273474b40bc863 Author: kaj dijkstra Date: Thu Dec 25 11:16:59 2025 +0100 First commit diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..2eb100a --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +loglevel=error \ No newline at end of file diff --git a/Animations.md b/Animations.md new file mode 100644 index 0000000..51a6a52 --- /dev/null +++ b/Animations.md @@ -0,0 +1,249 @@ + +# Animations in Unify + +Unify's animation system provides a **declarative and flexible way** to apply smooth transitions, visual effects, and interactive animations to your UI components. Whether it's for simple property changes, complex transitions, or interactive user feedback, Unify makes it easy to animate your components in a clear and structured way. + +--- + +## 1. Introduction to Animations + +Animations in Unify are **object-driven**, meaning animations are attached directly to **Unify objects** such as panels, buttons, and other UI components. The animation system uses **keyframes** to define transitions over time, allowing properties like `opacity`, `transform`, `background`, etc., to change smoothly. + +Animations are executed based on **events** (e.g., `click`, `load`, `hover`) or can be triggered explicitly using the `play()` method. + +--- + +## 2. Basic Animation Example + +To define an animation, you typically use the **`createAnimation`** method, which creates a new animation instance. You can then define **keyframes** and set the properties for the element at various points during the animation. + +### Example: Color Change Animation + +Here’s an example where we animate the background color of an element from **blue** to **green**: + +```js +class ColorChangeAnimation { + + element = document.createElement("div"); + width = 100; + height = 100; + margin = 20; + + create() { + // Create the animation + this.animation = this.createAnimation("colorChange"); + + // Define keyframes + var key = this.animation.createKeyFrame(0); + key.setProperty("background", "#03a9f4"); // Initial color + + key = this.animation.createKeyFrame(100); + key.setProperty("background", "#a6e22e"); // Final color + } + + async click() { + // Play the animation over 2 seconds when clicked + await this.animation.play("2s"); + } +} +``` + +### Key Concepts: + +* **Create the animation**: The `createAnimation("colorChange")` method creates a new animation instance. +* **Define keyframes**: Keyframes define the start and end states of the animation (e.g., `background` changing from blue to green). +* **Trigger the animation**: The `play()` method starts the animation and allows you to define its duration (e.g., `2s` for 2 seconds). + +--- + +## 3. Animating Multiple Properties + +You can animate multiple properties simultaneously by setting **multiple keyframes** for different CSS properties. This allows you to create more complex animations that change several aspects of the UI at once. + +### Example: Fading and Scaling + +Here’s an example of an animation that fades an element in while simultaneously scaling it up: + +```js +class FadeAndScale { + + element = document.createElement("div"); + width = 100; + height = 100; + margin = 20; + + create() { + // Create the animation + this.animation = this.createAnimation("fadeAndScale"); + + // Fade in + var key = this.animation.createKeyFrame(0); + key.setProperty("opacity", "0"); + key.setProperty("transform", "scale(0.5)"); + + // Fade and scale up + key = this.animation.createKeyFrame(100); + key.setProperty("opacity", "1"); + key.setProperty("transform", "scale(1)"); + } + + async click() { + // Play the fade and scale animation + await this.animation.play("2s"); + } +} +``` + +In this example: + +* **Opacity** and **transform** properties are animated together. +* The element fades in from `opacity: 0` to `opacity: 1` while scaling from `scale(0.5)` to `scale(1)`. + +--- + +## 4. Triggering Animations Based on Events + +You can trigger animations in response to various user events like `click`, `hover`, or `focus`. This makes the animations interactive, responding to user actions. + +### Example: Button Click Animation + +Let’s animate a button's background color when it’s clicked: + +```js +import button from '/elements/button.js'; + +export default class AnimatedButton extends button { + + label = "Click Me"; + + async click() { + // Create a new animation + this.animation = this.createAnimation("buttonClick"); + + var key = this.animation.createKeyFrame(0); + key.setProperty("background-color", "#03a9f4"); // Initial color + + key = this.animation.createKeyFrame(100); + key.setProperty("background-color", "#f92672"); // Final color + + // Play the animation for 2 seconds + await this.animation.play("2s"); + } +} +``` + +When the user clicks the button, the `click()` method triggers the animation that changes the background color from **blue** (`#03a9f4`) to **red** (`#f92672`). + +--- + +## 5. Sequential and Chained Animations + +You can also chain animations together to create more complex effects. For instance, you can have one animation complete before the next one starts. + +### Example: Sequential Animations + +```js +class SequentialAnimations { + + element = document.createElement("div"); + width = 100; + height = 100; + margin = 20; + + create() { + // Animation 1: Fade in + this.animation1 = this.createAnimation("fadeIn"); + var key = this.animation1.createKeyFrame(0); + key.setProperty("opacity", "0"); + + key = this.animation1.createKeyFrame(100); + key.setProperty("opacity", "1"); + + // Animation 2: Scale up + this.animation2 = this.createAnimation("scaleUp"); + key = this.animation2.createKeyFrame(0); + key.setProperty("transform", "scale(0.5)"); + + key = this.animation2.createKeyFrame(100); + key.setProperty("transform", "scale(1)"); + } + + async click() { + // Play fade-in animation first + await this.animation1.play("2s"); + + // After fade-in, play scale-up animation + await this.animation2.play("2s"); + + alert("Both animations are complete!"); + } +} +``` + +### Explanation: + +* **Sequential Execution**: The `await` ensures that the animations play one after another. First, the **fade-in** animation plays, followed by the **scale-up** animation. +* **Multiple Animations**: The keyframes for each animation are created independently, and their respective properties change over time. + +--- + +## 6. Animating Transitions Between States + +Animations are often used for transitioning between different **states** of an application, such as showing or hiding a panel, or transitioning between pages. + +### Example: Sliding In a Panel + +```js +import panel from '/elements/panel.js'; + +export default class SlidePanel extends panel { + isOpen = false; + + async click() { + if (!this.isOpen) { + // Slide in animation + this.animation = this.createAnimation("slideIn"); + var key = this.animation.createKeyFrame(0); + key.setProperty("transform", "translateX(100%)"); + + key = this.animation.createKeyFrame(100); + key.setProperty("transform", "translateX(0)"); + + await this.animation.play("0.5s"); + this.isOpen = true; + } else { + // Slide out animation + this.animation = this.createAnimation("slideOut"); + var key = this.animation.createKeyFrame(0); + key.setProperty("transform", "translateX(0)"); + + key = this.animation.createKeyFrame(100); + key.setProperty("transform", "translateX(100%)"); + + await this.animation.play("0.5s"); + this.isOpen = false; + } + } +} +``` + +### Steps: + +1. **Slide In**: The panel slides in from the right (by transitioning `translateX(100%)` to `translateX(0)`). +2. **Slide Out**: When clicked again, the panel slides out of view (by transitioning `translateX(0)` to `translateX(100%)`). +3. **Interactive**: The `isOpen` flag determines whether to slide in or slide out, toggling the state. + +--- + +## 7. Conclusion + +Unify’s animation system provides a **flexible, declarative approach** to animating UI elements. Whether you're animating simple property changes or complex transitions between multiple states, you can easily add animations to your UI. + +Key features: + +* **Multiple keyframes** to animate multiple properties simultaneously. +* **Event-driven animations** triggered by user interactions (e.g., clicks, page loads). +* **Sequential and parallel animations** to create complex visual effects. +* **Smooth transitions** for UI states like opening/closing panels or transitioning between pages. + +By leveraging Unify’s animation system, you can craft engaging and interactive user experiences with minimal effort. diff --git a/Permissions.md b/Permissions.md new file mode 100644 index 0000000..ff3d79a --- /dev/null +++ b/Permissions.md @@ -0,0 +1,215 @@ + +# Permissions: Groups, Scopes, Authorization Rules + +In Unify, the **permissions system** is designed to give you full control over who can **read**, **write**, or **delete** data, while allowing you to enforce security at various levels of the application. + +Unify offers a **flexible**, **declarative** approach to managing permissions across different objects, allowing you to define **authorization rules** based on: + +* **User Groups** (e.g., admin, guest, member) +* **Scopes** (e.g., a column, a table, or an entire resource) +* **Actions** (e.g., READ, WRITE, DELETE) + +## 1. Groups: Defining User Roles + +In Unify, **Groups** represent user roles, and each group has certain **permissions** associated with it. These groups can be used to control access at various levels, such as: + +* Viewing data +* Editing data +* Deleting data + +### Example: Defining Groups + +```js +import groups from '/user/group/user.group.permission.js'; + +export default class user extends table { + + username = new username(); + email = new email(); + groups = new groups(); // Associate user with groups + +} +``` + +### Common Use Case + +For instance, you might have: + +* **Visitor**: Can only **read** public information +* **Member**: Can **read** and **write** content +* **Admin**: Can perform all actions, including **delete** + +You can easily enforce these permissions using: + +```js +permission() { + this.allow(groups.visitor, "READ"); // Visitors can read + this.allow(groups.member, "READ"); // Members can read + this.allow(groups.member, "WRITE"); // Members can write + this.allow(groups.admin, "READ"); // Admins can read + this.allow(groups.admin, "WRITE"); // Admins can write + this.allow(groups.admin, "DELETE"); // Admins can delete +} +``` + +--- + +## 2. Scopes: Fine-Grained Permission Control + +**Scopes** allow you to define permissions not just for entire tables or models, but for **specific fields** or **columns** within those models. + +For example, a user might be allowed to **read** all the data but only **edit** a certain field, such as a profile description or a specific product attribute. + +### Example: Scope-Based Permissions + +```js +permission() { + // Allow "member" group to read all users but only update email + this.allow(groups.member, "READ"); + this.allow(groups.member, "WRITE", "email"); // Allow update on email only + this.allow(groups.admin, "READ"); + this.allow(groups.admin, "WRITE"); + this.allow(groups.admin, "DELETE"); +} +``` + +In this example: + +* **Members** can **read** all data but only **update** the `email` field. +* **Admins** have full access (can **read**, **write**, and **delete** all fields). + +You can also control **views** or **actions** like **deleting** based on a particular column or resource. + +--- + +## 3. Authorization Rules: Controlling Access + +**Authorization rules** are how you declare which groups have what types of access to your tables, fields, or methods. These rules govern **what actions** a group can perform on **what objects**. + +You can define rules for specific actions such as: + +* **READ**: View data +* **WRITE**: Modify data +* **DELETE**: Remove data + +Each object can implement an associated **`permission()`** method to specify which group can perform what action on the object. + +### Example: Implementing Authorization Rules + +```js +export default class news extends table { + + title = new title(); + body = new body(); + + permission() { + this.allow(groups.visitor, "READ"); // Visitors can read the news + this.allow(groups.member, "WRITE"); // Members can write/edit news + this.allow(groups.admin, "READ"); // Admins can read + this.allow(groups.admin, "WRITE"); // Admins can write + this.allow(groups.admin, "DELETE"); // Admins can delete + } +} +``` + +--- + +## 4. Implementing Permissions in `node` Methods + +In addition to controlling UI elements like columns, you may want to enforce permissions when executing actions on the server (such as creating, updating, or deleting records). This is where **manual permission checks** come into play. + +### Example: Using Permissions in `node` Methods + +```js +node async deleteRow(client) { + const user = client.user; + + // Check if the user has permission to delete + if (!user.hasPermission("DELETE_NEWS")) { + throw new Error("Permission denied: User cannot delete"); + } + + this.delete(); // Perform the delete action +} +``` + +In this example, the `deleteRow` method checks whether the **current user** has permission to delete the record. If they do not, it throws an error and prevents the action. + +--- + +## 5. Permissions with Collections + +Since collections may contain multiple rows (or objects), you may also need to control access at the **collection level**. This allows you to define permissions that apply across the entire dataset. + +### Example: Permissions for Collection + +```js +export default class newsListTableBody extends renderCollection, gridViewBody { + + permission() { + this.allow(groups.visitor, "READ"); // Visitors can read all news in the collection + this.allow(groups.member, "WRITE"); // Members can write new news items + this.allow(groups.admin, "DELETE"); // Admins can delete news items + } +} +``` + +This ensures that each row in the collection respects the user’s permissions when they try to **view**, **create**, **update**, or **delete** entries. + +--- + +## 6. Combining Permissions with UI + +In Unify, you **don't** have to manually manage every UI element (such as showing or hiding a button) based on permissions. You can use the `permission()` method to dynamically control UI elements' visibility and accessibility by the roles assigned. + +For instance: + +```js +node async click() { + if (this.user.hasPermission("EDIT_NEWS")) { + this.showEditForm(); + } else { + throw new Error("Permission denied: Cannot edit news"); + } +} +``` + +You can pair the **permissions check** with UI changes to ensure users can only interact with elements they are authorized to use. + +--- + +## 7. Custom Authorization Logic + +You can also write custom authorization logic, such as role hierarchies (where one group has broader permissions than another). + +### Example: Custom Authorization + +```js +node async deleteRow(client) { + const user = client.user; + + // Only admin or user who created the news can delete it + if (!(user.hasPermission("DELETE_NEWS") || this.createdBy === user.id)) { + throw new Error("Permission denied: User cannot delete this news item"); + } + + this.delete(); // Proceed to delete if authorized +} +``` + +This custom rule checks whether the **current user** is an **admin** or the **creator** of the news item before allowing them to delete it. + +--- + +## Summary of Permissions System + +| Element | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| **Groups** | Roles that define the access level of a user (e.g., Admin, Member, Visitor) | +| **Scopes** | Granular permissions tied to specific fields, columns, or actions within a model | +| **Authorization Rules** | Methods (`permission()`) where groups are assigned specific actions (READ, WRITE, DELETE) for objects, fields, or collections | +| **Custom Logic** | Developers can write custom authorization logic for complex rules like ownership or hierarchical access | + +Unify's permission system is flexible, allowing developers to define, check, and enforce rules throughout the application — from **UI visibility** to **backend operations** like SQL queries and method executions. + + diff --git a/Property_Binding.md b/Property_Binding.md new file mode 100644 index 0000000..57a0012 --- /dev/null +++ b/Property_Binding.md @@ -0,0 +1,64 @@ + + +### Automatic Rendering and Property Binding in Unify + +In Unify, you **define properties** on your objects, and the framework automatically **creates the associated DOM elements**, applies **styles**, and **binds the properties** without you needing to manually manipulate the DOM. This approach significantly reduces boilerplate code, making it easier and faster to build dynamic user interfaces. + +#### Key Concepts: + +1. **Automatic Element Creation**: + When you define a Unify object, like a `panel`, the framework automatically generates the corresponding HTML element for you. You don't need to manually call `document.createElement()` or manage the element's attributes. + +2. **Property Binding**: + The properties you define (such as `height`, `width`, or `text`) are automatically reflected in the rendered DOM element. For instance, if you set the `height` property of a `panel` object, Unify ensures that the corresponding HTML element's height is updated accordingly. + +3. **No Need for Render Methods**: + Unlike traditional frameworks where you need to explicitly define a `render()` method to apply changes to the DOM, Unify handles this for you. Simply updating the properties of a Unify object triggers the necessary updates in the DOM without needing extra code. + +4. **Dynamic Updates**: + Whenever a property is changed, such as adjusting the `height` or `text` of an element, Unify automatically re-renders the element to reflect these changes. There's no need to manually call DOM manipulation methods like `element.style.height` or `element.innerText`. + +#### Example: + +Here’s an example demonstrating how Unify makes it easy to manage UI elements: + +```js +class panel { + // Define initial properties + height = 100; + width = 200; + margin = 20; + text = "Initial Text"; + + // Modify properties dynamically + click() { + this.height = 300; // Change height + this.width = 400; // Change width + this.text = "Updated Text"; // Change text content + } +} + +// Create an instance of the panel +const myPanel = new panel(); +``` + +### How It Works: + +1. **No Manual DOM Updates**: You don’t need to manually create elements or apply styles. Unify automatically creates an HTML element for your `panel` and applies the `height`, `width`, and `text` properties to it. + +2. **Automatic Synchronization**: When you modify properties like `height`, `width`, or `text`, Unify ensures that the corresponding DOM element is updated to reflect these changes without requiring additional code. + +3. **Simplified UI Development**: This approach makes it easier to build dynamic, interactive UIs. You simply update the object’s properties, and Unify handles the underlying DOM updates. + +4. **Declarative Approach**: By defining properties on objects, you declaratively specify the state of your UI, and Unify takes care of the rendering and synchronization for you. + +### Benefits: + +* **Less Boilerplate Code**: Since Unify automatically binds properties to DOM elements, there's no need for repetitive code to manually update styles or text. +* **Faster Development**: By removing the need for manual DOM manipulation, you can focus on defining the state and behavior of your components. +* **Automatic Synchronization**: Changes to object properties are automatically reflected in the UI without any extra code to update the DOM. + +--- + +This approach streamlines the process of building dynamic UIs and ensures that your objects and the DOM are always in sync, reducing the likelihood of errors and improving maintainability. With Unify, you focus on defining the state of your UI, and the framework takes care of the rendering for you. + diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..bc387ca --- /dev/null +++ b/Readme.md @@ -0,0 +1,214 @@ + + +# Unify Developer Manual + +### Build full applications with a single, unified codebase. + +Unify is a full-stack application framework designed to remove the accidental complexity of modern web development. Instead of hand-wiring HTTP requests, state management, SQL queries, UI updates, permissions, and caching — Unify turns each **domain object** into a **live application object** that exists simultaneously on the server and client. + +You write your application *once*. +Unify takes care of syncing it everywhere it needs to be. + +--- + +## Why Unify? + +Most web apps are assembled from disconnected technologies: +React + REST + ORM + SQL + State Manager + WebSockets + UI Framework + Access Control… + +Each layer requires boilerplate to keep everything in sync: + +* serialize → send → parse → update → re-render → validate permissions +* write SQL + write endpoints + write frontend state logic for the same entity + +Unify eliminates these seams. + +> **One class = data + logic + UI + permissions + real-time behavior** + +The framework: + +* turns your class into a database table (server) +* generates UI components from that class (client) +* syncs all changes via a structured WebSocket protocol +* applies permissions automatically based on user role +* integrates filtering, joins, pagination at the SQL level +* caches and updates only changed fields + +You focus on the domain model. +Unify handles the rest. + +--- + + +### Why Unify Is AI-Optimized + +Unify applications are self-describing graphs. +The object structure defines: + +UI layout + +Backend relationships + +Permissions + +Sync rules + +Navigation + +A human developer may lose track of where objects live in the graph. + +But AI can: + +infer full graph topology + +find optimal traversal paths + +safely modify relationships + +rewrite UI interactions without breaking structure + +This means Unify enables: + +AI-generated UI actions + +AI-guided refactoring + +AI-assisted CRUD creation + +Automated join discovery + +Intelligent navigation handling + + + +## What does development feel like? + +Example: define a `News` class + +```javascript +export default class news extends table { + title = new text("Title"); + body = new text("Message"); + price = new number("Price"); + + permission() { + this.allow(groups.visitor, "READ"); + this.allow(groups.admin, "WRITE"); + } +} +``` + +And a list view: + +```javascript +export default class newsListTable extends gridView { + header = new newsListTableHeader(); + body = new newsListTableBody(newsListItem, new collection(news)); +} +``` + +You don’t manually: + +* write SQL queries +* define REST endpoints +* build WebSocket handlers +* implement CRUD actions +* code client state syncing +* generate UI markup + +Unify does all of that from your object graph. + +--- + +## Architecture: What’s inside + +| Layer | Responsibility | +| ---------------------- | ------------------------------------------ | +| **Domain Objects** | Single class shared by server + client | +| **Render Collections** | Auto-loaded lists with pagination + search | +| **Table Controller** | Database operations + joins | +| **Socket Controller** | Real-time communication layer | +| **UI Runtime** | Live elements, animations, events | +| **Permission Engine** | Automatic security per object/action | + +This creates a **Behavioral ORM**: + +* objects contain their own server logic +* queries are automatically composed from UI actions +* users see only what they are permitted to interact with + +--- + +## Why does this matter? + +Modern software complexity isn’t caused by features — it’s caused by **glue code**. +For every feature, you implement it 3–6 times: backend models, database schema, API routes, frontend state, UI bindings… + +Unify collapses those layers into **one source of truth**. + +The result: + +* drastically fewer bugs +* ultra-fast iteration cycles +* real-time UX without extra work +* secure-by-construction access rules +* smaller teams can ship full apps + +--- + +## Current focus + +The goal of this release is to give developers a working demonstration of: + +* full-stack sync with no REST boilerplate +* real-time UI updates +* built-in permissions +* SQL searching / joining from the UI +* cross-platform dynamic UI rendering (Windows / Mac / Web) + +The included **News Application** shows: + +* search/filter with SQL operators (`LIKE`, `OR`, `>=`) +* item detail transitions + CRUD dialogs +* login + role-based access +* pagination +* dynamic view/layout behavior + +--- + +## Who is Unify for? + +✔ Full-stack developers +✔ Product developers who hate glue code +✔ Teams who want to ship faster +✔ Anyone who believes software should be simpler + +--- + +## Status + +Unify is actively developed and evolving. +Contributions, feedback, and architectural discussion are welcome. + +> Help define the future of unified application development. + +--- + +## Get started + +The source includes: + +* `unify_source/` – the core framework +* `unify_application/` – working reference application + +Clone and run the app to see the architecture in motion: + +``` +git clone https://.../unify +cd unify_application +npm install +npm start +``` + +Documentation and complete API references are coming. + diff --git a/Rendering.md b/Rendering.md new file mode 100644 index 0000000..645d40b --- /dev/null +++ b/Rendering.md @@ -0,0 +1,212 @@ + + +# Rendering Data: Render Collections, Lists & Pagination + +In Unify, data-driven interfaces, such as tables, lists, or collections, are rendered through a powerful concept: **Render Collections**. + +A **Render Collection** is a UI component that displays rows of data, with a complete lifecycle from querying the backend to rendering the results, all while maintaining a declarative, JavaScript-centric approach. + +## 1. Define a Render Collection + +A render collection consists of two key components: + +* **The Row Renderer**: A component that defines how each row is visually rendered. +* **The Collection**: A component that defines the data source and binds to a backend Table (like `news`, `users`, etc.). + +### Example: Defining a Render Collection + +```js +export default class newsListTable extends gridView { + + header = new newsListTableHeader(); + + body = new newsListTableBody( + newsListItem, // Row Renderer + new collection(news) // Backend Data Binding + ); +} +``` + +In this example: + +* **`newsListItem`** is the row component used to render individual items. +* **`new collection(news)`** binds to the `news` Table on the backend, providing the data to be displayed. + +### How it works: + +* The **Collection** defines the data. +* The **Row Renderer** defines how to display each individual row. + +--- + +## 2. Syncing Data — Client-Server Integration + +Unify makes sure the **data remains synced** across the client and the backend. You can fetch data on-demand and refresh it easily with the `.sync()` method: + +```js +await this.body.sync(); +``` + +When the data is synced, the following happens: + +1. The query is sent to the server (via `node async filterSearch()`). +2. The server executes the query and returns the rows. +3. The rows are parsed and displayed in the UI via the **Row Renderer**. + +If the collection is already **pre-bound** to a table with an `id`, calling `.sync()` will also refresh that specific object’s details. + +--- + +## 3. Pagination — Developer Controlled + +Pagination in Unify is **developer-controlled**. Unlike typical frameworks that handle pagination automatically, you have full control over how the **limit**, **offset**, and **searching** are applied. + +### Pagination Example: + +```js +async update(updatePagination = true) { + if (updatePagination) { + this.page = 0; + } + + // Filtering and pagination logic + this.numberOfPages = await this.filterSearch( + this.searchType, + this.searchTerm, + this.sort, + this.direction, + this.limit, + this.page + ); + + await this.sync(); + + if (updatePagination) { + this.parents("newsItemPage").tableControl.pagination.create(); + } +} +``` + +In this case: + +1. **`filterSearch()`** constructs the filter for the query and is called to fetch the rows. +2. After filtering, **pagination** is managed manually. +3. **`sync()`** then updates the UI with the results. + +This gives you control over **pagination logic** and how the list is managed. + +--- + +## 4. Filtering and Searching — Declarative Querying + +In Unify, **filtering and searching** are handled using **logical expressions** that are parsed on the server side. You construct the queries using Unify's SQL helpers: + +```js +import OR from '/unify/sql/OR.js'; +import LIKE from '/unify/sql/LIKE.js'; +import GREATER from '/unify/sql/GREATER_OR_EQUAL.js'; +import SMALLER from '/unify/sql/SMALLER_OR_EQUAL.js'; + +node async filterSearch(searchType, searchTerm, order, direction, limit, page) { + const filter = this.getFilter(); + + switch (searchType) { + case 0: + filter.search = OR( + OR(LIKE(filter.title, searchTerm), LIKE(filter.comments.body, searchTerm)), + LIKE(filter.body, searchTerm) + ); + break; + case 1: + filter.search = GREATER(filter.price, searchTerm); + break; + case 2: + filter.search = SMALLER(filter.price, searchTerm); + break; + } + + if (!searchTerm) filter.search = false; + + filter.order = filter[order]; + filter.direction = direction === "desc" ? "desc" : "asc"; + + filter.limit = parseInt(limit); + filter.from = parseInt(page * limit); + + await this.get(); // Fetch results + + const numberOfPages = Math.ceil(this.rows.length / limit); + return numberOfPages; +} +``` + +### Key Points: + +* **Logical operators** like `OR`, `AND`, and `LIKE` are used to build declarative filters. +* Filters are executed directly **on the server**. The objects are **parsed as-is**, without the need for string-based queries or manual SQL building. +* **Pagination and sorting** logic is fully under the developer’s control. + +The **query-building** helpers (`LIKE`, `GREATER`, `SMALLER`) are parsed directly by the server. They allow you to declaratively specify complex queries in JavaScript, all while Unify handles the logic and results. + +--- + +## 5. Permissions — Controlling Access to Data + +Just like Unify Table objects, **Render Collections** have a permission system that controls who can **read**, **write**, or **delete** data. For example: + +```js +permission() { + this.allow(groups.visitor, "READ"); + this.allow(groups.member, "READ"); + this.allow(groups.admin, "READ"); +} +``` + +Permissions can control: + +* Which rows are visible to different user roles +* Which fields inside those rows are visible or editable + +It’s important to note that **filtering** does not automatically enforce permissions. You must explicitly **validate** access rights to each table, column, or row. + +For example, before executing an action like `deleteRow()`, you must check the user’s permissions: + +```js +node async deleteRow(client) { + const user = client.user; + + if (!user.hasPermission("DELETE_NEWS")) { + throw new Error("Permission denied"); + } + + this.delete(); +} +``` + +--- + +## 6. Lifecycle Summary + +| Action | Happens Where | Implemented by | +| --------------------------- | ------------------------ | -------------- | +| Configure UI of list | Client | Developer | +| Construct query logic | Shared (Client + Server) | Developer | +| Execute SQL on server | Server | Unify | +| Deserialize objects | Server → Client | Unify | +| Render rows in the UI | Client | Unify | +| Handle permissions for rows | Server | Developer | + +Unify abstracts away complex data handling. The **UI** remains declarative and **directly synced** with the **backend**, ensuring **zero glue code** between database and frontend. + +--- + +## Conclusion + +Unify’s **Render Collections** provide a simple, declarative way to build **dynamic, paginated, filtered lists**: + +1. The **backend logic** remains completely abstracted (no REST APIs, no ORM configuration). +2. The **client UI** renders the data based on **filter and query objects**. +3. The **permissions and security** of the data are automatically respected with clear separation between **frontend** and **backend** logic. + +The system gives you **total control** over pagination, sorting, searching, and permissions, while Unify handles the **syncing**, **UI updates**, and **backend query execution** for you. + diff --git a/Tables.md b/Tables.md new file mode 100644 index 0000000..3eb1cf4 --- /dev/null +++ b/Tables.md @@ -0,0 +1,163 @@ +Here is a fully rewritten version of the entire **Tables + Columns + Floating Mapping** section — accurate, simplified, and without over-emphasizing the “floating” term, while still explaining why it matters. + +--- + +## Tables & Columns + +### Automatic SQL Mapping from UI Components + +In Unify, **your UI defines your data model**. + +Every data entity in an application is a **table object**: + +```js +import table from '/unify/table.js'; + +export default class user extends table { + + username = new username(); // column + email = new email(); // column + groups = new groups(); // relation +} +``` + +Any child object that extends `column` is automatically treated as a **database column** belonging to its nearest table ancestor. + +There is no need to write schemas, migrations, or model config files. +Unify inspects the structure at runtime and understands: + +* Table name → class name (`user`) +* Column names → field names (`username`, `email`, …) +* Relationships → nested collections +* Permissions → defined on the table + +No duplication. No ORM setup. +Your UI code **is** your data model. + +--- + +### Columns Can Live Anywhere in the UI Tree + +Columns do not need to be direct children of the table. + +You can design your UI freely: + +```js +export default class userEditPanel extends panel { + accountPanel = new accountPanel(); + contactPanel = new contactPanel(); +} + +class accountPanel extends panel { + username = new username(); // column +} + +class contactPanel extends panel { + email = new email(); // column +} +``` + +Unify automatically discovers these fields because they appear **under a table instance** in the object tree. + +So you are free to: + +* Split a screen into panels +* Reuse complex component hierarchies +* Move UI structure without refactoring SQL code + +This enables **UI-first design** without breaking the data layer. + +--- + +### CRUD Without CRUD Code + +Unify provides two primary data operations: + +| Action | Developer code | Result | +| ------ | ------------------- | ----------------------------------- | +| Save | `await user.save()` | INSERT or UPDATE depending on `id` | +| Load | `await user.sync()` | SELECT + populate all child columns | + +Example: Editing a profile + +```js +async click() { + const form = this.parents('userEdit'); + await form.save(); // automatically writes username & email + form.hide(); +} +``` + +And for loading: + +```js +user.id = 42; +await user.sync(); // loads username/email into the UI automatically +``` + +No setters. +No binding boilerplate. +No DTOs. +No form libraries. + +The table object is both: + +* Data source +* UI container +* Binding layer + +--- + +### Why This Matters + +| Traditional Full-Stack | With Unify | +| --------------------------- | -------------------------- | +| Write database schema | Skip — inferred | +| Write backend model | Skip — inferred | +| Write API controllers | Skip — RPC auto-generation | +| Write validation logic | Built into column objects | +| Build UI → manually connect | UI *is* the data model | +| Keep everything in sync | `.sync()` + `.save()` | + +This eliminates the friction between backend + frontend and replaces it with one unified codebase. + +--- + +### Minimal Mental Model + +> A **table** object represents a database row. +> Any **column** object inside that table’s UI subtree automatically becomes a database column. +> `sync()` loads data into the UI. +> `save()` writes UI data back to SQL. + +Nothing more is needed to build and ship real applications. + +--- + +### Example Recap + +```js +user.id = 7; +await user.sync(); // load existing row → UI updates + +user.username.value = "kaj"; +await user.save(); // update DB row with new values +``` + +One line to fetch, one line to commit. + +--- + +If you'd like, the next chapter can flow directly into **Render Collections & Lists**, since they demonstrate the same philosophy at scale: + +* UI defines queries (pagination, filtering) +* Changes propagate automatically across the app + +Should I continue with: + +A) Render Collections + Filtering/Searching +B) Permissions (groups, scopes, READ/WRITE/DELETE) +C) Routing + Animated Page State +D) Server RPC Communication Model (socket commands) + +Just tell me which one comes next. diff --git a/Why.md b/Why.md new file mode 100644 index 0000000..b882a44 --- /dev/null +++ b/Why.md @@ -0,0 +1,65 @@ +### 1. **Full-Stack Integration with Minimal Effort** + +Unify offers a **high-level abstraction** over traditional full-stack frameworks, combining the backend (data models, SQL queries, server-side logic) and frontend (UI rendering, state management, animations) into a single cohesive system. It drastically reduces the need for **manual synchronization** between layers, which is typically a source of complexity in traditional architectures. + +**Value Add**: By using Unify, you're gaining expertise in building applications that **automatically sync** across client and server, without needing to write separate API routes, manage frontend state, or even handle SQL queries manually. + +### 2. **AI Optimization Potential** + +Unify's **self-describing object graph** enables AI to generate code for UI actions, refactoring, CRUD generation, and more. This opens up the potential for **AI-assisted development**, making tasks like optimizing UI behavior, managing state, and writing backend logic much faster. + +**Value Add**: You’re working with a **forward-thinking framework** that embraces AI optimization, placing you at the forefront of innovation in the full-stack development space. + +### 3. **Declarative Approach to Data and UI** + +Unify turns **data models into UI components**. You define your business logic in terms of **classes** and **objects**, and Unify handles the database queries, API calls, state management, and UI bindings. + +**Value Add**: This **declarative model** significantly reduces **boilerplate code** and streamlines the development process. You are not manually wiring complex data flows, which means you can focus more on solving the core problem rather than dealing with infrastructure and repeated patterns of implementation. + +### 4. **Real-Time Sync and Permissions Management** + +Unify automatically syncs data between the client and the server, ensuring that the state is always up-to-date across all layers of the application. It also applies **permissions automatically** based on user roles and object-level access control, ensuring **security** is built into the framework rather than added as an afterthought. + +**Value Add**: You get **real-time syncing** and **permissions enforcement** with minimal effort, which are traditionally complex features to implement. This **reduces the risk of security vulnerabilities** and improves the consistency of user data across applications. + +### 5. **Automatic Query Composition** + +Unify’s system allows **SQL queries to be generated automatically** from UI interactions and object manipulations. Filtering, pagination, and joins are built-in features, which means you don't have to write SQL manually for each interaction. You simply define what you want the data to look like, and Unify handles the query generation. + +**Value Add**: This **eliminates SQL boilerplate** and query-building code, helping you rapidly prototype applications with complex data requirements, saving you significant time on backend development. + +### 6. **Flexible and Scalable UI with Floating Columns** + +The framework allows you to **flexibly design the UI** without worrying about how it will impact the underlying database model. With the concept of **floating columns**, Unify offers **dynamic UI management**, where objects (e.g., panels, tables) can be nested freely, with no disruption to backend data structures. + +**Value Add**: This **enhances your design flexibility** and allows you to **focus on user experience** without the constraints of having to directly map UI components to your database schema. It’s a powerful feature for building **scalable, maintainable UIs**. + +### 7. **Minimal Glue Code and Increased Efficiency** + +Unify eliminates the need for traditional **"glue code"** that connects various parts of an app: backend models, database schema, API routes, and frontend state. Instead, it relies on **automated syncing**, reducing duplication and the potential for bugs. + +**Value Add**: By cutting out this **manual glue code**, you can ship **full applications faster** and with fewer opportunities for errors. Your workflow becomes more **efficient**, focusing solely on defining business logic and UI components. + +--- + +### How does it add value to your CV? + +* **Innovative Technology**: Unify is a highly **innovative framework** that addresses many of the challenges full-stack developers face, such as synchronization, permission management, and data handling. Being involved with a framework like this demonstrates your ability to work with cutting-edge technology. + +* **Problem-Solving**: Working with Unify showcases your **problem-solving skills**. You are tackling the problem of **redundant code and complexity** in a novel way, leveraging the power of abstraction to create a more elegant solution for modern web development. + +* **Future-Proofing**: By working with a framework that has the potential to integrate **AI-assisted development**, you’re positioning yourself as someone who is not just keeping up with modern trends but also preparing for **future technologies**. + +* **Reduced Development Time**: Your experience with Unify shows that you can develop and ship complex applications quickly and efficiently, as the framework automates much of the **boilerplate coding** involved in backend and frontend development. + +* **Full-Stack Expertise**: Unify allows you to work across the entire stack, from database to UI to real-time updates, making you a **well-rounded full-stack developer**. This skill is highly valuable in today’s job market. + +* **Security Awareness**: The **automatic permission system** in Unify indicates that you’re mindful of security concerns and can develop applications with **built-in access control**. + +--- + +### Conclusion + +Unify, with its **automatic syncing**, **AI optimization potential**, and **declarative approach** to building applications, is an advanced framework that offers significant time-saving benefits. By adding this to your CV, you're showcasing your ability to work with **cutting-edge technologies** that address modern full-stack development challenges. + +If you’re comfortable with the framework’s complexity and confident in its capabilities, it would be **highly beneficial** to include it on your CV, especially if you're targeting positions where efficiency, innovation, and full-stack expertise are valued. diff --git a/application/demo/animations/animation.color.js b/application/demo/animations/animation.color.js new file mode 100644 index 0000000..57ab391 --- /dev/null +++ b/application/demo/animations/animation.color.js @@ -0,0 +1,69 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + create() { + + this.animation = this.createAnimation("backgroundAnimation"); + + var key = this.animation.createKeyFrame( 0 ); + + key.setProperty( "background", "#03a9f4" ); + + + var key = this.animation.createKeyFrame( 40 ); + + key.setProperty( "background", "#a6e22e" ); + + + + var key = this.animation.createKeyFrame( 70 ); + + key.setProperty( "background", "#f92672" ); + + + + var key = this.animation.createKeyFrame( 100 ); + + key.setProperty( "background", "#03a9f4" ); + + } + + async click() { + + this.animation.play("2s"); + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("Background color"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animation.move.js b/application/demo/animations/animation.move.js new file mode 100644 index 0000000..b0e1e39 --- /dev/null +++ b/application/demo/animations/animation.move.js @@ -0,0 +1,79 @@ + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + marginTop = 12; + + marginLeft = 12; + + create() { + + + this.moveAnimation = this.createAnimation("moveAnimation"); + + + var key = this.moveAnimation.createKeyFrame( 0 ); + + key.setProperty( "margin-right", 12 ); + + + var key = this.moveAnimation.createKeyFrame( 20 ); + + //key.setProperty( "margin-top", 200 ); + key.setProperty( "margin-right", 40 ); + + + var key = this.moveAnimation.createKeyFrame( 30 ); + + //key.setProperty( "margin-top", 500 ); + key.setProperty( "margin-right", 120 ); + + + var key = this.moveAnimation.createKeyFrame( 50 ); + + key.setProperty( "margin-top", 200 ); + + + var key = this.moveAnimation.createKeyFrame( 100 ); + + //key.setProperty( "margin-top", 0 ); + + } + + async click() { + + this.moveAnimation.play("2s"); + + } + +} + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class moveRow extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("Move"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animation.render.js b/application/demo/animations/animation.render.js new file mode 100644 index 0000000..4e7d082 --- /dev/null +++ b/application/demo/animations/animation.render.js @@ -0,0 +1,50 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + time = 0; + + + render( ) { + + this.time++; + + this.width = 100 + ( Math.cos( this.time / 100 ) * 100 ); + + this.height = 100 + ( Math.sin( this.time / 100 ) * 100 ); + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("RenderLoop"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animation.reverse.js b/application/demo/animations/animation.reverse.js new file mode 100644 index 0000000..2cc62ab --- /dev/null +++ b/application/demo/animations/animation.reverse.js @@ -0,0 +1,188 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + +import button from '/elements/button.js'; + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + create() { + + this.animation = this.createAnimation("reverseAnimation"); +/* + var key = this.animation.createKeyFrame( 0 ); + + key.setProperty( "rotate", "0deg" ); + + + var key = this.animation.createKeyFrame( 20 ); + + key.setProperty( "rotate", "60deg" ); + + + var key = this.animation.createKeyFrame( 60 ); + + key.setProperty( "rotate", "120deg" ); + + + var key = this.animation.createKeyFrame( 100 ); + + key.setProperty( "rotate", "0deg" ); + + */ + var key = this.animation.createKeyFrame( 0 ); + + key.setProperty( "rotate", "0deg" ); + + + + var key = this.animation.createKeyFrame( 100 ); + + key.setProperty( "rotate", "360deg" ); + + this.animation.duration = "2s" + + this.animation.iterationCount = "infinite" + + this.animation.fillMode = "forwards" + } + + async mouseover() { + + + + + //this.animation.play(); + + } + + async mouseleave() { + + //this.animation.pause(); + + } + +} + +class forwardButton extends button{ + + text = "Direction Forward"; + + click() { + + var animation = this.parent.parent.animationBlock.animation; + + animation.direction = "normal" + + } + + +} + +class backwardButton extends button{ + + text = "Direction Backward"; + + click() { + + var animation = this.parent.parent.animationBlock.animation; + + animation.direction = "reverse" + + } + +} + + +class pauseButton extends button{ + + text = "Pause"; + + click() { + + var animation = this.parent.parent.animationBlock.animation; + + + animation.pause(); + } + +} + +class playButton extends button{ + + text = "Play"; + + click() { + + var animation = this.parent.parent.animationBlock.animation; + + animation.play(); + + } + +} + +class stopButton extends button{ + + text = "Stop"; + + click() { + + var animation = this.parent.parent.animationBlock.animation; + + animation.stop(); + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + +class buttons{ + + + + playButton = new playButton(); + + pauseButton = new pauseButton(); + + stopButton = new stopButton(); + + forwardButton = new forwardButton(); + + backwardButton = new backwardButton(); + + + flexDirection = "column" + +} + + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("Reverse"); + + buttons = new buttons(); + + animationBlock = new animationBlock(); + + +} \ No newline at end of file diff --git a/application/demo/animations/animation.rotate.js b/application/demo/animations/animation.rotate.js new file mode 100644 index 0000000..b1ec303 --- /dev/null +++ b/application/demo/animations/animation.rotate.js @@ -0,0 +1,67 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + create() { + + this.animation = this.createAnimation("rotateAnimation"); + + var key = this.animation.createKeyFrame( 0 ); + + key.setProperty( "rotate", "0deg" ); + + + var key = this.animation.createKeyFrame( 20 ); + + key.setProperty( "rotate", "60deg" ); + + + var key = this.animation.createKeyFrame( 60 ); + + key.setProperty( "rotate", "120deg" ); + + + var key = this.animation.createKeyFrame( 100 ); + + key.setProperty( "rotate", "0deg" ); + + } + + async click() { + + this.animation.play("2s"); + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("Rotate"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animation.rotateMoveColor.js b/application/demo/animations/animation.rotateMoveColor.js new file mode 100644 index 0000000..5aa5d22 --- /dev/null +++ b/application/demo/animations/animation.rotateMoveColor.js @@ -0,0 +1,145 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + + zIndex = 4; + + + create() { + + this.rotateAnimation = this.createAnimation("rotateAnimation"); + + var key = this.rotateAnimation.createKeyFrame( 0 ); + + key.setProperty( "rotate", "0deg" ); + + + var key = this.rotateAnimation.createKeyFrame( 20 ); + + key.setProperty( "rotate", "60deg" ); + + + var key = this.rotateAnimation.createKeyFrame( 60 ); + + key.setProperty( "rotate", "120deg" ); + + + var key = this.rotateAnimation.createKeyFrame( 100 ); + + key.setProperty( "rotate", "0deg" ); + + + + + + + this.moveAnimation = this.createAnimation("moveAnimation"); + + var key = this.moveAnimation.createKeyFrame( 0 ); + + key.setProperty( "margin-right", 12 ); + + + var key = this.moveAnimation.createKeyFrame( 20 ); + + //key.setProperty( "margin-top", 200 ); + key.setProperty( "margin-right", 40 ); + + + var key = this.moveAnimation.createKeyFrame( 30 ); + + //key.setProperty( "margin-top", 500 ); + key.setProperty( "margin-right", 120 ); + + + var key = this.moveAnimation.createKeyFrame( 50 ); + + key.setProperty( "margin-top", 200 ); + + + var key = this.moveAnimation.createKeyFrame( 100 ); + + //key.setProperty( "margin-top", 0 ); + + + + + this.backgroundAnimation = this.createAnimation("backgroundAnimation"); + + var key = this.backgroundAnimation.createKeyFrame( 0 ); + + key.setProperty( "background", "#03a9f4" ); + + + var key = this.backgroundAnimation.createKeyFrame( 40 ); + + key.setProperty( "background", "#a6e22e" ); + + + + var key = this.backgroundAnimation.createKeyFrame( 70 ); + + key.setProperty( "background", "#f92672" ); + + + + var key = this.backgroundAnimation.createKeyFrame( 100 ); + + key.setProperty( "background", "#03a9f4" ); + + + } + + async click() { + + + this.text = "Rotating and moving."; + + this.rotateAnimation.play("2s"); + + await this.moveAnimation.play("3s"); + + + + this.text = "Changing background color."; + + await this.backgroundAnimation.play("2s"); + + + this.text = "Animation is done." + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("Rotate + Move + Background"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animation.skewX.js b/application/demo/animations/animation.skewX.js new file mode 100644 index 0000000..86e7ed9 --- /dev/null +++ b/application/demo/animations/animation.skewX.js @@ -0,0 +1,67 @@ + + +import panelRow from '/elements/panel/row.js'; + +import label from '/elements/label.js'; + + +class animationBlock{ + + width = 100; + + height = 100; + + margin = 20; + + background = "#03a9f4"; + + create() { + + this.animation = this.createAnimation("rotateAnimation"); + + var key = this.animation.createKeyFrame( 0 ); + + key.setProperty( "skewX", "0deg" ); + + + var key = this.animation.createKeyFrame( 20 ); + + key.setProperty( "skewX", "14deg" ); + + + var key = this.animation.createKeyFrame( 60 ); + + key.setProperty( "skewX", "52deg" ); + + + var key = this.animation.createKeyFrame( 100 ); + + key.setProperty( "skewX", "0deg" ); + + } + + async click() { + + this.animation.play("2s"); + + } + +} + + +class rowLabel extends label{ + + flex = "1"; + +} + + +export default class row extends panelRow{ + + boxWidth = "95%" + + rowLabel = new rowLabel("skewX"); + + animationBlock = new animationBlock(); + +} \ No newline at end of file diff --git a/application/demo/animations/animations.js b/application/demo/animations/animations.js new file mode 100644 index 0000000..f9f844a --- /dev/null +++ b/application/demo/animations/animations.js @@ -0,0 +1,95 @@ + +import moveAnimation from "./animation.move.js"; + +import rotateAnimation from "./animation.rotate.js"; + +import backgroundColor from "./animation.color.js"; + +import skewX from "./animation.skewX.js"; + +import rotateMoveColor from "./animation.rotateMoveColor.js"; + +import reverse from "./animation.reverse.js"; + +import render from "./animation.render.js"; + +export default class animations{ + + overflowY = "auto" + + height = 600; + + width = "auto" + + flexDirection = "column"; + + + scrollbarWidth = "6px"; + + scrollbarTrackBackground = "#1c1d1e"; + + scrollbarThumbBackground = "#404040" + + scrollbarThumbBorderRadius = "4px" + + scrollbarThumbHoverBackground = "grey"; + + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#fdfdfd"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + background = "#202020cc"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + #endif + + #endif + + + layers = 1; + + // height = "-webkit-fill-available"; + + padding = 20; + + // width = "100%" + + + moveAnimation = new moveAnimation(); + + rotateAnimation = new rotateAnimation(); + + backgroundColor = new backgroundColor(); + + skewX = new skewX(); + + + rotateMoveColor = new rotateMoveColor(); + + reverse = new reverse(); + + render = new render(); + +} \ No newline at end of file diff --git a/application/demo/application.js b/application/demo/application.js new file mode 100644 index 0000000..54e2c30 --- /dev/null +++ b/application/demo/application.js @@ -0,0 +1,183 @@ + + +import minimizeButton from './minimizeButton.js'; + +import leftSide from './leftSide/leftSide.js'; + +import rightSide from './rightSide/rightSide.js'; + +import document from '/unify/document.js'; + +import vector2 from '/unify/math/vector2.js'; + +import flexbox from '/elements/flexbox.js'; + +import frostedGlass from '/elements/window/frostedGlass.js'; + +import draggable from '/elements/window/draggable.js'; + + + +export default class application extends frostedGlass, flexbox, draggable{ + + // Children + minimizeButton = new minimizeButton(); + + leftSide = new leftSide(); + + rightSide = new rightSide(); + + // Environment + mode = "development" + + os = "Windows"; + + device = "Pc"; + + tint = "Dark"; + + + loadThemes = true; + + + maxClients = 1000; + + cacheBuildSpeed = 4; + + maxClusters = 1; + + //serverAddress = "192.168.178.15"; + + + // Styling + position = "absolute"; + + borderRadius = 12; + + boxBackgroundSize = "1000px 1000px"; + + boxTransition = "background-image 0.1s ease-in-out"; + + boxHeight = "100vh"; + + position = "absolute"; + + + + #ifdef ANDROID + + flexDirection = "column"; + + #else + + flexDirection = "row"; + + #endif + + + + + // Pragma's + #ifdef ANDROID + + lastPosition = new vector2( 0, 0 ); + + fontFamily = "android"; + + transform = "translate(0px, 0px)"; + + #endif + + #ifdef WINDOWS + + fontFamily = "SegoeUI"; + + #ifdef DARK + + //boxBackgroundImage = "url('/assets/images/wallpapers/windows/light/2048.png')"; + + //backgroundImage = "url('/assets/images/wallpapers/windows/light/blur_1024.jpg')"; + + #endif + + #ifdef LIGHT + + //boxBackgroundImage = "url('/assets/images/wallpapers/windows/light/2048.jpg')"; + + //backgroundImage = "url('/assets/images/wallpapers/windows/light/blur_1024.jpg')"; + + #endif + + border = "1px solid rgb(65 84 118 / 32%)"; + + #endif + + + #ifdef MACOS + + fontFamily = "Inter"; + + #ifdef DARK + + //boxBackgroundImage = "url('/assets/images/wallpapers/ventura/dark/dark.jpg')"; + + //backgroundImage = "url('/assets/images/wallpapers/ventura/dark/darkBlur.jpg')"; + + border = "1px solid #8f8f8f59"; + + outline = "1px solid black"; + + #endif + + #ifdef LIGHT + + //boxBackgroundImage = "url('/assets/images/wallpapers/ventura/light/light.jpg')"; + + //backgroundImage = "url('/assets/images/wallpapers/ventura/light/lightBlur.jpg')"; + + #endif + + #endif + + // Methods + afterLoad() { + + console.log( "loaded application", this ); + + this.centerObject(); + + } + + centerObject() { + + var domWindow = document.defaultView; + + this.windowHeight = domWindow.innerHeight; + + this.windowWidth = domWindow.innerWidth; + + + var boundBox = this.defaultElement.getBoundingClientRect(); + + + var width = boundBox.width; + + var height = boundBox.height; + + + var x = this.windowWidth / 2 - ( width / 2 ); + + var y = this.windowHeight / 2 - ( height / 2 ); + + + this.lastPosition = new vector2( Math.round( x ), Math.round( y ) ); + + } + + click() { + + this.boxShadow = "1px 1px 3px 0px #00000054" + + } + +} \ No newline at end of file diff --git a/application/demo/comment/comment.body.js b/application/demo/comment/comment.body.js new file mode 100644 index 0000000..dc91cf1 --- /dev/null +++ b/application/demo/comment/comment.body.js @@ -0,0 +1,11 @@ + + +import column from '/unify/column.js'; + + +export default class body extends column { + +} + + + diff --git a/application/demo/comment/comment.js b/application/demo/comment/comment.js new file mode 100644 index 0000000..b30cf4e --- /dev/null +++ b/application/demo/comment/comment.js @@ -0,0 +1,22 @@ + +import table from '/unify/table.js'; + +import user from '/user/user.js'; + +import body from './comment.body.js'; + +import title from './comment.title.js'; + + +export default class comment extends table{ + + author = new user(); + + title = new title(); + + body = new body(); + + flexDirection = "column"; + +} + diff --git a/application/demo/comment/comment.title.js b/application/demo/comment/comment.title.js new file mode 100644 index 0000000..57481d1 --- /dev/null +++ b/application/demo/comment/comment.title.js @@ -0,0 +1,40 @@ + + +import column from '/unify/column.js'; + + +export default class title extends column { + + padding = 20; + + color = "black"; + + label = "title"; + + useCustomElement = true; + + + async keyup( event ){ + + this.value = event.target.value; + + this.animate(150, 400, function( value ){ + + this.height = value; + + }) + + var result = await this.socketManager.get( "column", "update", this, "keyup" ); + + } + + serverKeyup( object ) { + + this.value = object.value; + + } + +} + + + diff --git a/application/demo/comment/comments.messages.js b/application/demo/comment/comments.messages.js new file mode 100644 index 0000000..8833505 --- /dev/null +++ b/application/demo/comment/comments.messages.js @@ -0,0 +1,48 @@ + +import renderCollection from '/unify/renderCollection.js'; + +import groups from '/user/group/user.group.permission.js'; + +import OR from '/unify/sql/OR.js'; + +import AND from '/unify/sql/AND.js'; + +import LIKE from '/unify/sql/LIKE.js'; + + +export default class commentsMessages extends renderCollection { + + flexFlow = "column"; + + direction = "desc"; + + width = "-webkit-fill-available"; + + marginTop = 20; + + debug = true; + + node async search( value ) { + + var filter = this.getFilter(); + + filter.search = OR( LIKE( filter.body, value ), LIKE( filter.title, value ) ); + + filter.direction = "desc"; + + } + + permission() { + + this.allow( groups.visitor, "READ" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + + + + } + +} \ No newline at end of file diff --git a/application/demo/comment/create/comment.create.author.js b/application/demo/comment/create/comment.create.author.js new file mode 100644 index 0000000..b6bb7b4 --- /dev/null +++ b/application/demo/comment/create/comment.create.author.js @@ -0,0 +1,8 @@ + +import user from '/user/user.js'; + +export default class commentEditAuthor extends user{ + + display = "none"; + +} \ No newline at end of file diff --git a/application/demo/comment/create/comment.create.body.js b/application/demo/comment/create/comment.create.body.js new file mode 100644 index 0000000..ae3b1f4 --- /dev/null +++ b/application/demo/comment/create/comment.create.body.js @@ -0,0 +1,16 @@ + + +import commentBody from '../comment.body.js'; + +import textarea from '/elements/textarea.js'; + + +export default class commentEditBody extends commentBody, textarea{ + + useCustomElement = true; + + height = "97px"; + + placeholder = "Message"; + +} \ No newline at end of file diff --git a/application/demo/comment/create/comment.create.js b/application/demo/comment/create/comment.create.js new file mode 100644 index 0000000..ddb832b --- /dev/null +++ b/application/demo/comment/create/comment.create.js @@ -0,0 +1,103 @@ + +import comment from '../comment.js'; + +import saveButton from './comment.saveButton.js'; + +import userLabel from './comment.userLabel.js'; + +import commentEditTitle from './comment.create.title.js'; + +import commentEditBody from './comment.create.body.js'; + +import commentEditAuthor from './comment.create.author.js'; + +import header from '/elements/header.js'; + +import collection from '/unify/collection.js'; + +import groups from '/user/group/user.group.permission.js'; + + + +export default class createComment extends comment{ + + display = "flex"; + + body = new commentEditBody(); + + saveButton = new saveButton(); + + title = false; + + author = this.user; // bug destroys the permission system + + + #ifdef WINDOWS + + #ifdef DARK + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef MACOS + + #ifdef DARK + + background = "#00000042"; + + #endif + + #ifdef LIGHT + + background = "#ffffffd1"; + + #endif + + #endif + + width = "50vw"; + + debug = true; + + width = "100%"; + + marginTop = 40; + + + async create() { + + this.body.value = ""; + + this.setID( false ); + + } + + disableWRITE() { + + this.hide(); + + } + + enableWRITE() { + + this.show(); + + } + + permission() { + + this.allow( groups.member, "WRITE" ); + + this.allow( groups.admin, "WRITE" ); + + } + +} + + diff --git a/application/demo/comment/create/comment.create.title.js b/application/demo/comment/create/comment.create.title.js new file mode 100644 index 0000000..8906e11 --- /dev/null +++ b/application/demo/comment/create/comment.create.title.js @@ -0,0 +1,8 @@ + + +import commentTitle from '../comment.title.js'; + + +export default class commentEditTitle extends commentTitle{ + +} \ No newline at end of file diff --git a/application/demo/comment/create/comment.saveButton.js b/application/demo/comment/create/comment.saveButton.js new file mode 100644 index 0000000..30b6acf --- /dev/null +++ b/application/demo/comment/create/comment.saveButton.js @@ -0,0 +1,29 @@ + +import button from '/elements/button.js'; + +import tools from '/unify/tools.js'; + + +export default class saveCommentButton extends button { + + label = "Create comment"; + + async click( event ){ + + var result = await this.socketManager.get( "table", "save", this.parent ); + + this.parent.create(); + + await this.parent.parent.commentsMessages.sync(); + + this.parent.parent.customElement.scrollTo( 0, this.parent.parent.customElement.scrollHeight); + + console.log("laatste", this.parent.parent.customElement.scrollHeight); + + } + + +} + + + diff --git a/application/demo/comment/create/comment.userLabel.js b/application/demo/comment/create/comment.userLabel.js new file mode 100644 index 0000000..2fd28a9 --- /dev/null +++ b/application/demo/comment/create/comment.userLabel.js @@ -0,0 +1,38 @@ + +import input from '/elements/input.js'; + +export default class userLabel extends input{ + + float = "right"; + + useCustomElement = false; + + height = 20; + + float = "right"; + + marginLeft = 100; + + marginTop = 20; + + + setAuthor( author ) { + + if( author.username ) { + + this.value = "author: " + author.username.value; + + } + } + + + create() { + + var author = this.parent.parent.author; + + this.setAuthor( author ); + + } + +} + diff --git a/application/demo/comment/edit/comment.deleteButton.js b/application/demo/comment/edit/comment.deleteButton.js new file mode 100644 index 0000000..7fdbd06 --- /dev/null +++ b/application/demo/comment/edit/comment.deleteButton.js @@ -0,0 +1,37 @@ + +import button from '/elements/button.js'; + +export default class deleteButton extends button { + + label = "Delete"; + + #ifdef ANDROID + + fontSize = 12; + + width = "auto" + + height = "auto" + + #endif + + async click() { + + var sure = confirm("Are you sure you want to delete this Post"); + + if( sure ) { + + this.parent.parent.delete(); + + this.parent.parent.remove(); + + } + } +} + + + + + + + diff --git a/application/demo/comment/edit/comment.edit.author.js b/application/demo/comment/edit/comment.edit.author.js new file mode 100644 index 0000000..699737b --- /dev/null +++ b/application/demo/comment/edit/comment.edit.author.js @@ -0,0 +1,10 @@ + + +import user from '/user/user.js'; + + +export default class commentEditAuthor extends user{ + + display = "none"; + +} \ No newline at end of file diff --git a/application/demo/comment/edit/comment.edit.body.js b/application/demo/comment/edit/comment.edit.body.js new file mode 100644 index 0000000..eb8d4d6 --- /dev/null +++ b/application/demo/comment/edit/comment.edit.body.js @@ -0,0 +1,109 @@ + +import commentBody from '../comment.body.js'; + +import textarea from '/elements/textarea.js'; + +import document from '/unify/document.js'; + +import flexbox from '/elements/flexbox.js'; + + +export default class commentEditBody extends commentBody, flexbox{ + + customElement = document.createElement("textarea"); + + useCustomElement = true; + + width = "-webkit-fill-available" + + padding = 20; + + + #ifdef MACOS + + #ifdef LIGHT + + background = "white"; + + color = "black"; + + borderRadius = 12; + + margin = 6; + + #endif + + + #ifdef DARK + + background = "#282828!important"; + + + //color = "white"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef LIGHT + + background = "none"; + + color = "black"; + + #endif + + + #ifdef DARK + + background = "#202020cc"; + + borderRadius = 12; + + #endif + + margin = 16; + + #endif + + + + + + async keyup( event ){ + + this.value = event.target.value; + + var result = await this.socketManager.get( "column", "update", this, "keyup" ); + + } + + + create() { + + this.deactivateTextarea() + + } + + activateTextarea() { + + this.useCustomElement = true; + + } + + deactivateTextarea() { + + this.useCustomElement = false; + + + } + + useCustomElement = false; + + fontSize = 14; + + //color = "red"; + +} \ No newline at end of file diff --git a/application/demo/comment/edit/comment.edit.js b/application/demo/comment/edit/comment.edit.js new file mode 100644 index 0000000..6ad9c7d --- /dev/null +++ b/application/demo/comment/edit/comment.edit.js @@ -0,0 +1,127 @@ + +import comment from '../comment.js'; + +import saveButton from './comment.saveButton.js'; + +import commentEditTitle from './comment.edit.title.js'; + +import commentEditBody from './comment.edit.body.js'; + +import commentEditAuthor from './comment.edit.author.js'; + +import header from '/elements/header.js'; + +import collection from '/unify/collection.js'; + +import userLabel from './comment.userLabel.js'; + +import deleteButton from './comment.deleteButton.js'; + +import editButton from './comment.editButton.js'; + +import information from './comment.information.js'; + + + +export default class editComment extends comment{ + + + + + layers = 1; + + display = "flex"; + + debug = true; + + flexFlow = "column"; + + gridTemplate = " '_information ' " + + " 'body ' " + + " 'body ' " + + " 'saveButton ' "; + + + _information = new information(); + + body = new commentEditBody(); + + title = new commentEditTitle(); + + saveButton = new saveButton(); + + + + + width = "-webkit-fill-available"; + + #ifdef ANDROID + + width = "100vw" + + borderRadius = 18 + + margin = 4 + + + #ifdef LIGHT + + background = "white"; + + #endif + + #endif + + + create() { + + this.title.hide(); + + this.author.disable = true; + + if( !this.id ) { + + this.body.useCustomElement = true; + + } + + } + + enableWRITE() { + + this._information._editButton.show(); + + } + + disableWRITE() { + + this._information._editButton.hide(); + + this.body.useCustomElement = false; + + this.saveButton.hide(); + + } + + enableDELETE() { + + this._information._deleteButton.show(); + + } + + disableDELETE() { + + this._information._deleteButton.hide(); + + } + + permission() { + + this.allow( this.author, "WRITE" ); + this.allow( this.author, "DELETE" ); + + } + +} + + diff --git a/application/demo/comment/edit/comment.edit.title.js b/application/demo/comment/edit/comment.edit.title.js new file mode 100644 index 0000000..2f13d12 --- /dev/null +++ b/application/demo/comment/edit/comment.edit.title.js @@ -0,0 +1,31 @@ + + +import commentTitle from '../comment.title.js'; + + +export default class commentEditTitle extends commentTitle{ + + + useCustomElement = false; + + borderLeft = "solid 1px #faebd7"; + + borderRight = "solid 1px #faebd7"; + + enableInput() { + + this.background = "#373b44"; + + this.useCustomElement = true; + + } + + disableInput() { + + this.background = "white"; + + this.useCustomElement = false; + + } + +} \ No newline at end of file diff --git a/application/demo/comment/edit/comment.editButton.js b/application/demo/comment/edit/comment.editButton.js new file mode 100644 index 0000000..06cf1ba --- /dev/null +++ b/application/demo/comment/edit/comment.editButton.js @@ -0,0 +1,35 @@ + +import button from '/elements/button.js'; + +export default class editButton extends button{ + + label = "Edit"; + + #ifdef ANDROID + + fontSize = 12; + + width = "auto" + + height = "auto" + + #endif + + async click() { + + this.parent.parent.body.activateTextarea(); + + this.parent.parent.saveButton.show(); + + this.hide(); + + } + +} + + + + + + + diff --git a/application/demo/comment/edit/comment.information.js b/application/demo/comment/edit/comment.information.js new file mode 100644 index 0000000..349af90 --- /dev/null +++ b/application/demo/comment/edit/comment.information.js @@ -0,0 +1,70 @@ + +import userLabel from './comment.userLabel.js'; + +import deleteButton from './comment.deleteButton.js'; + +import editButton from './comment.editButton.js'; + +import icon from '/elements/icon.js'; + + +class chatIcon extends icon{ + + margin = 12; + + +} + +export default class information{ + + + width = "100%"; + + display = "grid"; + + display = "flex"; + + flexFlow = "row"; + + layers = 2; + + borderBottom = "#2b2c2d57"; + + borderTop = "#2b2c2d57"; + + + gridTemplate = " '_deleteButton _editButton' " + + " 'userLabel userLabel' "; + + gridTemplateColumns = "40px 100px"; + + gridTemplateRows = "40px 60px"; + + #ifdef WINDOWS + + #ifdef LIGHT + + background = "#4b94d31f"; + + #endif + + #ifdef DARK + + //background = "rgb(48 51 56 / 86%)"; + + #endif + + #endif + + + + + _deleteButton = new deleteButton( ); + + _editButton = new editButton( ); + + _userLabel = new userLabel(); + + //_icon = new chatIcon("ios-chatbubbles-outline.svg", true); + +} \ No newline at end of file diff --git a/application/demo/comment/edit/comment.saveButton.js b/application/demo/comment/edit/comment.saveButton.js new file mode 100644 index 0000000..6da0c6d --- /dev/null +++ b/application/demo/comment/edit/comment.saveButton.js @@ -0,0 +1,36 @@ + +import button from '/elements/button.js'; + +import tools from '/unify/tools.js'; + + +export default class saveEditButton extends button { + + text = "Save Message"; + + display = "none"; + + userContract; + + + async click( event ){ + + var result = await this.socketManager.get( "table", "save", this, "sign" ); + + this.parent.id = false; + + this.hide(); + + this.parent._information._editButton.show(); + + this.parent.body.useCustomElement = false; + + //this.parent.background = "#cdf0ce"; + + } + + +} + + + diff --git a/application/demo/comment/edit/comment.userLabel.js b/application/demo/comment/edit/comment.userLabel.js new file mode 100644 index 0000000..fd9d9a9 --- /dev/null +++ b/application/demo/comment/edit/comment.userLabel.js @@ -0,0 +1,34 @@ + +import input from '/elements/input.js'; + +import label from '/elements/label.js'; + +export default class userLabel extends label { + + float = "left"; + + fontWeight = "bold"; + + padding = "12px"; + + paddingLeft = 26; + + setAuthor( author ) { + + if( author.username ) { + + this.text = author.username.value; + + } + } + + create() { + + var author = this.parent.parent.author; + + this.setAuthor( author ); + + } + +} + diff --git a/application/demo/edit/news.edit.body.js b/application/demo/edit/news.edit.body.js new file mode 100644 index 0000000..cfa3816 --- /dev/null +++ b/application/demo/edit/news.edit.body.js @@ -0,0 +1,19 @@ + +import newsBody from '../news.body.js'; + +import textarea from '/elements/textarea.js'; + + +export default class newsPageBody extends newsBody, textarea{ + + placeholder = "Message"; + + height = 120; + + async keyup( event ) { + + this.value = event.target.value; + + } + +} \ No newline at end of file diff --git a/application/demo/edit/news.edit.button.js b/application/demo/edit/news.edit.button.js new file mode 100644 index 0000000..3f01eee --- /dev/null +++ b/application/demo/edit/news.edit.button.js @@ -0,0 +1,39 @@ +import button from '/elements/button.js'; + +export default class editButton extends button { + + label = "Save"; + + async click( event, object ){ + + var result = await this.parent.parent.save(); + + // reset id so you can create a new row again + var editNewsDialog = this.parent.parent; + + editNewsDialog.id = false; + + // reset title + editNewsDialog.newsTitleRow.title.value = ""; + + // reset body + editNewsDialog.newsBodyRow.body.value = ""; + + editNewsDialog.hide(); + + this.parents("newsPages").newsPage.sync(); + + if( this.parents("newsItemPage").newsListTable ) { + + this.parents("newsItemPage").newsListTable.body.update(); + + + + + + + } + + } + +} \ No newline at end of file diff --git a/application/demo/edit/news.edit.js b/application/demo/edit/news.edit.js new file mode 100644 index 0000000..4cb9008 --- /dev/null +++ b/application/demo/edit/news.edit.js @@ -0,0 +1,246 @@ + + +import news from '../news.js'; + +import newsEditTitle from './news.edit.title.js'; + +import newsEditBody from './news.edit.body.js'; + +import newsEditbutton from './news.edit.button.js'; + +import newsEditPrice from './news.edit.price.js'; + + +import groups from '/user/group/user.group.permission.js'; + +import label from '/elements/label/left.js'; + +import panel from '/elements/panel.js'; + +import frostedGlass from '/elements/window/frostedGlass.js'; + +import draggable from '/elements/window/draggable.js'; + +import button from '/elements/button.js'; + + +import panelRow from '/elements/panel/row.js'; + +class newsBodyRow extends panelRow{ + + #ifdef WINDOWS + + background = "none"; + + #endif + + border = "none" + + label = new label("Message"); + + body = new newsEditBody(); + +} + +class newsTitleRow extends panelRow{ + + #ifdef WINDOWS + + background = "none"; + + #endif + + border = "none" + + label = new label("Title"); + + title = new newsEditTitle(); + +} + +class newsPriceRow extends panelRow{ + + #ifdef WINDOWS + + background = "none"; + + #endif + + border = "none" + + label = new label("Price"); + + price = new newsEditPrice(); + +} + + + +class cancelButton extends button{ + + text = "Cancel"; + + boxWidth = "100%" + + + click() { + + this.parent.parent.hide(); + + } + +} + + +class newsButtonRow extends panelRow{ + + border = "none" + + cancelButton = new cancelButton(); + + newsEditbutton = new newsEditbutton(); + + + #ifdef WINDOWS + + background = "none"; + + #endif + +} + + +import header from '/elements/window/header.js'; + +export default class newsEdit extends news, panel, draggable { + + header = new header("News"); + + layers = 2; + + zIndex = 10000; + + + #ifdef WINDOWS + + fontFamily = "segoe"; + + + #endif + + + + #ifdef MACOS + + fontFamily = "sf-ui"; + + width = 600; + + #ifdef DARK + + background = "#161110bf"; + + + + #endif + + #ifdef LIGHT + + //background = "white"; + + background = "#fdfdfdbf" + + #endif + + backdropFilter = "blur(22px)"; + + #endif + + #ifdef WINDOWS + + fontFamily = "SegoeUI"; + + width = 600; + + #ifdef DARK + + background = "#202020cc"; + + border = "1px solid rgb(44 45 46)"; + + + + #endif + + #ifdef LIGHT + + //background = "white"; + + background = "#fdfdfdbf" + + #endif + + backdropFilter = "blur(22px)"; + + #endif + + + + + selector = "#application"; + + display = "none"; + + flexDirection = "column"; + + debug = true; + + position = "absolute" + + boxBackgroundImage; + + newsTitleRow = new newsTitleRow(); + + newsPriceRow = new newsPriceRow(); + + newsBodyRow = new newsBodyRow(); + + newsButtonRow = new newsButtonRow(); + + + + debug = true; + + height = "fit-content"; + + async create() { + + //await this.sync(); + + //this.hide(); + + } + + afterLoad() { + + this.center(); + + } + + permission() { + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + this.allow( groups.visitor, "READ" ); + + this.allow( groups.member, "WRITE" ); + + this.allow( groups.admin, "WRITE" ); + + this.allow( groups.visitor, "WRITE" ); + + } + +} \ No newline at end of file diff --git a/application/demo/edit/news.edit.price.js b/application/demo/edit/news.edit.price.js new file mode 100644 index 0000000..014126f --- /dev/null +++ b/application/demo/edit/news.edit.price.js @@ -0,0 +1,18 @@ + +import newsPrice from '../news.price.js'; + +import input from '/elements/input.js'; + + +export default class newsPagePrice extends newsPrice, input{ + + placeholder = "Price"; + + + async keyup( event ) { + + this.value = event.target.value; + + } + +} \ No newline at end of file diff --git a/application/demo/edit/news.edit.title.js b/application/demo/edit/news.edit.title.js new file mode 100644 index 0000000..36ec861 --- /dev/null +++ b/application/demo/edit/news.edit.title.js @@ -0,0 +1,11 @@ + +import newsTitle from '../news.title.js'; + +import input from '/elements/input.js'; + + +export default class newsEditTitle extends input, newsTitle{ + + placeholder = "Title"; + +} \ No newline at end of file diff --git a/application/demo/examples/grids.js b/application/demo/examples/grids.js new file mode 100644 index 0000000..a1d2b63 --- /dev/null +++ b/application/demo/examples/grids.js @@ -0,0 +1,140 @@ + +import input from "/elements/input.js" + +import page from "/elements/page.js" + + +class label{ + + constructor( text ) { + + this.text = text; + + } + + background = "#0000002e" + + borderRadius = 6; + + margin = 10; + + padding = 26; + +} + +class a extends input{ + + boxAlignItems = "center" + + boxJustifyContent = "center"; + + boxColor = "black" + +} + + +class b extends input{ + + //background = "blue"; + + boxAlignItems = "center" + + boxJustifyContent = "center"; + + boxColor = "black" + +} + +class c extends input{ + + //background = "yellow"; + + boxAlignItems = "center" + + boxJustifyContent = "center"; + + boxColor = "black" + + +} + +class d extends input{ + + //boxBackground = "grey"; + + boxAlignItems = "center" + + boxJustifyContent = "center"; + + boxColor = "black" + + +} + +class gridA{ + + display = "grid"; + + gridTemplate = ` + + "label label" + "a a" + "b d" + "c d" + `; + + height = 400; + + width = "100%" + + label = new label("This is the first Grid, Press tab to navigate trough the inputs."); + + a = new a(); + + b = new b(); + + c = new c(); + + d = new d(); + +} + + +class gridB{ + + display = "grid"; + + gridTemplate = ` + + "label label" + "d d" + "a empty" + "b b" + `; + + height = 400; + + width = "100%" + + label = new label("This is the second Grid, Press tab to navigate trough the inputs."); + + a = new a(); + + b = new b(); + + c = new c(); + + d = new d(); + +} + +export default class gridExample extends page{ + + flexDirection = "column" + + + gridA = new gridA(); + + gridB = new gridB(); + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.icon.deleteButton.js b/application/demo/fileManager/fileManager.icon.deleteButton.js new file mode 100644 index 0000000..71cb99a --- /dev/null +++ b/application/demo/fileManager/fileManager.icon.deleteButton.js @@ -0,0 +1,102 @@ + +import icon from "/elements/icon.js"; + + + +#ifdef SERVER + + import fs from "fs"; + +#endif + + +const delay = time => new Promise(res=>setTimeout(res,time)); + + +export default class deleteFileIconButton extends icon{ + + width = 24; + + height = 24; + + propegateEvent = false; + + boxMarginTop = "-12px"; + + boxBorderRadius = 14; + + boxBackground = "#ffffffbf"; + + boxWidth = "fit-content"; + + boxPadding = 2; + + boxPosition = "absolute"; + + boxMarginLeft = -8; + + boxDisplay = "none"; + + + async click() { + + this.parent.opacity = "0%"; + + await delay(200) + + this.parent.background = "none"; + + this.parent.width = 0; + + this.parent.margin = 0; + + this.parent.padding = 0; + + this.parent.border = "none" + + await delay(200) + + this.parent.hide(); + + this.parent.remove(); + + var fileName = this.parent.value; + + await this.removeFile( fileName ); + + } + + node async removeFile( fileName ) { + + var absolutePath = path.resolve( "./assets/uploads/" + fileName ); + + console.log("Removing file test", absolutePath); + + if( fs.existsSync( absolutePath ) ) { + + fs.unlinkSync( absolutePath ); + + console.log("File is removed."); + + } else { + + console.log("File does not exist."); + + } + + } + + constructor() { + + super("close.svg") + + } + + create() { + + this.hide(); + + } + + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.icon.js b/application/demo/fileManager/fileManager.icon.js new file mode 100644 index 0000000..f00dcad --- /dev/null +++ b/application/demo/fileManager/fileManager.icon.js @@ -0,0 +1,164 @@ + +import icon from "/elements/icon.js"; + +import deleteButton from "./fileManager.icon.deleteButton.js"; + + +export default class fileIcon extends icon{ + + boxSizing = "border-box" + + border = "none" + + opacity = "100%" + + fontSize = "0" + + propegateEvent = false; + + backgroundSize = "cover!important" + + width = 60; + + height = 60; + + borderRadius = 12; + + margin = 6; + + display = "block"; + + float = "left"; + + layers = 1; + + border = "2px solid #F7FAFC" + + cursor = "pointer"; + + + deleteButton = new deleteButton(); + + mode = "show"; + + //transition = "2s" + + toggleEditMode() { + + if( this.mode == "show" ) { + + this.deleteButton.show(); + + this.mode = "edit"; + + this.rotateAnimation.play(); + + } else { + + this.deleteButton.hide(); + + this.mode = "show"; + + this.rotateAnimation.stop(); + + } + + } + + create() { + + this.setImage( "'/assets/uploads/" + this.value + "'" ); + + this.createKeyFrame(); + + this.opacityAnimation.play(); + + } + + createKeyFrame() { + + this.rotateAnimation = this.createAnimation("rotateAnimation"); + + var randomTime = "0."+ 2 + Math.floor(Math.random() *1000); + + this.rotateAnimation.setDuration( randomTime +"s" ); + + this.rotateAnimation.setIterationCount("infinite"); + + + var key = this.rotateAnimation.createKeyFrame( 0 ); + + key.setProperty( "rotate", "3deg" ); + + + var key = this.rotateAnimation.createKeyFrame( 50 ); + + key.setProperty( "rotate", "-3deg" ); + + + var key = this.rotateAnimation.createKeyFrame( 100 ); + + key.setProperty( "rotate", "3deg" ); + + + + this.opacityAnimation = this.createAnimation("opacityAnimation"); + + this.opacityAnimation.setIterationCount("1"); + + this.opacityAnimation.setDuration( "0.9s" ); + + this.opacityAnimation.setFillMode( "forwards" ); + + + + + var key = this.opacityAnimation.createKeyFrame( 0 ); + + key.setProperty( "opacity", "0" ); + key.setProperty( "display", "none" ); + + + var key = this.opacityAnimation.createKeyFrame( 1 ); + + key.setProperty( "opacity", "0" ); + key.setProperty( "display", "block" ); + + + var key = this.opacityAnimation.createKeyFrame( 100 ); + + key.setProperty( "display", "block" ); + key.setProperty( "opacity", "100%" ); + + } + + + mouseover() { + + this.border = "2px solid rgb(125 177 211)"; + + } + + mouseleave() { + + this.border = "2px solid #F7FAFC"; + + //this.rotateAnimation.stop(); + + } + + async click() { + + var previewWindow = this.parent.parent.previewWindow; + + previewWindow.setTitle( this.value ); + + previewWindow.show("block"); + + previewWindow.center(); + + previewWindow.setImage( "/assets/uploads/" + this.value ); + + } + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.imagePreviewWindow.js b/application/demo/fileManager/fileManager.imagePreviewWindow.js new file mode 100644 index 0000000..72f7c7a --- /dev/null +++ b/application/demo/fileManager/fileManager.imagePreviewWindow.js @@ -0,0 +1,70 @@ + +import draggable from '/elements/window/draggable.js'; + +import page from '/elements/page.js'; + +import windowHeader from '/elements/window/header.js'; + +import previewImage from './preview/previewWindow.image.js'; + + +export default class imagePreviewWindow extends draggable{ + + selector = "#application"; + + backdropFilter = "blur(22px)"; + + paddingBottom = 30; + + display = "none" + + + #ifdef WINDOWS + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)" + + #endif + + #ifdef DARK + + background = "#202020cc" + + #endif + + #endif + + create() { + + this.center(); + + this.hide(); + + } + + + + width = 600; + + + flexDirection = "column"; + + borderRadius = 12; + + windowHeader = new windowHeader(); + + previewImage = new previewImage(); + + setTitle( title ) { + + this.windowHeader.setTitle( title ); + } + + setImage( path ) { + + this.previewImage.setImage( path ) + + } + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.js b/application/demo/fileManager/fileManager.js new file mode 100644 index 0000000..381281a --- /dev/null +++ b/application/demo/fileManager/fileManager.js @@ -0,0 +1,44 @@ + + +import fileupload from './fileManager.upload.js'; + +import fileList from "./fileManager.list.js"; + +import removeIcons from "./fileManager.removeIcons.js"; + +import header from '/elements/header.js'; + +import page from '/elements/page.js'; + +import previewWindow from "./fileManager.imagePreviewWindow.js" + +import fileChooser from '/elements/fileChooser/fileChooser.js'; + + +export default class fileManager extends page{ + + + width = "100%" + + minHeight = 350; + + flexDirection = "column" + + uploadHeader = new header("Upload"); + + fileupload = new fileupload(); + + filesHeader = new header("Files"); + + removeIcons = new removeIcons(); + + fileList = new fileList(); + + previewWindow = new previewWindow(); + + + fileChooser = new fileChooser(); + + + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.list.js b/application/demo/fileManager/fileManager.list.js new file mode 100644 index 0000000..b7c00d0 --- /dev/null +++ b/application/demo/fileManager/fileManager.list.js @@ -0,0 +1,55 @@ + + +import fileIcon from "./fileManager.icon.js"; + +import panel from "/elements/panel/row.js"; + +#ifdef SERVER + + import fs from "fs"; + + import path from "path"; + +#endif + +export default class fileList extends panel{ + + margin = 20; + + padding = 20; + + display = "block"; + + async create() { + + this.empty(); + + var files = await this.readFiles(); + + } + + node async readFiles() { + + var absolutePath = path.resolve( "./assets/uploads/" ); + + var files = fs.readdirSync( absolutePath ); + + for (var i = 0; i < files.length; i++) { + + var file = files[i]; + + + var currentFileIcon = new fileIcon(); + + currentFileIcon.value = file; + + this.add( currentFileIcon ); + + + } + + return files; + + } + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.removeIcons.js b/application/demo/fileManager/fileManager.removeIcons.js new file mode 100644 index 0000000..e246e78 --- /dev/null +++ b/application/demo/fileManager/fileManager.removeIcons.js @@ -0,0 +1,74 @@ + +import icon from "/elements/icon.js"; + + +export default class removeIcons extends icon{ + + width = 14; + + height = 14; + + margin = 4; + + propegateEvent = false; + + backgroundSize = "contain!important" + + + cursor = "pointer"; + + boxMarginTop = "17px"; + + boxBorderRadius = 14; + + boxBackground = "#ffffffbf"; + + boxWidth = "fit-content"; + + boxPadding = 2; + + //boxPosition = ""; + + boxMarginLeft = 11; + + boxMarginBottom = -37; + + + constructor() { + + super("edit.svg"); + + } + + mode = "normal"; + + click() { + + var icons = this.parent.fileList.getChildren(); + + for (var i = 0; i < icons.length; i++) { + + var icon = icons[i]; + + icon.toggleEditMode(); + + } + + + if(this.mode == "normal") { + + this.setImage("/assets/images/icons/stop.png") + + this.mode = "wiggle"; + + } else { + + this.mode = "normal"; + + this.setImage("/assets/images/icons/edit.svg") + + } + + } + +} \ No newline at end of file diff --git a/application/demo/fileManager/fileManager.upload.js b/application/demo/fileManager/fileManager.upload.js new file mode 100644 index 0000000..aff6f93 --- /dev/null +++ b/application/demo/fileManager/fileManager.upload.js @@ -0,0 +1,150 @@ + +import fileUpload from "/elements/fileUpload.js"; + +import fileIcon from "./fileManager.icon.js"; + + +#ifdef SERVER + + import fs from "fs"; + + import path from "path"; + + //import android from 'androidjs'; + +#endif + + +export default class stream extends fileUpload { + + placeholder = "Upload." + + + + margin = 20; + + stream; + + type; +/* + inputType = "button"; + + + + click( event ) { + + //this.android_file_chooser(); + + + //var fileChooser = this.parent.fileChooser; + + //fileChooser.show("flex") + + //fileChooser.open(); + + } +*/ + async change( event ) { + + var input = this.customElement; + + var files = input.files; + + for (var i = 0; i < files.length; i++) { + + var file = files[i]; + + var chunksize = 64 * 1024; + + var offset = 0; + + var filename = file.name.replaceAll(" ", "_"); + + await this.createStream( filename ); + + + while( offset < file.size ) { + + const chunkfile = await file.slice( offset, offset + chunksize ); + + const chunk = await chunkfile.arrayBuffer(); + + var intChunk = new Int8Array( chunk ); + + this.writeChunk( intChunk ) + + offset += chunksize; + + } + + await this.endstream(); + + } + + } + + node async createStream( filename ) { + + var absolutePath = path.resolve( "./assets/uploads/" + filename ); + + this.filename = filename; + + console.log("Writing file to path", absolutePath); + + this.stream = fs.createWriteStream( absolutePath, { encoding: 'binary' } ); + + this.stream.on('finish', function() { + + console.log('file has been written'); + + }); + + } + + + node async writeChunk( chunk ) { + + this.stream.write( Buffer.from( Object.values( chunk ) ) ); + + } + + node async endstream() { + + this.stream.end(); + + + var currentFileIcon = new fileIcon(); + + currentFileIcon.value = this.filename; + + this.parent.fileList.add( currentFileIcon ); + + } + + node async android_file_chooser() { + + //const status = app.mobiledata.isEnabled(); + + //console.log(android); + + //console.log("Mobile Data status: ", android); + + //console.log(app.mobiledata.isEnabled()); + + } + + + //mouseover() { + + // console.log("mouseover??", this.parent.removeIcons) + + // if( this.parent.removeIcons.mode == "wiggle" ) { + + // this.parent.removeIcons.click(); + + // } + + //} + + +} \ No newline at end of file diff --git a/application/demo/fileManager/preview/previewWindow.image.js b/application/demo/fileManager/preview/previewWindow.image.js new file mode 100644 index 0000000..c1f4288 --- /dev/null +++ b/application/demo/fileManager/preview/previewWindow.image.js @@ -0,0 +1,24 @@ + +import image from "/elements/image.js"; + + +export default class previewImage extends image{ + + layers = 1; + + width = "90%" + + //height = "100%" + + margin = "0 auto"; + + backgroundSize = "contain!important"; + + propegateEvent = false; + + borderRadius = 12; + + transition = "1s" + + maxHeight = "87vh" +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.animations.js b/application/demo/leftSide/leftSide.button.animations.js new file mode 100644 index 0000000..56ef232 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.animations.js @@ -0,0 +1,51 @@ + + +import menuButton from './leftSide.button.js'; + +export default class settingsButton extends menuButton{ + + text = "Animations"; + + create() { + + //this.activateButton(); + + } + + touchstart() { + + this.click(); + + } + + async click() { + + this.stateMachine.composeState( "Animations" ); + + this.openPage(); + + + } + + state openPage() { + + var application = this.parent.parent; + + var rightSide = application.rightSide; + var menu = application.leftSide; + + this.deactivateButtons(); + this.activateButton(); + + rightSide.hideChildren(); + rightSide.animations.show(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.fileManager.js b/application/demo/leftSide/leftSide.button.fileManager.js new file mode 100644 index 0000000..6526faa --- /dev/null +++ b/application/demo/leftSide/leftSide.button.fileManager.js @@ -0,0 +1,51 @@ + + +import menuButton from './leftSide.button.js'; + +export default class fileMangerButton extends menuButton{ + + text = "File Manager"; + + create() { + + //this.activateButton(); + + } + + touchstart() { + + this.click(); + + } + + async click() { + + this.stateMachine.composeState( "File Manager" ); + + this.openPage(); + + } + + state openPage() { + + var application = this.parent.parent; + + var rightSide = application.rightSide; + + this.deactivateButtons(); + this.activateButton(); + + rightSide.hideChildren(); + rightSide.fileManager.show(); + + rightSide.fileManager.fileList.create(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.grid.js b/application/demo/leftSide/leftSide.button.grid.js new file mode 100644 index 0000000..4f69d78 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.grid.js @@ -0,0 +1,51 @@ + + +import menuButton from './leftSide.button.js'; + +export default class settingsButton extends menuButton{ + + text = "Grids"; + + create() { + + //this.activateButton(); + + } + + touchstart() { + + this.click(); + + } + + async click() { + + this.stateMachine.composeState( "Appearance" ); + + this.openPage(); + + } + + state openPage() { + + var application = this.parent.parent; + + var rightSide = application.rightSide; + var menu = application.leftSide; + + this.deactivateButtons(); + this.activateButton(); + + rightSide.hideChildren(); + rightSide.gridExample.show(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.js b/application/demo/leftSide/leftSide.button.js new file mode 100644 index 0000000..80f7d9f --- /dev/null +++ b/application/demo/leftSide/leftSide.button.js @@ -0,0 +1,202 @@ +export default class menuButton{ + + width = 110; + + color; + + background; + + fontWeight; + + #ifdef ANDROID + + width = "80vw"; + + borderRadius = 18; + + textAlign = "center" + + padding = 20; + + margin = "0 auto" + + marginTop = 8; + + fontSize = 20; + + height = 24; + + fontWeight = "600" + + fontColor = "#313131"; + + #ifdef LIGHT + + borderBottom = "1px solid #ececec"; + + background = "white"; + + #endif + + + #endif + + #ifdef WINDOWS + + borderRadius = 6; + + width = 160 + + padding = 10; + + marginTop = 2; + + marginBottom = 2; + + paddingLeft = 30; + + #endif + + + activated = false; + + propegateEvent = false; + + cursor = "pointer"; + + #ifdef WINDOWS + + #ifdef DARK + + hightlightBackgroundColor = "#2d2d2d"; + + hightlightBackgroundColor = "#0c0e165c"; + + + #endif + + #ifdef LIGHT + + hightlightBackgroundColor = "rgb(141 180 189 / 12%)"; + + #endif + + #endif + + #ifdef MACOS + + borderRadius = 8; + + padding = 10; + + paddingLeft = 20; + + fontSize = 16; + + fontWeight = "600"; + + + hightlightBackgroundColor = "rgb(189 193 221 / 22%)" + + + #ifdef LIGHT + + color = "#343434"; + + #endif + + #endif + + + activated = false; + + state activateButton() { + + this.activated = true; + + this.highlightButton(); + + } + + state deactivateButton() { + + this.activated = false; + + this.lowlightButton(); + + } + + highlightButton() { + + this.background = this.hightlightBackgroundColor; + + if( !this.activated ) { + + + } + + } + + lowlightButton() { + + if( !this.activated ) { + + this.background = ""; + + } + + } + + mouseover() { + + this.highlightButton(); + + } + + mouseleave() { + + if( !this.activated ) { + + this.lowLightButtons(); + + } + + } + + deactivateButtons() { + + var children = this.parent.getChildren(); + + for (var i = 0; i < children.length; i++) { + + var child = children[i]; + + if( child.deactivateButton ) { + + child.deactivateButton(); + + } + + } + + } + + lowLightButtons() { + + var children = this.parent.getChildren(); + + for (var i = 0; i < children.length; i++) { + + var child = children[i]; + + if( child.lowlightButton ){ + + child.lowlightButton(); + + } + + } + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.news.js b/application/demo/leftSide/leftSide.button.news.js new file mode 100644 index 0000000..33565b0 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.news.js @@ -0,0 +1,74 @@ + + +import menuButton from './leftSide.button.js'; + +export default class newsButton extends menuButton{ + + text = "Home"; + + #ifdef MACOS + + borderTopLeftRadius = 8; + + #endif + + + + create() { + + var pathName = window.location.pathname; + + var pathParts = pathName.split("/"); + + if( !pathParts[1] ) { + + this.stateMachine.composeState( ); + + } + + //this.activateButton(); + + this.openPage(); + + } + + async click() { + + this.stateMachine.composeState( "Home" ); + + this.openPage(); + + } + + state openPage() { + + var application = this.parent.parent; + + var rightSide = application.rightSide; + + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + this.deactivateButtons(); + + //this.activateButton(); + + console.log("rightSide", rightSide); + + rightSide.newsPages.newsItemPage.transform = "translateX(0)"; + + rightSide.newsPages.newsPage.transform = "translateX(0)"; + + rightSide.hideChildren(); + + rightSide.newsPages.show(); + + //rightSide.newsPages.newsItemPage.newsListTable.body.sync() + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.settings.js b/application/demo/leftSide/leftSide.button.settings.js new file mode 100644 index 0000000..95eb767 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.settings.js @@ -0,0 +1,51 @@ + + +import menuButton from './leftSide.button.js'; + +export default class settingsButton extends menuButton{ + + text = "Appearance"; + + create() { + + //this.activateButton(); + + } + + touchstart() { + + this.click(); + + } + + async click() { + + this.stateMachine.composeState( "Appearance" ); + + this.openPage(); + + } + + state openPage() { + + var application = this.parent.parent; + + var rightSide = application.rightSide; + var menu = application.leftSide; + + this.deactivateButtons(); + this.activateButton(); + + rightSide.hideChildren(); + rightSide.settings.show(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.signin.js b/application/demo/leftSide/leftSide.button.signin.js new file mode 100644 index 0000000..b3243b5 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.signin.js @@ -0,0 +1,62 @@ + + +import menuButton from './leftSide.button.js'; + +import groups from '/user/group/user.group.permission.js'; + + +export default class signinPageButton extends menuButton{ + + text = "Signin"; + + click() { + + this.stateMachine.composeState( "Signin" ); + + this.openPage(); + + } + + state openPage() { + + this.deactivateButtons(); + this.activateButton(); + + var application = this.parent.parent; + + var rightSide = application.rightSide; + + rightSide.width = ""; + + rightSide.hideChildren(); + + rightSide.signin.show(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + } + + enableREAD() { + + this.hide(); + + } + + disableREAD() { + + this.show(); + + } + + permission() { + + this.allow( groups.member , "READ" ); + this.allow( groups.admin , "READ" ); + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.signout.js b/application/demo/leftSide/leftSide.button.signout.js new file mode 100644 index 0000000..8616fdc --- /dev/null +++ b/application/demo/leftSide/leftSide.button.signout.js @@ -0,0 +1,94 @@ + + +import menuButton from './leftSide.button.js'; + +import groups from '/user/group/user.group.permission.js'; + +import userManager from '/server/userManager.js'; + + +export default class signoutButton extends menuButton{ + + text = "Signout"; + + create(){ + + this.hide(); + + } + + async click() { + + this.stateMachine.composeState( "Signout" ); + + await this.openPage(); + + } + + state async openPage() { + + this.deactivateButtons(); + this.activateButton(); + + console.log("before process",this); + + var visitorUser = await this.signout(); + + + localStorage.setItem( "username", false ); + + localStorage.setItem( "sessionKey", false ); + + this.getCore().updatePermissions( visitorUser.permissionObjects ); + + } + + createVisitor( client ) { + + var userInstance = new user(); + + userInstance.username.value = "Visitor"; + + userInstance.id = 0; + + userInstance.permissionObjects = userManager.getPermissions( userInstance, client ); + + return userInstance; + + } + + node async signout( object, client ) { + + var newUser = this.createVisitor( this.client ); + + this.client.user = newUser; + + global.core.setUserObjects( false, this.client ); + + return newUser; + + } + + enableREAD() { + + this.show(); + + } + + disableREAD() { + + this.hide(); + + } + + permission() { + + this.allow( groups.member , "PROCESS" ); + this.allow( groups.admin , "PROCESS" ); + + this.allow( groups.member , "READ" ); + this.allow( groups.admin , "READ" ); + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.signup.js b/application/demo/leftSide/leftSide.button.signup.js new file mode 100644 index 0000000..249ed3b --- /dev/null +++ b/application/demo/leftSide/leftSide.button.signup.js @@ -0,0 +1,37 @@ + +import menuButton from './leftSide.button.js'; + +export default class signinButton extends menuButton{ + + text = "Signup"; + + click() { + + this.stateMachine.composeState( "Signup" ); + + this.openPage(); + + } + + state openPage() { + + this.deactivateButtons(); + this.activateButton(); + + var application = this.parent.parent; + + var rightSide = application.rightSide; + + rightSide.hideChildren(); + + rightSide.signup.show(); + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.button.users.js b/application/demo/leftSide/leftSide.button.users.js new file mode 100644 index 0000000..c3927d8 --- /dev/null +++ b/application/demo/leftSide/leftSide.button.users.js @@ -0,0 +1,68 @@ + + +import menuButton from './leftSide.button.js'; + +import groups from '/user/group/user.group.permission.js'; + + +export default class usersPageButton extends menuButton{ + + text = "Users"; + + click() { + + this.stateMachine.composeState( "Users" ); + + this.openPage(); + + } + + state openPage() { + + this.deactivateButtons(); + + this.activateButton(); + + var application = this.parent.parent; + + var rightSide = application.rightSide; + + rightSide.width = ""; + + rightSide.hideChildren(); + + rightSide.userListPage.show(); + + rightSide.userListPage.userTable.body.create() + + #ifdef ANDROID + + application.minimizeButton.close(); + + #endif + + } + + enableREAD() { + + this.show(); + + } + + disableREAD() { + + this.hide(); + + } + + permission() { + + this.allow( groups.member , "PROCESS" ); + this.allow( groups.admin , "PROCESS" ); + + this.allow( groups.member , "READ" ); + this.allow( groups.admin , "READ" ); + + } + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.header.js b/application/demo/leftSide/leftSide.header.js new file mode 100644 index 0000000..5b0e39b --- /dev/null +++ b/application/demo/leftSide/leftSide.header.js @@ -0,0 +1,33 @@ + +import header from "/elements/header.js"; + +export default class menuHeader extends header{ + + text = "Menu"; + + flexDirection = "column"; + + fontSize = 36; + + paddingTop = 100; + + fontWeight = "300" + + paddingBottom = 100; + + textAlign = "center"; + + width = "100vw"; + + #ifdef ANDROID + + display = "flex"; + + #else + + display = "none"; + + #endif + + +} \ No newline at end of file diff --git a/application/demo/leftSide/leftSide.js b/application/demo/leftSide/leftSide.js new file mode 100644 index 0000000..00cc537 --- /dev/null +++ b/application/demo/leftSide/leftSide.js @@ -0,0 +1,179 @@ + + +import button from '/elements/button.js'; + +import newsButton from './leftSide.button.news.js'; + +import settingsButton from './leftSide.button.settings.js'; + +import signinButton from './leftSide.button.signin.js'; + +import signupButton from './leftSide.button.signup.js'; + +import signoutButton from './leftSide.button.signout.js'; + +import fileManagerButton from './leftSide.button.fileManager.js'; + +import animationsButton from './leftSide.button.animations.js'; + +import usersButton from './leftSide.button.users.js'; + +import gridButton from './leftSide.button.grid.js'; + +import menuHeader from './leftSide.header.js'; + + + +export default class leftSide{ + + state = "visible"; + + boxOverflow = "hidden"; + + boxTransition = "0.3S"; + + #ifdef ANDROID + + boxHeight = "100vh"; + + #else + + boxHeight = ""; + + #endif + + boxWidth = 220; + + width = 220; + + flexDirection = "column"; + + //borderRight = "1px solid #3D3D3D" + paddingTop = 30; + + //minHeight = "40vh" + + header = new menuHeader(); + + #ifdef ANDROID + + height = "100vh"; + + paddingTop = ""; + + boxWidth = "100vw"; + + width = "100vw"; + + #ifdef LIGHT + + boxBackground = "#f2f2f2"; + + //background = "white"; + + #endif + + + #endif + + #ifdef WINDOWS + + paddingLeft = 4; + + paddingRight = 4; + + #ifdef DARK + + background = "#202020cc"; + + color = "white" + + borderRight = "1px solid black" + + fontWeight = "500"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + color = "black"; + + + fontWeight = "200"; + + #endif + #endif + + #ifdef MACOS + + paddingTop = 40; + + paddingLeft = 20; + + + #ifdef DARK + + background = "rgb(40 22 22 / 75%)"; + + color = "white" + + borderRight = "1px solid black" + + fontWeight = "bold"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + color = "black"; + + + fontWeight = "200"; + + #endif + + #endif + + render() { + + + + } + + //opacity = "90%"; + + //backdropFilter = "blur(20px)"; + + borderTopLeftRadius = 8; + + borderBottomLeftRadius = 8; + + borderTopLeftRadius = "12px"; + + borderBottomLeftRadius = "12px"; + + + + newsButton = new newsButton(); + + settingsButton = new settingsButton(); + + usersButton = new usersButton(); + + signinButton = new signinButton(); + + signoutButton = new signoutButton(); + + signupButton = new signupButton(); + + animationsButton = new animationsButton(); + + gridButton = new gridButton(); + + fileManagerButton = new fileManagerButton(); + +} \ No newline at end of file diff --git a/application/demo/leftSide/testChild.js b/application/demo/leftSide/testChild.js new file mode 100644 index 0000000..c3e83bb --- /dev/null +++ b/application/demo/leftSide/testChild.js @@ -0,0 +1,21 @@ +export default class testChild{ + + text = "test"; + + width = 160; + + height = 30; + + background = "red"; + + + fontSize = 24; + + constructor( abc ) { + + this.text = abc; + + } + + +} diff --git a/application/demo/list/header/news.list.header.actions.js b/application/demo/list/header/news.list.header.actions.js new file mode 100644 index 0000000..b0f8071 --- /dev/null +++ b/application/demo/list/header/news.list.header.actions.js @@ -0,0 +1,29 @@ + +import groups from '/user/group/user.group.permission.js'; + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + + +export default class newsListHeaderActions extends gridViewColumn { + + text = "Actions"; + + enableDELETE() { + + this.show(); + + } + + disableDELETE() { + + this.hide(); + + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/demo/list/header/news.list.header.body.js b/application/demo/list/header/news.list.header.body.js new file mode 100644 index 0000000..2609601 --- /dev/null +++ b/application/demo/list/header/news.list.header.body.js @@ -0,0 +1,9 @@ + + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + +export default class newsListHeaderBody extends gridViewColumn{ + + text = "Message"; + +} \ No newline at end of file diff --git a/application/demo/list/header/news.list.header.js b/application/demo/list/header/news.list.header.js new file mode 100644 index 0000000..8ba6d5d --- /dev/null +++ b/application/demo/list/header/news.list.header.js @@ -0,0 +1,26 @@ + + +import news from '../../news.js'; + +import body from './news.list.header.body.js'; + +import title from './news.list.header.title.js'; + +import price from './news.list.header.price.js'; + +import actions from './news.list.header.actions.js'; + +import gridViewRow from '/elements/gridView/gridView.header.row.js'; + + +export default class newsListHeader extends news, gridViewRow { + + body = new body(); + + title = new title(); + + price = new price(); + + actions = new actions(); + +} \ No newline at end of file diff --git a/application/demo/list/header/news.list.header.price.js b/application/demo/list/header/news.list.header.price.js new file mode 100644 index 0000000..b2522c4 --- /dev/null +++ b/application/demo/list/header/news.list.header.price.js @@ -0,0 +1,10 @@ + + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + + +export default class newsListHeaderPrice extends gridViewColumn{ + + text = "Price"; + +} \ No newline at end of file diff --git a/application/demo/list/header/news.list.header.title.js b/application/demo/list/header/news.list.header.title.js new file mode 100644 index 0000000..1ca949e --- /dev/null +++ b/application/demo/list/header/news.list.header.title.js @@ -0,0 +1,12 @@ + + +import newsTitle from '../../news.title.js'; + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + + +export default class newsListHeaderTitle extends gridViewColumn{ + + text = "Title"; + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.actions.deleteButton.js b/application/demo/list/item/news.list.item.actions.deleteButton.js new file mode 100644 index 0000000..7b47fcc --- /dev/null +++ b/application/demo/list/item/news.list.item.actions.deleteButton.js @@ -0,0 +1,32 @@ + +import button from "/elements/button.js"; + +import groups from '/user/group/user.group.permission.js'; + +export default class deleteButton extends button { + + text = "Delete"; + + propegateEvent = false; + + + async click() { + + var sure = confirm("Are you sure you want to delete this item"); + + if( sure ) { + + await this.parent.parent.delete(); + + this.parent.parent.remove(); + + } + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.actions.js b/application/demo/list/item/news.list.item.actions.js new file mode 100644 index 0000000..cbe9397 --- /dev/null +++ b/application/demo/list/item/news.list.item.actions.js @@ -0,0 +1,23 @@ + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + +import deleteButton from "./news.list.item.actions.deleteButton.js" + + +export default class newsListItemActions extends gridViewColumn, gridViewColumn{ + + useCustomElement = false; + + padding = 20; + + display = "table-cell"; + + layers = 1; + + paddingLeft = 30; + + borderRadius; + + deleteButton = new deleteButton(); + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.body.js b/application/demo/list/item/news.list.item.body.js new file mode 100644 index 0000000..497f145 --- /dev/null +++ b/application/demo/list/item/news.list.item.body.js @@ -0,0 +1,9 @@ + +import newsBody from '../../news.body.js'; + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + +export default class newsListItemBody extends newsBody, gridViewColumn{ + + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.js b/application/demo/list/item/news.list.item.js new file mode 100644 index 0000000..fa061f2 --- /dev/null +++ b/application/demo/list/item/news.list.item.js @@ -0,0 +1,123 @@ +import news from '../../news.js'; + +import body from './news.list.item.body.js'; + +import title from './news.list.item.title.js'; + +import price from './news.list.item.price.js'; + +import actions from './news.list.item.actions.js'; + +import groups from '/user/group/user.group.permission.js'; + +import gridViewRow from '/elements/gridView/gridView.body.row.js'; + +export default class newsListItem extends news, gridViewRow { + + body = new body(); + + title = new title(); + + price = new price(); + + actions = new actions(); + + cursor = "pointer"; + + background; + + #ifdef MACOS + + fontSize = 14; + + #endif + + hoverBackgroundColor = "#363333" + + #ifdef DARK + + //mouseHoverColor = "#363333"; + + #endif + + #ifdef LIGHT + + //mouseHoverColor = "rgb(255 255 255 / 95%)"; + + #endif + + async click() { + + this.stateMachine.composeState( this.id, this.value ); + + await this.loadPage( this.id ); + + } + + state async loadPage( id ) { + + var rightSide = this.parents("newsPages"); + + var boundBox = this.defaultElement.getBoundingClientRect(); + + var width = boundBox.width; + + + #ifdef ANDROID + + rightSide.newsItemPage.translateX = -width; + + #elif + + rightSide.newsItemPage.transform = "translateX(-600px)"; + + rightSide.newsPage.transform = "translateX(-600px)"; + + + #endif + + var newsPage = rightSide.newsPage; + + newsPage.id = this.id; + + await newsPage.sync(); + + newsPage.createComment.create(); + + //newsPage.updateFrostglass(); + + //newsPage.show(); + + } + + mouseover() { + + //this.background = this.mouseHoverColor; + + } + + mouseleave() { + + //this.background = "none"; + + } + + enableDELETE() { + + this.actions.show(); + + } + + disableDELETE() { + + this.actions.hide(); + + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.price.js b/application/demo/list/item/news.list.item.price.js new file mode 100644 index 0000000..9315c07 --- /dev/null +++ b/application/demo/list/item/news.list.item.price.js @@ -0,0 +1,20 @@ + +import newsPrice from '../../news.price.js'; + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + + +export default class newsListItemPrice extends newsPrice, gridViewColumn{ + + create() { + + const formatter = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'EUR', + }); + + this.text = formatter.format( this.value ); + + } + +} \ No newline at end of file diff --git a/application/demo/list/item/news.list.item.title.js b/application/demo/list/item/news.list.item.title.js new file mode 100644 index 0000000..770a99a --- /dev/null +++ b/application/demo/list/item/news.list.item.title.js @@ -0,0 +1,10 @@ +import newsTitle from '../../news.title.js'; + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + + +export default class newsListItemTitle extends newsTitle, gridViewColumn{ + + + +} \ No newline at end of file diff --git a/application/demo/list/news.list.table.body.js b/application/demo/list/news.list.table.body.js new file mode 100644 index 0000000..56f23af --- /dev/null +++ b/application/demo/list/news.list.table.body.js @@ -0,0 +1,168 @@ + + +import renderCollection from '/unify/renderCollection.js'; + +import groups from '/user/group/user.group.permission.js'; + +import gridViewBody from '/elements/gridView/gridView.body.js'; + +import OR from '/unify/sql/OR.js'; + +import AND from '/unify/sql/AND.js'; + +import LIKE from '/unify/sql/LIKE.js'; + +import GREATER from '/unify/sql/GREATER_OR_EQUAL.js'; + +import SMALLER from '/unify/sql/SMALLER_OR_EQUAL.js'; + + +export default class newsListTableBody extends renderCollection, gridViewBody { + + debug = true; + + sort = "title"; + + page = 0; + + limit = 2; + + async create() { + + //this.update(); + + } + + async update( updatePagination = true ) { + + if( updatePagination ) { + + this.page = 0; + + } + + this.numberOfPages = await this.filterSearch( this.searchType, this.searchTerm, this.sort, this.direction, this.limit, this.page ); + + await this.sync(); + + if( updatePagination ) { + + this.parents("newsItemPage").tableControl.pagination.create(); + + } + + } + + node async filterSearch( searchType, searchTerm, order, direction, limit, page ) { + + console.log("searchType", searchType); + + console.log("search input", searchTerm); + + console.log("search order", order); + + console.log("direction", direction); + + console.log("limit", limit); + + console.log("from", page * limit); + + + + var filter = this.getFilter(); + + switch( searchType ) { + + case 0: + + filter.search = OR( OR( LIKE( filter.title, searchTerm ), LIKE( filter.comments.body, searchTerm ) ), LIKE( filter.body, searchTerm ) ); + + + break; + + case 1: + + filter.search = GREATER( filter.price, searchTerm ); + + break; + + case 2: + + filter.search = SMALLER( filter.price, searchTerm ); + + break; + + } + + if( !searchTerm ) { + + filter.search = false; + + } + + switch( order ) { + + case "title": + + filter.order = filter.title; + + break; + + case "body": + + filter.order = filter.body; + + break; + + case "price": + + filter.order = filter.price; + + break; + + } + + if( direction == "desc" ) { + + filter.direction = "desc"; + + } else { + + filter.direction = "asc"; + + } + + filter.limit = 1000; + + filter.from = 0; + + // See how many searched rows there are in total + this.get(); + + filter.limit = parseInt( limit ); + + filter.from = parseInt( page * limit ); + + var numberOfPages = Math.ceil( this.rows.length / limit ); + + console.log("numberOfPages", numberOfPages); + + console.log("this.rows.length", this.rows.length); + + console.log("limit", limit); + + return numberOfPages; + + } + + permission() { + + this.allow( groups.visitor, "READ" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + } + +} \ No newline at end of file diff --git a/application/demo/list/news.list.table.header.js b/application/demo/list/news.list.table.header.js new file mode 100644 index 0000000..a58e9fd --- /dev/null +++ b/application/demo/list/news.list.table.header.js @@ -0,0 +1,13 @@ + +import newsListHeaderRow from "./header/news.list.header.js"; + +import document from '/unify/document.js'; + +import gridViewHeader from '/elements/gridView/gridView.header.js'; + + +export default class newsListTableHeader extends gridViewHeader { + + newsListHeaderRow = new newsListHeaderRow(); + +} \ No newline at end of file diff --git a/application/demo/list/news.list.table.js b/application/demo/list/news.list.table.js new file mode 100644 index 0000000..fe7bcd8 --- /dev/null +++ b/application/demo/list/news.list.table.js @@ -0,0 +1,34 @@ + + +import newsListTableHeader from "./news.list.table.header.js"; + +import newsListTableBody from "./news.list.table.body.js"; + + +import collection from '/unify/collection.js'; + +import newsListItem from '../list/item/news.list.item.js'; + +import news from '../news.js'; + +import gridView from '/elements/gridView/gridView.js'; + + + +export default class newsListTable extends gridView{ + + header = new newsListTableHeader(); + + body = new newsListTableBody( newsListItem, new collection( news ) ); + + #ifdef MACOS + + marginLeft = 6; + + width = "auto" + + margin = "6px -2px 10px 6px" + + #endif + +} \ No newline at end of file diff --git a/application/demo/minimizeButton.js b/application/demo/minimizeButton.js new file mode 100644 index 0000000..e50723e --- /dev/null +++ b/application/demo/minimizeButton.js @@ -0,0 +1,122 @@ + +import icon from '/elements/icon.js'; + +export default class minimizeButton { + + //showFps = true; + + text = "<" + + color = "white" + + fontWeight = "bold" + + cursor = "pointer" + + + + propegateEvent = false + + zIndex = 5000 + + transition = "1s easeInOutQuart"; + + margin = 10; + + + + position = "absolute"; + + #ifdef ANDROID + + top = "4px" + + #else + + bottom = "4px" + + #endif + + left = "0" + + zIndex = "100000" + + transform = "rotate(0)" ; + + open() { + + var menu = this.parent.leftSide; + + //this.setImage("chevron-right.svg") + + this.transform = "scale(1, 1)"; + + #ifdef ANDROID + + menu.boxHeight = "100vh"; + + #else + + menu.boxWidth = 220; + + #endif + + menu.state = "visible"; + + this.parent.rightSide.borderRadius = ""; + + } + + close() { + + var menu = this.parent.leftSide; + + //this.setImage("chevron-left.svg") + + this.transform = "scale(-1, 1)"; + + #ifdef ANDROID + + menu.boxHeight = "0"; + + #else + + menu.boxWidth = "0"; + + #endif + + menu.state = "hidden"; + + var that = this; + + setTimeout(function(){ + + console.log("asd"); + + that.parent.rightSide.borderRadius = 12; + + + }, 1000) + + } + + click() { + + var menu = this.parent.leftSide; + + var state = menu.state; + + if( state == "visible" ) { + + this.close(); + + } else { + + + this.open(); + + } + + } + +} diff --git a/application/demo/news.body.js b/application/demo/news.body.js new file mode 100644 index 0000000..8b30828 --- /dev/null +++ b/application/demo/news.body.js @@ -0,0 +1,7 @@ + +import column from '/unify/column.js'; + +export default class body extends column{ + + +} \ No newline at end of file diff --git a/application/demo/news.js b/application/demo/news.js new file mode 100644 index 0000000..740c429 --- /dev/null +++ b/application/demo/news.js @@ -0,0 +1,29 @@ + +import table from '/unify/table.js'; + +import title from './news.title.js'; + +import body from './news.body.js'; + +import price from './news.price.js'; + +import user from '/user/user.js'; + +import comment from './comment/comment.js'; + +import collection from '/unify/collection.js'; + + + + +export default class news extends table { + + title = new title(); + + body = new body(); + + price = new price(); + + comments = new collection( comment ); + +} \ No newline at end of file diff --git a/application/demo/news.price.js b/application/demo/news.price.js new file mode 100644 index 0000000..ab704e3 --- /dev/null +++ b/application/demo/news.price.js @@ -0,0 +1,11 @@ + +import column from '/unify/column.js'; + +import datatype from '/unify/datatype.js'; + + +export default class price extends column{ + + datatype = datatype.REAL; + +} \ No newline at end of file diff --git a/application/demo/news.title.js b/application/demo/news.title.js new file mode 100644 index 0000000..a00d657 --- /dev/null +++ b/application/demo/news.title.js @@ -0,0 +1,9 @@ + + +import column from '/unify/column.js'; + +export default class title extends column { + + + +} \ No newline at end of file diff --git a/application/demo/page/news.page.backButton.js b/application/demo/page/news.page.backButton.js new file mode 100644 index 0000000..64f61e2 --- /dev/null +++ b/application/demo/page/news.page.backButton.js @@ -0,0 +1,77 @@ + +import icon from "/elements/icon.js"; + +export default class backButton{ + + text = "<" + + color = "white" + + fontWeight = "bold" + + cursor = "pointer"; + + propegateEvent = false + + transition = "2s"; + + margin = 10; + + marginLeft = 20; + + fontFamily = "unset" + + + + #ifdef WINDOWS + + #ifdef DARK + + #endif + + #ifdef LIGHT + + + #endif + + #endif + + #ifdef MACOS + + #ifdef DARK + + boxBackground = "#282828"; + + #endif + + #ifdef LIGHT + + boxBackground = "#ffffff"; + + #endif + + #endif + + + + click() { + + this.stateMachine.composeState( "Home" ); + + this.openNewsItems(); + + } + + state openNewsItems() { + + var rightSide = this.parents("newsPages"); + + //rightSide.newsItemPage.marginLeft = "0"; + + rightSide.newsItemPage.transform = "translateX(0)"; + + rightSide.newsPage.transform = "translateX(0)"; + + } + +} \ No newline at end of file diff --git a/application/demo/page/news.page.body.js b/application/demo/page/news.page.body.js new file mode 100644 index 0000000..b466bf6 --- /dev/null +++ b/application/demo/page/news.page.body.js @@ -0,0 +1,57 @@ + +import newsBody from '../news.body.js'; + +import textarea from '/elements/textarea.js'; + +import flexbox from '/elements/flexbox.js'; + +export default class newsPageBody extends flexbox, newsBody{ + + padding = 20; + + width = "-webkit-fill-available" + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#ffffff"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + + #endif + + #ifdef LIGHT + + + #endif + + #endif + + #ifdef ANDROID + + borderRadius = "0 0 18px 18px" + + + #ifdef LIGHT + + background = "white"; + + #endif + + #endif + +} \ No newline at end of file diff --git a/application/demo/page/news.page.edit.button.js b/application/demo/page/news.page.edit.button.js new file mode 100644 index 0000000..b3e4ace --- /dev/null +++ b/application/demo/page/news.page.edit.button.js @@ -0,0 +1,49 @@ + +import button from "/elements/button.js"; + +export default class backButton extends button{ + + text = "Edit News" + + color = "white" + + fontWeight = "bold" + + cursor = "pointer"; + + float = "right" + + propegateEvent = false + + transition = "2s"; + + margin = 10; + + marginLeft = 20; + + fontFamily = "unset" + + + + click() { + + this.stateMachine.composeState( "Edit" ); + + var rightSide = this.parents("newsPages"); + + //this.parent.hide(); + + var newsEdit = rightSide.newsEdit; + + newsEdit.id = this.parent.id; + + newsEdit.sync(); + + newsEdit.show(); + + //rightSide.newsPage.transform = "translateX(-1200px)"; + + } + + +} \ No newline at end of file diff --git a/application/demo/page/news.page.js b/application/demo/page/news.page.js new file mode 100644 index 0000000..a3977d1 --- /dev/null +++ b/application/demo/page/news.page.js @@ -0,0 +1,254 @@ + +import news from '../news.js'; + +import newsPageTitle from './news.page.title.js'; + +import newsPageBody from './news.page.body.js'; + +import groups from '/user/group/user.group.permission.js'; + +import commentsMessages from '../comment/comments.messages.js'; + +import editComment from '../comment/edit/comment.edit.js'; + +import createComment from '../comment/create/comment.create.js'; + +import saveButton from './news.page.save.js'; + +import backButton from "./news.page.backButton.js" + +import editButton from "./news.page.edit.button.js" + +import filler from "/elements/filler.js"; + +import searchComments from "./search.comments.js"; + +import tools from "/unify/tools.js"; + + + + +class testDiv{ + + pageTitle = new newsPageTitle(); + +} + +class testSuffixes{ + + layers = 1; + + useCustomElement = true; + + customElement = document.createElement("a") + + text = "visit Unify"; + + + + visitedColor = "green"; + + linkColor = "#009688" + + activeColor = "red" + + + create() { + + this.element.setAttribute("href", "https://unifyjs.org") + + } + +} + + +export default class newsPage extends news{ + + willChange = "transform"; + + transform; + + minHeight = "100%"; + + transition = "1s" + + + scrollbarWidth = "6px"; + + scrollbarTrackBackground = "#1c1d1e"; + + scrollbarThumbBackground = "#404040" + + scrollbarThumbBorderRadius = "4px" + + scrollbarThumbHoverBackground = "grey"; + + + #ifdef MACOS + + #ifdef LIGHT + + background = "white"; + + #endif + + + #ifdef DARK + + background = "#282828"; + + #endif + + #endif + + + #ifdef WINDOWS + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + #endif + + + #ifdef DARK + + background = "#202020cc"; + + #endif + + #endif + + + #ifdef ANDROID + + height = "100vh"; + + paddingTop = ""; + + boxWidth = "100vw"; + + width = "100vw"; + + #ifdef LIGHT + + background = "#f2f2f2"; + + #endif + + + #endif + + + flexDirection = "column" + + _backButton = new backButton(); + + _testDiv = new testDiv(); + + body = new newsPageBody(); + + + editButton = new editButton(); + //testSuffixes = new testSuffixes(); + + debug = true; + + width = 600; + + sizing = "border-box"; + + layers = 1; + + height = "70vh" + + overflowY = "auto" + + + searchComments = new searchComments(); + + commentsMessages = new commentsMessages( editComment, this.comments ); + + createComment = new createComment( this.comments ); + + filler = new filler(); + + async afterLoad() { + + var pathName = window.location.pathname; + + var pathParts = pathName.split("/"); + + var id = parseFloat( pathParts[1] ); + + + if( id ) { + + this.stateMachine.composeState(); + + this.showParents(); + + this.show(); + + await this.loadPage( id ) + + } + + } + + state async loadPage( id ) { + + var rightSide = this.parents("newsPages"); + + var boundBox = this.defaultElement.getBoundingClientRect(); + + var width = boundBox.width; + + + #ifdef ANDROID + + rightSide.newsItemPage.translateX = -width; + + #elif + + rightSide.newsItemPage.transform = "translateX(-600px)"; + + rightSide.newsPage.transform = "translateX(-600px)"; + + + #endif + + this.id = id; + + await this.sync(); + + this.createComment.create(); + + } + + async create() { + + await this.commentsMessages.sync(); + + } + + permission() { + + this.allow( groups.member, "WRITE" ); + + this.allow( groups.admin, "WRITE" ); + + this.allow( groups.visitor, "WRITE" ); + + + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + this.allow( groups.visitor, "READ" ); + + } + + +} \ No newline at end of file diff --git a/application/demo/page/news.page.price.js b/application/demo/page/news.page.price.js new file mode 100644 index 0000000..e6d17b0 --- /dev/null +++ b/application/demo/page/news.page.price.js @@ -0,0 +1,17 @@ + + +import newsPrice from '../news.price.js'; + +import flexbox from '/elements/flexbox.js'; + +export default class newsPagePrice extends newsPrice, flexbox{ + + useCustomElement = false; + + fontWeight = "bold"; + + fontSize = 30; + + padding = 20; + +} \ No newline at end of file diff --git a/application/demo/page/news.page.save.js b/application/demo/page/news.page.save.js new file mode 100644 index 0000000..f9f1370 --- /dev/null +++ b/application/demo/page/news.page.save.js @@ -0,0 +1,16 @@ + + +import button from '/elements/button.js'; + +export default class saveButton extends button { + + label = "Save"; + + async click( event, object ){ + + var result = await this.parent.save(); + + + } + +} \ No newline at end of file diff --git a/application/demo/page/news.page.title.js b/application/demo/page/news.page.title.js new file mode 100644 index 0000000..83e262f --- /dev/null +++ b/application/demo/page/news.page.title.js @@ -0,0 +1,70 @@ + + +import newsTitle from '../news.title.js'; + +import flexbox from '/elements/flexbox.js'; + +export default class newsPageTitle extends newsTitle, flexbox{ + + useCustomElement = false; + + fontWeight = "bold"; + + //padding = 20; + + //width = "600px" + + //boxSizing = "border-box"; + + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#ffffff"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + //background = "#202020cc"; + + #endif + + #ifdef LIGHT + + //background = "rgb(255 255 255 / 75%)"; + + #endif + + #endif + + #ifdef ANDROID + + borderRadius = "18px 18px 0 0" + + width = "100%" + + #ifdef LIGHT + + background = "white"; + + #endif + + #endif + + fontSize = 30; + + padding = 20; + +} \ No newline at end of file diff --git a/application/demo/page/search.comments.js b/application/demo/page/search.comments.js new file mode 100644 index 0000000..5402269 --- /dev/null +++ b/application/demo/page/search.comments.js @@ -0,0 +1,28 @@ + +import input from "/elements/input.js"; + + + + +export default class searchBar extends input { + + placeholder = "Search." + + + async keyup( event ) { + + this.value = this.customElement.value; + + var value = this.value; + + console.log("search input", value); + + var newsItems = this.parent.commentsMessages; + + await newsItems.search( value ); + + await newsItems.sync(); + + } + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/panel.js b/application/demo/pages/appearance/panel.js new file mode 100644 index 0000000..4d1f3fd --- /dev/null +++ b/application/demo/pages/appearance/panel.js @@ -0,0 +1,17 @@ + +import os from "./rows/os.js"; + +import tint from "./rows/tint.js"; + +import panel from '/elements/panel.js'; + + +export default class appearancePanel extends panel{ + + flexDirection = "column"; + + os = new os(); + + tint = new tint(); + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/os.js b/application/demo/pages/appearance/rows/os.js new file mode 100644 index 0000000..2e13e88 --- /dev/null +++ b/application/demo/pages/appearance/rows/os.js @@ -0,0 +1,37 @@ + +import panelRow from '/elements/panel/row.js'; + +import spinner from '/elements/preloaders/simpleSpinner.js'; + +import osSelectorList from "./os.selector.list.js"; + +import osLabel from "./os.label.js"; + + +export default class os extends panelRow{ + + flexDirection = "row"; + + label = new osLabel("Os"); + + osSelector = new osSelectorList(); + + spinner = new spinner(); + + create() { + + this.osSelector.hide(); + + } + + afterThemeLoad() { + + this.spinner.hide() + + this.osSelector.show(); + + } + + +} + diff --git a/application/demo/pages/appearance/rows/os.label.js b/application/demo/pages/appearance/rows/os.label.js new file mode 100644 index 0000000..2433630 --- /dev/null +++ b/application/demo/pages/appearance/rows/os.label.js @@ -0,0 +1,8 @@ + +import label from '/elements/label.js'; + +export default class osLabel extends label{ + + flex = "1"; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/os.selector.js b/application/demo/pages/appearance/rows/os.selector.js new file mode 100644 index 0000000..8b79ac7 --- /dev/null +++ b/application/demo/pages/appearance/rows/os.selector.js @@ -0,0 +1,26 @@ + + +import themeSelector from "../themeSelector.js"; + +import tools from '/unify/tools.js'; + +export default class themeOSSelectorItem extends themeSelector{ + + click() { + + var osName = tools.CamelCase( this.selectLabel.text ); + + this.getRoot().os = osName; + + + this.parent.updateImages( this.getRoot().tint ); + + this.parents("appearancePanel").tint.themeTintSelectors.updateImages( osName ) + + this.highlight(); + + } + + propegateEvent = false; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/os.selector.list.js b/application/demo/pages/appearance/rows/os.selector.list.js new file mode 100644 index 0000000..1c3a57e --- /dev/null +++ b/application/demo/pages/appearance/rows/os.selector.list.js @@ -0,0 +1,44 @@ + +import themeOSSelector from './os.selector.js' + +import tools from '/unify/tools.js'; + + +export default class osSelectorList{ + + themeWindows = new themeOSSelector("Windows"); + + themeMacOS = new themeOSSelector("macOS"); + + //themeAndroid = new themeOSSelector("Android"); + + updateImages( tint ) { + + var camelCaseTint = tools.CamelCase( tint ); + + this.themeWindows.setImage("/assets/images/themeSelectors/windows" + camelCaseTint + ".png"); + + this.themeMacOS.setImage("/assets/images/themeSelectors/macos" + camelCaseTint + ".png"); + + //this.themeAndroid.setImage("/assets/images/themeSelectors/macos" + camelCaseTint + ".png"); + + } + + create() { + + this.themeWindows.highlight(); + + this.themeWindows.setImage('/assets/images/themeSelectors/windowsLight.png'); + + this.themeMacOS.setImage('/assets/images/themeSelectors/macosLight.png'); + + //this.themeAndroid.setImage('/assets/images/themeSelectors/macosLight.png'); + } + + layers = 1; + + margin = 4; + + marginLeft = "auto"; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/tint.js b/application/demo/pages/appearance/rows/tint.js new file mode 100644 index 0000000..7ab7bcd --- /dev/null +++ b/application/demo/pages/appearance/rows/tint.js @@ -0,0 +1,38 @@ + +import panelRow from '/elements/panel/row.js'; + +import select from '/elements/selectRenderCollection.js'; + +import spinner from '/elements/preloaders/simpleSpinner.js'; + +import themeTintSelectors from "./tint.selector.list.js"; + +import customLabel from "./tint.label.js"; + + + +export default class tint extends panelRow{ + + flexDirection = "row"; + + label = new customLabel("Appearance"); + + themeTintSelectors = new themeTintSelectors(); + + spinner = new spinner(); + + create() { + + this.themeTintSelectors.hide() + + } + + afterThemeLoad() { + + this.spinner.hide() + + this.themeTintSelectors.show(); + + } + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/tint.label.js b/application/demo/pages/appearance/rows/tint.label.js new file mode 100644 index 0000000..3bb2973 --- /dev/null +++ b/application/demo/pages/appearance/rows/tint.label.js @@ -0,0 +1,10 @@ + + +import label from '/elements/label.js'; + + +export default class customLabel extends label{ + + flex = "1"; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/tint.selector.js b/application/demo/pages/appearance/rows/tint.selector.js new file mode 100644 index 0000000..a24d8f5 --- /dev/null +++ b/application/demo/pages/appearance/rows/tint.selector.js @@ -0,0 +1,24 @@ + +import themeSelector from "../themeSelector.js"; + +import tools from '/unify/tools.js'; + + +export default class themeTintSelector extends themeSelector{ + + click() { + + var tintName = tools.CamelCase( this.selectLabel.text ); + + this.parents("appearancePanel").os.osSelector.updateImages( tintName ) + + this.highlight(); + + + this.getRoot().tint = tintName; + + } + + propegateEvent = false; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/rows/tint.selector.list.js b/application/demo/pages/appearance/rows/tint.selector.list.js new file mode 100644 index 0000000..cc68164 --- /dev/null +++ b/application/demo/pages/appearance/rows/tint.selector.list.js @@ -0,0 +1,46 @@ + +import themeTintSelector from "./tint.selector.js" + +import tools from '/unify/tools.js'; + + +export default class themeTintSelectors{ + + + themeLight = new themeTintSelector("Light"); + + themeDark = new themeTintSelector("Dark"); + + + updateImages( os ) { + + os = os.toLowerCase(); + + var tint = tools.CamelCase( this.getRoot().tint ); + + + this.themeDark.setImage("/assets/images/themeSelectors/" + os + "Dark.png"); + + this.themeLight.setImage("/assets/images/themeSelectors/" + os + "Light.png"); + + this["theme"+tint].highlight(); + + } + + create() { + + this.themeDark.highlight(); + + this.themeDark.setImage('/assets/images/themeSelectors/windowsDark.png'); + + this.themeLight.setImage('/assets/images/themeSelectors/windowsLight.png'); + + } + + layers = 1; + + margin = 4; + + marginLeft = "auto"; + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/themeSelector.image.js b/application/demo/pages/appearance/themeSelector.image.js new file mode 100644 index 0000000..f702b9c --- /dev/null +++ b/application/demo/pages/appearance/themeSelector.image.js @@ -0,0 +1,41 @@ + + +export default class themaSelectorImage{ + + cursor = "pointer"; + + backgroundSize = "cover"; + + borderRadius = 12; + + layers = 1; + + width = 80; + + height = 80; + + margin = 20; + + marginBottom = 4; + + transition = "1s" + + + border; + + backgroundImage; + + + lowLight() { + + this.border = "none"; + + } + + highlight() { + + this.border = "2px solid blue"; + + } + +} \ No newline at end of file diff --git a/application/demo/pages/appearance/themeSelector.js b/application/demo/pages/appearance/themeSelector.js new file mode 100644 index 0000000..b7f1ea1 --- /dev/null +++ b/application/demo/pages/appearance/themeSelector.js @@ -0,0 +1,45 @@ + + +import themeSelectorImage from "./themeSelector.image.js"; + +import themeSelectorLabel from "./themeSelector.label.js"; + + +export default class themeSelector{ + + flexDirection = "column"; + + marginBottom = 20; + + constructor( name ) { + + this.selectLabel.text = name; + + } + + highlight() { + + var children = this.parent.getChildren(); + + for (var i = 0; i < children.length; i++) { + + children[i].selectImage.lowLight(); + + } + + this.selectImage.highlight(); + + } + + setImage( image ) { + + this.selectImage.backgroundImage = "url("+image+")"; + + } + + + selectImage = new themeSelectorImage(); + + selectLabel = new themeSelectorLabel(); + +} diff --git a/application/demo/pages/appearance/themeSelector.label.js b/application/demo/pages/appearance/themeSelector.label.js new file mode 100644 index 0000000..a931008 --- /dev/null +++ b/application/demo/pages/appearance/themeSelector.label.js @@ -0,0 +1,24 @@ + + +export default class selectLabel{ + + fontSize = 12; + + fontWeight = "bold"; + + margin = "0 auto" + + +#ifdef DARK + + color = "white" + +#endif + +#ifdef LIGHT + + color = "black"; + +#endif + +} \ No newline at end of file diff --git a/application/demo/pages/newsDialogButton.js b/application/demo/pages/newsDialogButton.js new file mode 100644 index 0000000..569dc27 --- /dev/null +++ b/application/demo/pages/newsDialogButton.js @@ -0,0 +1,42 @@ + +import button from '/elements/button.js'; + +import groups from '/user/group/user.group.permission.js'; + + +export default class newsDialogButton extends button{ + + text = "Create News" + + marginTop = 10; + + marginLeft = 2; + + + async click() { + + this.parent.createNews.show(); + + this.parent.createNews.center(); + + } + + enableREAD() { + + this.show(); + + } + + disableREAD() { + + this.hide(); + + } + + permission() { + + this.allow( groups.admin, "READ" ); + + } + +} diff --git a/application/demo/pages/newsItemPage.js b/application/demo/pages/newsItemPage.js new file mode 100644 index 0000000..1a44ca1 --- /dev/null +++ b/application/demo/pages/newsItemPage.js @@ -0,0 +1,134 @@ + + + +import newsListTable from '../list/news.list.table.js'; + +import createNews from '../edit/news.edit.js'; + +import header from '/elements/header.js'; + +import button from '/elements/button.js'; + +import toggle from '/elements/toggle.js'; + +import newsDialogButton from './newsDialogButton.js'; + +import searchWidget from './search.widget.js'; + +import tableControl from './newsItemPage.tableControl.js'; + +import testbutton from "./testButton.js"; + +export default class newsItemPage{ + + layers = 1; + + overflowY = "auto"; + + width = "-webkit-fill-available"; + + flexDirection = "column"; + + transition = "1s" + + willChange = "transform"; + + overflowX = "none" + + transform; + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#ffffff"; + + #endif + + #endif + + + #ifdef WINDOWS + + #ifdef DARK + + background = "#202020cc"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + #endif + + #endif + + + + marginLeft = "0" + + sizing = "border-box"; + + + #ifdef ANDROID + + width = "100vw"; + + padding = "0"; + + #else + + width = 600; + + padding = 20; + + #endif + + + + newsListHeader = new header("News Items"); + + searchWidget = new searchWidget(); + + newsListTable = new newsListTable(); + + tableControl = new tableControl(); + + createNews = new createNews(); + + testbutton = new testbutton(); + + newsDialogButton = new newsDialogButton(); + + + + + #ifdef ANDROID + + height = "100vh"; + + paddingTop = ""; + + boxWidth = "100vw"; + + width = "100vw"; + + #ifdef LIGHT + + background = "#f2f2f2"; + + #endif + + + #endif + + +} + diff --git a/application/demo/pages/newsItemPage.limit.js b/application/demo/pages/newsItemPage.limit.js new file mode 100644 index 0000000..a217542 --- /dev/null +++ b/application/demo/pages/newsItemPage.limit.js @@ -0,0 +1,50 @@ + +import select from "/elements/select.js"; + +export default class limit extends select{ + + + height = 40; + + marginTop = -1; + + width = 60; + + change() { + + var index = this.element.selectedIndex; + + var renderCollection = this.parents("newsItemPage").newsListTable.body; + + renderCollection.limit = index; + + renderCollection.update( true ); + + console.log("index", index); + + } + + create() { + + var renderCollection = this.parents("newsItemPage").newsListTable.body; + + var limit = renderCollection.limit; + + // ( value, label, selected ) + for (var i = 0; i < 10; i++) { + + if( limit == i ) { + + this.addOption( i, i, true ); + + } else { + + this.addOption( i, i ); + + } + + } + + } + +} \ No newline at end of file diff --git a/application/demo/pages/newsItemPage.pagination.item.js b/application/demo/pages/newsItemPage.pagination.item.js new file mode 100644 index 0000000..efd76e4 --- /dev/null +++ b/application/demo/pages/newsItemPage.pagination.item.js @@ -0,0 +1,172 @@ + + +export default class paginationItem{ + + padding = 10 + + layers = 1; + + background = "#2d2d2d"; + + cursor = "pointer" + + border = "1px solid rgb(46, 46, 46)" + + borderRadius = "none" + + disabled = false; + + select() { + + this.background = "#434743" + + this.selected = true; + + } + + deselect() { + + this.background = "#2d2d2d" + + this.selected = false; + + } + + getSelected() { + + var children = this.parent.getChildren(); + + for (var i = 0; i < children.length; i++) { + + var child = children[i]; + + if( child.selected ) { + + return child; + + } + + } + + } + + deselectItems() { + + var children = this.parent.getChildren(); + + for (var i = 0; i < children.length; i++) { + + var child = children[i]; + + //child.value = i; + + if( child.deselect ) { + + child.deselect(); + + } + + } + + } + + click() { + + if( this.disabled ) { + + return true; + + } + + var children = this.parent.getChildren(); + + var renderCollection = this.parents("newsItemPage").newsListTable.body; + + var numberOfPages = renderCollection.numberOfPages; + + console.log("this.value", this.value); + + console.log("numberOfPages", numberOfPages); + + switch( this.value ) { + + case "<": + + var selectedChildItem = this.getSelected(); + + var previousSibling = selectedChildItem.getPreviousSibling(); + + previousSibling.click(); + + break; + + case ">": + + var selectedChildItem = this.getSelected(); + + var nextSibling = selectedChildItem.getNextSibling(); + + nextSibling.click(); + + break; + + default: + + if( this.value >= numberOfPages - 1 ) { + + children.pop().disable() + + } else { + + children.pop().enable(); + + } + + if( this.value == 0 ) { + + children[0].disable() + + } else { + + children[0].enable(); + + } + + + renderCollection.page = this.value; + + renderCollection.update( false ); + + this.deselectItems(); + + this.select(); + + + + } + + } + + disable() { + + this.opacity = "30%" + + this.cursor = "default" + + this.disabled = true; + + } + + enable() { + + this.opacity = "100%" + + this.cursor = "pointer" + + this.disabled = false; + + } + + opacity; + +} \ No newline at end of file diff --git a/application/demo/pages/newsItemPage.pagination.js b/application/demo/pages/newsItemPage.pagination.js new file mode 100644 index 0000000..8ddb235 --- /dev/null +++ b/application/demo/pages/newsItemPage.pagination.js @@ -0,0 +1,68 @@ + +import item from "./newsItemPage.pagination.item.js"; + + +export default class pagination{ + + height = 40; + + create() { + + this.clearChildren(); + + this.update(); + + } + + update() { + + var renderCollection = this.parents("newsItemPage").newsListTable.body; + + var numberOfPages = renderCollection.numberOfPages; + + + + var newItem = new item(); + + newItem.text = "<"; + + newItem.value = "<" + + newItem.borderRadius = "4px 0 0 4px" + + this.add( newItem ); + + + for (var i = 0; i < numberOfPages; i++) { + + var newItem = new item(); + + newItem.value = i; + + newItem.text = (i + 1).toString(); + + this.add( newItem ); + + + if( i == 0 ) { + + newItem.click(); + + } + + } + + var newItem = new item(); + + newItem.text = ">"; + + newItem.value = ">" + + newItem.borderRadius = "0 4px 4px 0" + + this.add( newItem ); + + + } + +} \ No newline at end of file diff --git a/application/demo/pages/newsItemPage.tableControl.js b/application/demo/pages/newsItemPage.tableControl.js new file mode 100644 index 0000000..81a7aac --- /dev/null +++ b/application/demo/pages/newsItemPage.tableControl.js @@ -0,0 +1,20 @@ + +import pagination from './newsItemPage.pagination.js'; + +import limit from './newsItemPage.limit.js'; + +import label from '/elements/label.js'; + +export default class tableControl{ + + pageLabel = new label("Select page:"); + + pagination = new pagination(); + + limitLabel = new label("Select items per page:"); + + limit = new limit(); + + + +} \ No newline at end of file diff --git a/application/demo/pages/newsPages.js b/application/demo/pages/newsPages.js new file mode 100644 index 0000000..ce72e95 --- /dev/null +++ b/application/demo/pages/newsPages.js @@ -0,0 +1,20 @@ + +import newsItemPage from "./newsItemPage.js"; + +import newsPage from "../page/news.page.js"; + +import newsEdit from "../edit/news.edit.js"; + +export default class newsPages{ + + sizing = "border-box"; + + newsItemPage = new newsItemPage(); + + newsPage = new newsPage(); + + newsEdit = new newsEdit(); + + width = 1800; + +} \ No newline at end of file diff --git a/application/demo/pages/search.input.js b/application/demo/pages/search.input.js new file mode 100644 index 0000000..1046cee --- /dev/null +++ b/application/demo/pages/search.input.js @@ -0,0 +1,47 @@ + +import input from "/elements/input.js"; + + + + +export default class searchBar extends input { + + placeholder = "Search." + + placeholderColor = "#8e8e8e" + + webkitTextFillColor = "none"; + + async keyup( event ) { + + this.search(); + + //newsItems.value = value; + + //newsItems.sync(); + + } + + async search() { + + var searchType = this.parent.select.customElement.selectedIndex; + + var searchTerm = this.customElement.value; + + + console.log("searchType", searchType); + + console.log("search input", searchTerm); + + + var newsItems = this.parent.parent.newsListTable.body; + + newsItems.searchType = searchType; + + newsItems.searchTerm = searchTerm; + + newsItems.update(); + + } + +} \ No newline at end of file diff --git a/application/demo/pages/search.select.js b/application/demo/pages/search.select.js new file mode 100644 index 0000000..6193307 --- /dev/null +++ b/application/demo/pages/search.select.js @@ -0,0 +1,19 @@ + + +import select from '/elements/select.js'; + +export default class customSelect extends select{ + + width = 100; + + change() { + + //var index = this.customElement.selectedIndex; + + this.parent.search.search(); + + //this.parents("newsItemPage").newsListTable.body.searchType = index; + + } + +} \ No newline at end of file diff --git a/application/demo/pages/search.widget.js b/application/demo/pages/search.widget.js new file mode 100644 index 0000000..2ecb542 --- /dev/null +++ b/application/demo/pages/search.widget.js @@ -0,0 +1,25 @@ + + +import search from './search.input.js'; + +import select from './search.select.js'; + + + + +export default class searchWidget{ + + search = new search(); + + select = new select() + + create() { + + // ( value, label, selected ) + this.select.addOption( 1, "Name" ); + this.select.addOption( 2, "Price >" ); + this.select.addOption( 3, "Price <" ); + + } + +} \ No newline at end of file diff --git a/application/demo/pages/settings.js b/application/demo/pages/settings.js new file mode 100644 index 0000000..3c484d9 --- /dev/null +++ b/application/demo/pages/settings.js @@ -0,0 +1,66 @@ + +import header from '/elements/header.js'; + +import appearancePanel from "./appearance/panel.js"; + + +import document from '/unify/document.js'; + + + + + + +export default class settings{ + + sizing = "border-box"; + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#fdfdfd"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + background = "#202020cc"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + #endif + + #endif + + layers = 1; + + height = "-webkit-fill-available"; + + padding = 20; + + width = "100%" + + flexDirection = "column"; + + settingsHeader = new header("Appearance"); + + appearancePanel = new appearancePanel(); + + //spinner = new spinner(); + +} \ No newline at end of file diff --git a/application/demo/pages/testButton.js b/application/demo/pages/testButton.js new file mode 100644 index 0000000..0e0c735 --- /dev/null +++ b/application/demo/pages/testButton.js @@ -0,0 +1,103 @@ +import user from "/user/user.js" + +import collection from "/unify/collection.js" + +import button from '/elements/button.js'; + +import OR from '/unify/sql/OR.js'; + +import AND from '/unify/sql/AND.js'; + +import LIKE from '/unify/sql/LIKE.js'; + + +export default class testbutton extends button{ + + text = "test" + + async click() { + + var a = new Array(); + + var b = new Object(); + + b.a = "this is a test" + + b.b = "this works good." + + a.push( b ); + + a.push( b ); + + a.push( b ); + + await this.test( a ); + + } + + node async test() { + + var users = new collection( user ); + + var filter = users.getFilter(); + + console.log("filter", filter); + + // Compose Filter + + //filter.search = AND( LIKE( filter.email, "josephDaniel@mail.com" ), LIKE( filter.username, "admin" ) ); + + filter.search = LIKE( filter.selectedUsers.email, "JosephDaniel@mail.com" ); + + filter.order = filter.groups; + + + users.sync(); + + + + var rows = users.rows; + + console.log( rows.length, rows ); + + // get first user + var a = users.get( 0 ); + + console.log("users.get( 0 )", a.username.value); + + console.log( "users.length()", users.length() ); + + // get and remove last item + var b = users.pop(); + + console.log( "users.length()", users.length() ); + + console.log("users.pop()", b.username.value); + + + + // get and remove first item + var c = users.shift(); + + console.log( "users.length()", users.length() ); + + console.log("users.shift()", c.username.value ); + + + users.sync(); + + // get all rows + var d = users.getRows(); + + console.log("users.getRows()",d.length); + + + } + + //node async test( a ) { + + // console.log( a ); + + //} + +} \ No newline at end of file diff --git a/application/demo/rightSide/rightSide.js b/application/demo/rightSide/rightSide.js new file mode 100644 index 0000000..802e43c --- /dev/null +++ b/application/demo/rightSide/rightSide.js @@ -0,0 +1,117 @@ + +import newsPages from '../pages/newsPages.js'; + +import settings from '../pages/settings.js'; + +import fileManager from '../fileManager/fileManager.js'; + +import animations from '../animations/animations.js'; + +import gridExample from '../examples/grids.js'; + +import userListPage from '/user/userList/user.userList.page.js'; + +import editUser from '/user/edit/edit.user.js'; + + + +import signup from '/user/signup/user.signup.js'; + +import signin from '/user/signin/user.signin.js'; + +import header from '/elements/header.js'; + +import flexbox from '/elements/flexbox.js'; + + +export default class rightSide { + + newsPages = new newsPages(); + + signup = new signup(); + + signin = new signin(); + + settings = new settings(); + + fileManager = new fileManager(); + + animations = new animations(); + + gridExample = new gridExample(); + + userListPage = new userListPage(); + + editUser = new editUser(); + + + borderRadius; + + flexDirection = "column"; + + + + transition = "2s, border-radius none"; + + borderTopRightRadius = 8; + + borderBottomRightRadius = 8; + + overflow = "hidden!important"; + + overflowY = "auto"; + + + #ifdef WINDOWS + + + borderTopRightRadius = 12; + + borderBottomRightRadius = 12; + + width = 600; + + #endif + + #ifdef MACOS + + + borderTopRightRadius = 12; + + borderBottomRightRadius = 12; + + width = 600; + + boxShadow = "-1px 0px 1px 0px #00000008"; + + #ifdef DARK + + background = "#2a2525e6"; + + background = "#282828"; + + + + #endif + + #ifdef LIGHT + + + + #endif + + #endif + + + create() { + + this.hideChildren(); + + this.newsPages.show(); + + document.application = this.parent; + + } + + +} \ No newline at end of file diff --git a/application/elements/button.js b/application/elements/button.js new file mode 100644 index 0000000..f57c7df --- /dev/null +++ b/application/elements/button.js @@ -0,0 +1,211 @@ + +//import document from '/unify/document.js'; + +export default class button{ + + height = "fit-content"; + + layers = 1; + + fontWeight = "normal"; + + borderRadius = "4px"; + + fontSize = "12px"; + + cursor = "pointer"; + + color = "white"; + + width = "fit-content"; + + + #ifdef ANDROID + + borderRadius = 40; + + fontSize = 15 + + margin = 20; + + width = "-webkit-fill-available"; + + fontSize = 22; + + fontWeight = "bold" + + textAlign = "center"; + + padding = 20; + + + + #ifdef LIGHT + + background = "#f2f2f2"; + + color = "#019e7c"; + + hoverBackgroundColor = "#d9d9d9"; + + opaqueBackgroundColor = "#f2f2f2"; + + #endif + + #ifdef DARK + + background = "#323232"; + + color = "white"; + + //border = "1px solid #3d3a3a"; + + hoverBackgroundColor = "#3e3e3e"; + + opaqueBackgroundColor = "#323232"; + + #endif + + #endif + + + #ifdef WINDOWS + + border = "1px solid #7f7b7b"; + + margin = 12; + + padding = "8px 40px"; + + #ifdef LIGHT + + background = "#0067C0"; + + color = "white"; + + hoverBackgroundColor = "rgb(86 141 189)"; + + opaqueBackgroundColor = "#0067C0"; + + #endif + + #ifdef DARK + + background = "#323232"; + + color = "white"; + + border = "1px solid #3d3a3a"; + + hoverBackgroundColor = "#3e3e3e"; + + opaqueBackgroundColor = "#323232"; + + #endif + + #endif + + + #ifdef MACOS + + border = "1px solid #7f7b7b"; + + margin = 2; + + margin = "4px 2px" + + padding = "4px 20px"; + + #ifdef LIGHT + + color = "black"; + + background = "white"; + + border = "1px solid #e3e1e1"; + + fontSize = 14; + + opaqueBackgroundColor = "white"; + + hoverBackgroundColor = "rgb(230 231 230 / 65%)"; + + #endif + + #ifdef DARK + + color = "white"; + + background = "#282828"; + + hoverBackgroundColor = "#3e3e3e"; + + opaqueBackgroundColor = "#282828"; + + #endif + + #endif + + + + display = "block"; + + async mousedown() { +/* + + var backgroundAnimation = this.createAnimation("backgroundAnimation"); + + var key = backgroundAnimation.createKeyFrame( 0 ); + + + key.setProperty( "background", this.background ); + + + + var key = backgroundAnimation.createKeyFrame( 100 ); + + + #ifdef WINDOWS + + #ifdef DARK + + key.setProperty( "background", "#484747" ); + + #endif + + #endif + + + var animationPromiseC = await backgroundAnimation.play("500ms"); + + this.background = "076fc9"; +*/ + + } + + + mouseover() { + + this.background = this.hoverBackgroundColor; + + } + + mouseleave() { + + this.background = this.opaqueBackgroundColor; + + #ifdef WINDOWS + + #ifdef DARK + + this.background = this.opaqueBackgroundColor; + + #endif + + #endif + + } + + +} + diff --git a/application/elements/checkbox.js b/application/elements/checkbox.js new file mode 100644 index 0000000..0767478 --- /dev/null +++ b/application/elements/checkbox.js @@ -0,0 +1,37 @@ + +import document from '/unify/document.js'; + +export default class checkbox{ + + boxDisplay = "table-cell"; + + customElement = document.createElement("input"); + + autoUpdate = true; + + inputType = "checkbox"; + + useCustomElement = true; + + editable = true; + + layers = 2; + + parseChildren = false; + + + setType( type ) { + + this.inputType = type; + + } + + setup() { + + this.customElement.setAttribute( "value", this.id ); + + this.customElement.setAttribute( "type", this.inputType ); + + } + +} \ No newline at end of file diff --git a/application/elements/empty.js b/application/elements/empty.js new file mode 100644 index 0000000..5b4c3e2 --- /dev/null +++ b/application/elements/empty.js @@ -0,0 +1,6 @@ + + +export default class empty{ + + +} \ No newline at end of file diff --git a/application/elements/fileChooser/fileChooser.file.icon.js b/application/elements/fileChooser/fileChooser.file.icon.js new file mode 100644 index 0000000..a66ddca --- /dev/null +++ b/application/elements/fileChooser/fileChooser.file.icon.js @@ -0,0 +1,33 @@ + +import icon from "../icon.js"; + +export default class fileChooserFileIcon extends icon{ + + width = 50; + + height = 50; + + layers = 1; + + backgroundSize = "contain!important" + + create() { + + console.log("icon type", this.parent.fileType); + + + if( this.parent.fileType == "file" ) { + + this.setImage( "assets/images/icons/file.png" ); + + } + + if( this.parent.fileType == "directory" ) { + + this.setImage( "assets/images/icons/folder.png" ) + + } + + } + +} \ No newline at end of file diff --git a/application/elements/fileChooser/fileChooser.file.js b/application/elements/fileChooser/fileChooser.file.js new file mode 100644 index 0000000..5c68234 --- /dev/null +++ b/application/elements/fileChooser/fileChooser.file.js @@ -0,0 +1,34 @@ + + +import icon from "./fileChooser.file.icon.js"; + +import label from "../label.js"; + +import checkbox from "/elements/checkbox.js"; + +export default class file{ + + margin = 10; + + + filename; + + path; + + create() { + + var filename = this.filename; + + this.label.text = filename; + + } + + checkbox = new checkbox(); + + icon = new icon(); + + label = new label(); + + + +} \ No newline at end of file diff --git a/application/elements/fileChooser/fileChooser.files.js b/application/elements/fileChooser/fileChooser.files.js new file mode 100644 index 0000000..4a1b381 --- /dev/null +++ b/application/elements/fileChooser/fileChooser.files.js @@ -0,0 +1,76 @@ + +#ifdef SERVER + + import fs from "fs"; + + import path from "path"; + +#endif + + +import file from "./fileChooser.file.js"; + +export default class fileChooserFiles{ + + async open() { + + var relativePath = "./"; + + var systemPath = await this.getSystemPath( relativePath ) + + var files = await this.getDirectory( systemPath ); + + } + + node async getSystemPath( relativePath ) { + + var absolutePath = path.resolve( relativePath ); + + console.log("getSystemPath", absolutePath); + + return absolutePath; + + } + + node async getDirectory( absolutePath ) { + + var files = fs.readdirSync( absolutePath ); + + + for (var i = 0; i < files.length; i++) { + + var filename = files[i]; + + var fileStat = fs.lstatSync( absolutePath + "/" + filename ); + + + var currentFile = new file(); + + + currentFile.filename = filename; + + currentFile.path = absolutePath; + + if( fileStat.isDirectory() ) { + + currentFile.fileType = "directory"; + + } else { + + currentFile.fileType = "file"; + + } + + console.log("add file", currentFile); + + this.add( currentFile ); + + } + + console.log("readdirSync", files); + + return files; + + } + +} \ No newline at end of file diff --git a/application/elements/fileChooser/fileChooser.js b/application/elements/fileChooser/fileChooser.js new file mode 100644 index 0000000..5dda3cd --- /dev/null +++ b/application/elements/fileChooser/fileChooser.js @@ -0,0 +1,51 @@ + +import files from "./fileChooser.files.js"; + +import selectButton from "./fileChooser.select.button.js"; + +export default class fileChooser{ + + //selector = "#application"; + + zIndex = 1000; + + left = 0; + + top = 0; + + width = "100vw" + + height = "100vh" + + flexDirection = "column" + + display = "none" + + + + #ifdef LIGHT + + background = "white" + + #endif + + + + + files = new files(); + + selectButton = new selectButton(); + + open() { + + this.files.open(); + + } + + async create() { + + this.hide(); + + } + +} \ No newline at end of file diff --git a/application/elements/fileChooser/fileChooser.select.button.js b/application/elements/fileChooser/fileChooser.select.button.js new file mode 100644 index 0000000..42751f8 --- /dev/null +++ b/application/elements/fileChooser/fileChooser.select.button.js @@ -0,0 +1,22 @@ + +import button from "/elements/button.js"; + + +export default class fileChooserSelectButton extends button { + + layers = 2; + + + click() { + alert("asd") + console.log("click", this); + /* + var files = this.parent.files.getChildren(); + //console.log(files); + for (var i = 0; i < files.length; i++) { + console.log(files[i].checkbox.value, files[i].path, files[i].filename); + } +*/ + } + +} \ No newline at end of file diff --git a/application/elements/fileUpload.js b/application/elements/fileUpload.js new file mode 100644 index 0000000..059e6f8 --- /dev/null +++ b/application/elements/fileUpload.js @@ -0,0 +1,45 @@ + + +import input from './input.js'; + + +import Console from '/unify/console.js'; + +import promiseManager from '/unify/promiseManager.js'; + +import shared from '/unify/shared.js'; + + +export default class fileUpload extends input{ + + inputType = "file"; + + attribute = "multiple"; + + promiseManager = new promiseManager(); + + uploadID = 0; + + fileInformation = new Array(); + + path = "/assets/uploads/"; + + customFileName = false; + + + constructor() { + + super(); + + } + + create() { + + this.customElement.setAttribute("type", this.inputType); + this.customElement.setAttribute("multiple", "true"); + + } + + +} + diff --git a/application/elements/filler.js b/application/elements/filler.js new file mode 100644 index 0000000..ba2e8b3 --- /dev/null +++ b/application/elements/filler.js @@ -0,0 +1,41 @@ + + +export default class filler{ + + layers = 1; + + height = "-webkit-fill-available"; + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#ffffff"; + + #endif + #endif + + #ifdef WINDOWS + + #ifdef LIGHT + + color = "black"; + + #endif + + + #ifdef DARK + + #endif + + #endif + + width = "-webkit-fill-available"; + +} \ No newline at end of file diff --git a/application/elements/flexbox.js b/application/elements/flexbox.js new file mode 100644 index 0000000..b2e1c36 --- /dev/null +++ b/application/elements/flexbox.js @@ -0,0 +1,39 @@ + + +export default class flexbox{ + + renderToDOM = true; + + #ifdef MACOS + + #ifdef DARK + + color = "white"; + + #endif + + #ifdef LIGHT + + color = "black"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + color = "white"; + + #endif + + #ifdef LIGHT + + color = "black"; + + #endif + + #endif + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.body.js b/application/elements/gridView/gridView.body.js new file mode 100644 index 0000000..185cf61 --- /dev/null +++ b/application/elements/gridView/gridView.body.js @@ -0,0 +1,54 @@ + + + + +export default class gridViewTableHeader{ + + flexFlow = "column"; + + display = "table-row-group" + + layers = 1; + + + #ifdef WINDOWS + + fontSize = 12; + + #ifdef DARK + + + #endif + + #ifdef LIGHT + + background = "white"; + + #endif + + #endif + + + + #ifdef MACOS + + fontSize = 12; + + #ifdef DARK + + background = "#2c2c2c"; + + fontWeight = "bold"; + + #endif + + #ifdef LIGHT + + + background = "rgb(0 0 0 / 1%)"; + + #endif + + #endif + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.body.row.column.js b/application/elements/gridView/gridView.body.row.column.js new file mode 100644 index 0000000..bb46078 --- /dev/null +++ b/application/elements/gridView/gridView.body.row.column.js @@ -0,0 +1,54 @@ + + +import tableCell from "/elements/tableCell.js"; + +export default class gridViewBodyColumn extends tableCell{ + + useCustomElement = false; + + layers = 1; + + + #ifdef WINDOWS + + padding = 20; + + #ifdef DARK + + paddingLeft = 30; + + //borderLeft = "1px solid #24364e7a"; + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef MACOS + + padding = 12; + + #ifdef DARK + + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef ANDROID + + padding = 20; + + #endif + + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.body.row.js b/application/elements/gridView/gridView.body.row.js new file mode 100644 index 0000000..28d9f66 --- /dev/null +++ b/application/elements/gridView/gridView.body.row.js @@ -0,0 +1,13 @@ + + + + +export default class gridViewRow{ + + display = "table-row"; + + layers = 1; + + propegateEvent = false; + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.header.js b/application/elements/gridView/gridView.header.js new file mode 100644 index 0000000..c288527 --- /dev/null +++ b/application/elements/gridView/gridView.header.js @@ -0,0 +1,59 @@ + + + + +export default class gridViewHeader{ + + display = "table-header-group" + + layers = 1; + + flexFlow = "column"; + + + #ifdef WINDOWS + + fontSize = 12; + + #ifdef DARK + + + + #endif + + #ifdef LIGHT + + background = "#ffffffa8" + + borderBottom = "1px solid rgb(0 0 0 / 5%)" + + #endif + + #endif + + + #ifdef MACOS + + fontSize = 12; + + #ifdef DARK + + background = "#393939"; + + borderBottom = "2px solid #3f3f3f"; + + #endif + + #ifdef LIGHT + + background = "rgb(0 0 0 / 3%)" + + borderBottom = "1px solid rgb(0 0 0 / 5%)" + + #endif + + #endif + + + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.header.row.column.js b/application/elements/gridView/gridView.header.row.column.js new file mode 100644 index 0000000..589efb2 --- /dev/null +++ b/application/elements/gridView/gridView.header.row.column.js @@ -0,0 +1,126 @@ + + +import tableCell from "/elements/tableCell.js"; + +import sortBy from "./gridView.header.row.column.sortBy.js"; + + +export default class gridViewRowColumn extends tableCell{ + + display = "table-cell"; + + layers = 1; + + propegateEvent = false; + + useCustomElement = false; + + cursor = "pointer"; + + hoverBackgroundColor = "#363333" + + async click() { + + var renderCollection = this.parent.parent.parent.body; + + renderCollection.sort = this.propertyName; + + this.unselectOtherColumns(); + + var direction = this.selectThisColumn(); + + renderCollection.direction = direction; + + renderCollection.update(); + + } + + unselectOtherColumns() { + + var columns = this.parent.getChildren(); + + for (var i = 0; i < columns.length; i++) { + + var column = columns[i]; + + if( column.sortBy ) { + + column.sortBy.text = ""; + + } + + } + + } + + selectThisColumn() { + + if( this.sortBy.type == "asc" ) { + + this.sortBy.transform = "rotate(90deg)"; + + this.sortBy.type = "desc" + + } else { + + this.sortBy.transform = "rotate(-90deg)"; + + this.sortBy.type = "asc" + + } + + this.sortBy.text = "<"; + + return this.sortBy.type; + + } + + + #ifdef WINDOWS + + padding = 10; + + paddingRight = 40; + + paddingLeft = 20; + + #ifdef DARK + + paddingLeft = 30; + + //borderLeft = "1px solid #24364e7a"; + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef MACOS + + padding = 10; + + #ifdef DARK + + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef ANDROID + + padding = 20; + + #endif + + sortBy = new sortBy(); + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.header.row.column.sortBy.js b/application/elements/gridView/gridView.header.row.column.sortBy.js new file mode 100644 index 0000000..ad5bf01 --- /dev/null +++ b/application/elements/gridView/gridView.header.row.column.sortBy.js @@ -0,0 +1,19 @@ + + +import button from "/elements/button.js"; + +export default class sortBy{ + + text = "" + + transition = "none" + + layers = 1; + + float = "right" + + transform; + + type = "desc" + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.header.row.js b/application/elements/gridView/gridView.header.row.js new file mode 100644 index 0000000..f6f54e8 --- /dev/null +++ b/application/elements/gridView/gridView.header.row.js @@ -0,0 +1,13 @@ + + + + +export default class gridViewTableRow{ + + display = "table-row"; + + propegateEvent = false; + + layers = 1; + +} \ No newline at end of file diff --git a/application/elements/gridView/gridView.js b/application/elements/gridView/gridView.js new file mode 100644 index 0000000..fd2c09a --- /dev/null +++ b/application/elements/gridView/gridView.js @@ -0,0 +1,80 @@ + + +export default class gridView{ + + display = "table"; + + layers = 1; + + fontSize = 12; + + + + borderCollapse = "separate"; + + borderSpacing = "0"; + + borderRadius = 12; + + overflow = "hidden"; + + + + #ifdef WINDOWS + + margin = 30; + + borderRadius = 4; + + #ifdef DARK + + background = "#202020" + + color = "white" + + #endif + + #ifdef LIGHT + + #endif + + #endif + + #ifdef MACOS + + margin = 2; + + borderRadius = 4; + + #ifdef DARK + + color = "white" + + border = "1px solid #4f4f4f" + + #endif + + #ifdef LIGHT + + border = "1px solid rgb(0 0 0 / 5%)" + + #endif + + #endif + + #ifdef ANDROID + + + + #ifdef LIGHT + + background = "white"; + + #endif + + + #endif + + propegateEvent = false; + +} \ No newline at end of file diff --git a/application/elements/header.js b/application/elements/header.js new file mode 100644 index 0000000..e2a2762 --- /dev/null +++ b/application/elements/header.js @@ -0,0 +1,95 @@ + + +export default class header{ + + constructor( text, gridName ) { + + this.text = text; + this.gridArea = gridName; + + } + + gridArea = "passwordLabel"; + + text = "password"; + + color = "#665f5f"; + + padding = 10; + + + + #ifdef WINDOWS + + fontWeight = "bold"; + + fontSize = 24; + + margin = 0; + + #ifdef DARK + + color = "white" + + //background = "#1c1c1c61"; + + #endif + + #ifdef LIGHT + + color = "#282626"; + + #endif + + #endif + + + #ifdef MACOS + + margin = 6; + + fontWeight = "bold"; + + fontSize = 16; + + marginLeft = 4; + + #ifdef DARK + + color = "white" + + #endif + + #ifdef LIGHT + + #endif + + #endif + + + #ifdef ANDROID + + text = "Menu"; + + flexDirection = "column"; + + fontSize = 36; + + paddingTop = 100; + + fontWeight = "300" + + paddingBottom = 100; + + textAlign = "center"; + + width = "100vw"; + + padding = "0" + + margin = 0; + + #endif + +} + diff --git a/application/elements/icon.js b/application/elements/icon.js new file mode 100644 index 0000000..690f7cb --- /dev/null +++ b/application/elements/icon.js @@ -0,0 +1,66 @@ + +import button from './button.js'; + +var icon_id = 0; + + +export default class icon{ + + id = icon_id++; + + constructor( name, invert ) { + + if( name ) { + + this.background = "url( assets/images/icons/" + name + " )"; + + } + + if( invert ) { + + this.invert = 1; + this.filter = "invert(" + this.invert + ") "; //drop-shadow(0 0 4px white) + + } else { + + this.invert = 0; + this.filter = "invert(" + this.invert + ") "; //drop-shadow(0 0 4px white) + } + + } + + setImage( path ) { + + this.background = "url( " + path + " )"; + + } + + + #ifdef WINDOWS + + #ifdef LIGHT + + filter = "invert(0)" + + #endif + + #ifdef DARK + + filter = "invert(1)" + + #endif + + #endif + + + filter = "invert(1)"; + + editable = false; + + backgroundSize = "contain"; + + width = 20; + + height = 20; + +} diff --git a/application/elements/iconButton.js b/application/elements/iconButton.js new file mode 100644 index 0000000..3f7d42b --- /dev/null +++ b/application/elements/iconButton.js @@ -0,0 +1,74 @@ + +import label from './label.js'; +import icon from './icon.js'; + + +class customLabel extends label{ + + color = "black"; + + constructor( text, color ) { + + super(); + + if( color ) { + + this.color = color; + + } + + this.text = text; + + this.value = text; + + } + + setActive() { + + //this.fontWeight = "bold"; + //this.textShadow = "#dfdfdf 1px 0px 5px"; + + } + + setInactive() { + + //this.fontFamily = "TT Norms Pro Regular"; + //this.color = "#bdbdbd"; + //this.fontWeight = "normal"; + //this.textShadow = "none"; + + } + + create() { + + //this.fontFamily = "TT Norms Pro Regular"; + + } + + click() { + + console.log("click label"); + + //this.setActive(); + + } + + fontSize = "14px"; + + editable = false; + +} + + + + +export default class iconButton{ + + constructor( text, iconName, mirror = true, color ) { + + this.label = new customLabel( text, color ); + this._icon = new icon( iconName, mirror ); + + } + +} diff --git a/application/elements/image.js b/application/elements/image.js new file mode 100644 index 0000000..03a788d --- /dev/null +++ b/application/elements/image.js @@ -0,0 +1,20 @@ + +import document from '/unify/document.js'; + +var icon_id = 0; + +export default class image{ + + customElement = document.createElement("img"); + + useCustomElement = true; + + id = icon_id++; + + setImage( path ) { + + this.customElement.setAttribute("src", path) + + } + +} diff --git a/application/elements/input.js b/application/elements/input.js new file mode 100644 index 0000000..28a85ca --- /dev/null +++ b/application/elements/input.js @@ -0,0 +1,501 @@ + +import document from '/unify/document.js'; + +import tools from '/unify/tools.js'; + + +export default class input { + + renderToDOM = true; + + value = ""; + + disabled = false; + + customElement = document.createElement("input"); + + inputType = "text"; + + layers = 2; + + useCustomElement = true; + + autocomplete = "on"; + + placeholder = ""; + + outline = "none"; + + validateType = "default"; + + fontSize = 16 + + border = "1px solid #ececec"; + + layers = 1; + + propegateEvent = false; + + width = "-webkit-fill-available" + + + + #ifdef MACOS + + width = "70%"; + + #ifdef LIGHT + + + + + borderBottom = "1px solid #dedede" + + background = "#f7f7f7"; + + + color = "black"; + + opaqueBackgroundColor = "#f7f7f7"; + + + + focusBackgroundColor = "#f7f7f7"; + + focusBorderBottom = "1px solid #dedede"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + color = "#b1b1b1"; + + + + #endif + + + #ifdef DARK + + background = "rgb(255 255 255 / 3%)"; + + color = "white"; + + opaqueBackgroundColor = "rgb(255 255 255 / 3%)"; + + + + focusBackgroundColor = "rgb(255 255 255 / 3%)"; + + focusBorderBottom = ""; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = ""; + + + #endif + + + + padding = 12; + + margin = 6; + + marginRight = 20; + + height = "fit-content"; + + borderRadius = 0; + + fontWeight = "bold"; + + fontSize = 10; + + border = "1px solid rgba(255,255,255,0.04)"; + + padding = 12; + + fontSize = ""; + + borderRadius = 6; + + borderBottom = "none"; + + width = "auto" + + + + + + #endif + + + + + #ifdef WINDOWS + + borderBottom = "2px solid #868686" + + borderRadius = 6; + + padding = 12; + + margin = 12; + + height = "fit-content" + + #ifdef LIGHT + + background = "#F7FAFC"; + + border = "1px solid #E5E5E5"; + + opaqueBackgroundColor = "#F7FAFC"; + + + focusBackgroundColor = "white"; + + focusBorderBottom = "2px solid #4CC2FF"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + #endif + + + #ifdef DARK + + background = "#1d1d1d!important" + + webkitBoxShadow = "inset 0 0 20px 20px #1c1c1c"; + + webkitTextFillColor = "white"; + + color = "white" + + transition = "background-color 5000s ease-in-out 0s"; + + + border = "1px solid #303030"; + + borderBottom = "2px solid #9A9A9A"; + + color = "WHITE"; + + opaqueBackgroundColor = "#1d1d1d!important"; + + + focusBackgroundColor = "#1F1F1F"; + + focusBorderBottom = "2px solid #0067C0"; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = "1px solid #9A9A9A"; + + + + #endif + + + #endif + + + + focus() { + + this.borderBottom = this.focusBorderBottom; + + this.background = this.focusBackgroundColor; + + } + + blur() { + + this.background = this.blurBackgroundColor; + + this.borderBottom = this.blurBorderBottom; + + } + + setup( ) { + + var that = this; + + that._useCustomElement = this.useCustomElement; + + this.__defineSetter__( "useCustomElement", function( value ) { + + that._useCustomElement = value; + + that.setupElement(); + + }); + + this.__defineGetter__( "useCustomElement", function( value ){ + + if( typeof that._useCustomElement == "undefined" ) { + + that._useCustomElement = false; + + + return false; + + } else { + + return that._useCustomElement; + + } + }); + + this.setupElement(); + + } + + + // For AutoComplete -> but makes that you cannot overide or it happens again + change() { + + this.value = this.customElement.value; + + } + + setupElement() { + + this.customElement.setAttribute( "type", this.inputType ); + + this.customElement.setAttribute( "autocomplete", this.autocomplete ); + + this.customElement.setAttribute( "placeholder", this.placeholder ); + + + if( this.step ) { + + this.customElement.setAttribute( "step", this.step ); + } + + + if( this.placeholder && this.customElement ) { + + this.customElement.setAttribute( "placeholder", this.placeholder ); + + } + + if( this.width ) { + + if( typeof this.width == "number" ) { + + this.customElement.style.width = this.width + "px"; + + } else { + + this.customElement.style.width = this.width; + + } + + + + } + + + if( this.element ) { + + var parentNode = this.element.parentNode; + + if( this.useCustomElement ) { + + + + if( this.element.tagName != this.customElement.tagName ) { + + parentNode.replaceChild( this.customElement, this.element ); + + this.element = this.customElement; + + } + + } else { + + if( this.element.tagName != this.defaultElement.tagName ) { + + parentNode.replaceChild( this.defaultElement, this.element ); + + this.element = this.defaultElement; + + } + + } + + this.updateElementContent(); + + } + + } + + + + isValid() { + + if( !this.value ) { + + return false; + + } + + return this.validateString( this.value ); + + } + + validateEmail(email) { + + const res = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + + return res.test(String(email).toLowerCase()); + + } + + validateString( value ) { + + var isValid = true; + + if( !this.value ) { + + return false; + + } + + + switch( this.validateType ) { + + case "default": + + if( this.minLength ) { + + if( value.length < this.minLength ) { + + return false; + + } + + } + + break; + + case "email": + + return this.validateEmail( this.value ); + + break; + + + } + + + return true; + + } + + + + validateInput() { + + if( this.validateString( this.value ) ) { + + this.removeErrorMessages(); + + this.validated = true; + + console.log("remove errorBlock"); + + + this.border = "#28a745"; + + this.color = "#495057"; + + this.shadow = "0px 0px 4px 2px #28a745"; + + } else { + + this.validated = false; + + this.border = "1px solid #dc3545"; + + this.color = "black"; + + this.shadow = "0px 0px 4px 2px #dc3545"; + + } + + } + +/* + focus() { + + this.validateInput(); + + this.customElement.focus(); + + } +*/ + removeErrorMessages() { + + var errorBlocks = document.querySelectorAll(".errorBlock"); + + for (var i = 0; i < errorBlocks.length; i++) { + + errorBlocks[i].remove(); + + } + + } + + showError( text ) { + + this.removeErrorMessages(); + + var errorBlock = document.createElement("div"); + + + errorBlock.innerText = text; + + errorBlock.className = "errorBlock"; + + this.boxElement.appendChild( errorBlock ); + + } + + + afterLoad() { + + if( this.validate ) { + + //this.validateInput(); + + } + + + } + + async keyup( event ){ + + this.value = event.target.value; + + if( this.validate ) { + + this.validateInput(); + + } + + + } + +} + diff --git a/application/elements/inputPassword.js b/application/elements/inputPassword.js new file mode 100644 index 0000000..1bff6e9 --- /dev/null +++ b/application/elements/inputPassword.js @@ -0,0 +1,27 @@ + +import input from './input.js'; + +export default class inputPassword extends input{ + + inputType = "password"; + + + outline = "none"; + + constructor(){ + + super(); + + this.type = "password"; + + } + + + create() { + + this.customElement.setAttribute("type", this.inputType); + + } + +} + diff --git a/application/elements/label.js b/application/elements/label.js new file mode 100644 index 0000000..70cebdc --- /dev/null +++ b/application/elements/label.js @@ -0,0 +1,77 @@ + +export default class label{ + + constructor( text, gridName ) { + + this.text = text; + + this.gridArea = gridName; + + } + + + layers = 1; + + gridArea = "passwordLabel"; + + text = "password"; + + color = "black"; + + padding = 20; + + fontSize = 12; + + + #ifdef WINDOWS + + fontWeight = "bold"; + + + + #ifdef LIGHT + + + color = "#282626"; + + #endif + + + #ifdef DARK + + color = "white"; + + #endif + + + #endif + + + #ifdef MACOS + + padding = 10; + + paddingLeft = 0; + + boxWidth = "100%"; + + + #ifdef LIGHT + + + + + #endif + + + #ifdef DARK + + color = "white"; + + #endif + + + #endif + + +} diff --git a/application/elements/label/left.js b/application/elements/label/left.js new file mode 100644 index 0000000..b38ada8 --- /dev/null +++ b/application/elements/label/left.js @@ -0,0 +1,10 @@ + +import label from "../label.js"; + +export default class leftLabel extends label{ + + width = "30%" + + justifyContent = "flex-end"; + +} \ No newline at end of file diff --git a/application/elements/option.js b/application/elements/option.js new file mode 100644 index 0000000..3e3bb96 --- /dev/null +++ b/application/elements/option.js @@ -0,0 +1,231 @@ + +import document from '/unify/document.js'; + + +export default class option{ + + customElement = document.createElement("option"); + + layers = 1; + + parseChildren = false; + + useCustomElement = true; + + editable = true; + + preventUpdating = true; + + padding = 4; + + + + #ifdef MACOS + + width = "70%"; + + #ifdef LIGHT + + + + + borderBottom = "1px solid #dedede" + + background = "#f7f7f7"; + + + color = "black"; + + opaqueBackgroundColor = "#f7f7f7"; + + + + focusBackgroundColor = "#f7f7f7"; + + focusBorderBottom = "1px solid #dedede"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + color = "#b1b1b1"; + + + + #endif + + + #ifdef DARK + + background = "rgb(255 255 255 / 3%)"; + + color = "white"; + + opaqueBackgroundColor = "rgb(255 255 255 / 3%)"; + + + + focusBackgroundColor = "rgb(255 255 255 / 3%)"; + + focusBorderBottom = ""; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = ""; + + + #endif + + + + padding = 6; + + margin = 6; + + marginRight = 20; + + height = "fit-content"; + + borderRadius = 0; + + fontWeight = "bold"; + + fontSize = 10; + + border = "1px solid rgb(255 255 255 / 18%)"; + + padding = 12; + + fontSize = ""; + + borderRadius = 6; + + borderBottom = "none"; + + width = "auto" + + + + + + #endif + + + + + #ifdef WINDOWS + + borderBottom = "2px solid #868686" + + borderRadius = 6; + + padding = 8; + + margin = 12; + + #ifdef LIGHT + + background = "#F7FAFC"; + + border = "1px solid #E5E5E5"; + + opaqueBackgroundColor = "#F7FAFC"; + + + focusBackgroundColor = "white"; + + focusBorderBottom = "2px solid #4CC2FF"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + #endif + + + #ifdef DARK + + background = "#2D2D2D!important" + + webkitBoxShadow = "0 0 0px 30px #2D2D2D inset!important"; + + webkitTextFillColor = "white"; + + color = "white" + + transition = "background-color 5000s ease-in-out 0s"; + + + border = "1px solid #303030"; + + borderBottom = "2px solid #9A9A9A"; + + color = "WHITE"; + + opaqueBackgroundColor = "#2D2D2D!important"; + + + focusBackgroundColor = "#1F1F1F"; + + focusBorderBottom = "2px solid #0067C0"; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = "1px solid #9A9A9A"; + + + + #endif + + + #endif + + + constructor( value, label ) { + + if( value ) { + + this.value = value; + + } + + if( label ) { + + this.label = label; + + } + + } + + setup() { + + if( this.label ) { + + this.customElement.innerHTML = this.label; + + this.customElement.value = this.value; + + } + + if( this.selected ) { + + this.customElement.setAttribute("selected", "true") + + } + + + } + +} + + + + + + diff --git a/application/elements/page.js b/application/elements/page.js new file mode 100644 index 0000000..5e16754 --- /dev/null +++ b/application/elements/page.js @@ -0,0 +1,66 @@ + +export default class page{ + + + #ifdef ANDROID + + height = "100vh" + + padding = 0; + + borderRadius = 0; + + #ifdef LIGHT + + background = "#f2f2f2"; + + // background = "#000000"; + + #endif + + #endif + + + #ifdef MACOS + + #ifdef DARK + + background = "#282828"; + + #endif + + #ifdef LIGHT + + background = "#fdfdfd"; + + #endif + + #endif + + #ifdef WINDOWS + + #ifdef DARK + + background = "#202020cc"; + + #endif + + #ifdef LIGHT + + background = "rgb(255 255 255 / 75%)"; + + #endif + + #endif + + padding = 20; + + height = "-webkit-fill-available"; + + minHeight = 400; + + width = "-webkit-fill-available"; + + paddingRight = 80; + +} \ No newline at end of file diff --git a/application/elements/panel.js b/application/elements/panel.js new file mode 100644 index 0000000..2df5a0a --- /dev/null +++ b/application/elements/panel.js @@ -0,0 +1,58 @@ + + +export default class panel{ + + layers = 1; + + width = "100%" + + #ifdef WINDOWS + + #ifdef LIGHT + + + #endif + + #ifdef DARK + + #endif + + borderRadius = 12; + + + #endif + + #ifdef MACOS + + #ifdef LIGHT + + border = "1px solid rgb(241 241 241)" + + background = "#fbfbfb"; + + borderRadius = 6; + + marginRight = 20; + + + #endif + + #ifdef DARK + + border = "1px solid #ffffff26" + + background = "rgb(255 255 255 / 4%)"; + + width = "100%" + + borderRadius = 6; + + marginRight = 20; + + #endif + + #endif + + + +} diff --git a/application/elements/panel/row.js b/application/elements/panel/row.js new file mode 100644 index 0000000..41a72f5 --- /dev/null +++ b/application/elements/panel/row.js @@ -0,0 +1,73 @@ + + +export default class panelRow{ + + width = "100%"; + + //layers = 1; + sizing = "border-box"; + + + #ifdef WINDOWS + + marginTop = 20; + + #ifdef LIGHT + + background = "#F7FAFC"; + + #endif + + #ifdef DARK + + background = "#2b2b2b"; + + background = "#0c0e165c"; + + #endif + + borderRadius = 12; + + + #endif + + + + afterLoad() { + + #ifdef MACOS + + var children = this.parent.getChildren(); + + var count = children.length-1 + + var lastChild = children[count] + + lastChild.borderBottom = "none"; + + #endif + + } + + + #ifdef MACOS + + margin = "0 6px"; + + #ifdef LIGHT + + borderBottom = "1px solid rgb(241 241 241)" + + #endif + + #ifdef DARK + + borderBottom = "1px solid #ffffff26" + + width = "96%" + + #endif + + #endif + +} \ No newline at end of file diff --git a/application/elements/preloaders/simpleSpinner.js b/application/elements/preloaders/simpleSpinner.js new file mode 100644 index 0000000..d0a744c --- /dev/null +++ b/application/elements/preloaders/simpleSpinner.js @@ -0,0 +1,75 @@ + +import document from "/unify/document.js"; + + + +class line{ + + layers = 1; + + display = "block"; + + + + create() { + + //this.element.className = "loader-line"; + + this.element.classList.add("loader-line-dark") + + } + +} + +class lineMask{ + + layers = 1; + + display = "block"; + + + line = new line(); + + create() { + + //this.element.className = "loader-line-mask"; + this.element.classList.add("loader-line-mask") + } + +} + + + + + + +export default class preloaderBox{ + + layers = 1; + + margin = 40 + + left = "0" + + top = "0" + + + //marginTop = "0px!important" + + //marginLeft = "0px!important"; + + + + position = "relative!important" + + lineMask = new lineMask(); + + + create() { + + this.element.classList.add("loader-circle") + + } + + +} \ No newline at end of file diff --git a/application/elements/preloaders/spinner.js b/application/elements/preloaders/spinner.js new file mode 100644 index 0000000..ff9f30b --- /dev/null +++ b/application/elements/preloaders/spinner.js @@ -0,0 +1,75 @@ + +import document from "/unify/document.js"; + + +class circle{ + + customElement = document.createElementNS("http://www.w3.org/2000/svg","circle"); + + useCustomElement = true; + + layers = 1; + + zIndex = 1000; + + boxShadow = "inset 0 0 0 1px rgb(0 0 0 / 50%)!important" + + create() { + + this.customElement.setAttributeNS(null,"cx", "50") + + this.customElement.setAttributeNS(null,"cy", "50") + + this.customElement.setAttributeNS(null,"r", "20") + + this.customElement.setAttributeNS(null,"fill", "none") + + this.customElement.setAttributeNS(null,"stroke-width", "2") + + this.customElement.setAttributeNS(null,"stroke-miterlimit", "10") + + this.customElement.setAttributeNS(null,"box-shadow", "inset 0 0 0 1px rgb(0 0 0 / 50%)!important") + + + + this.customElement.classList.add('path-dark'); + + + + } + + +} + +class spinner{ + + customElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + + useCustomElement = true; + + layers = 1; + + circle = new circle(); + + create() { + + this.customElement.setAttributeNS(null,"viewBox", "25 25 50 50") + + this.element.setAttributeNS(null, "class", "circular"); + } + +} + + +export default class preloaderBox{ + + layers = 1; + + margin = 40 + + width = 40; + + spinner = new spinner(); + + +} \ No newline at end of file diff --git a/application/elements/radioButton.js b/application/elements/radioButton.js new file mode 100644 index 0000000..a6ac0ab --- /dev/null +++ b/application/elements/radioButton.js @@ -0,0 +1,15 @@ + +import checkbox from '/elements/checkbox.js'; + + +export default class radio extends checkbox{ + + constructor( object ) { + + super( object ); + + this.setType("radio"); + + } + +} \ No newline at end of file diff --git a/application/elements/select.js b/application/elements/select.js new file mode 100644 index 0000000..ca156ad --- /dev/null +++ b/application/elements/select.js @@ -0,0 +1,251 @@ + +import header from './header.js'; +import button from './button.js'; + +import querySQL from '/unify/querySQL.js'; +import renderCollection from '/unify/renderCollection.js'; +import document from '/unify/document.js'; + + +import permission from '/user/group/user.group.permission.js'; + + +export default class select extends renderCollection { + + values = new Array(); + + width = 200; + + layers = 1; + + customElement = document.createElement("select"); + + useCustomElement = true; + + editable = true; + + typedSelect = false; + + debug = true; + + #ifdef WINDOWS + + borderBottom = "2px solid #868686" + + borderRadius = 6; + + padding = 8; + + margin = 12; + + #ifdef LIGHT + + background = "#F7FAFC"; + + border = "1px solid #E5E5E5"; + + opaqueBackgroundColor = "#F7FAFC"; + + + focusBackgroundColor = "white"; + + focusBorderBottom = "2px solid #4CC2FF"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + #endif + + + #ifdef DARK + + background = "#2D2D2D!important" + + webkitBoxShadow = "0 0 0px 30px #2D2D2D inset!important"; + + webkitTextFillColor = "white"; + + color = "white" + + transition = "background-color 5000s ease-in-out 0s"; + + + border = "1px solid #303030"; + + borderBottom = "2px solid #9A9A9A"; + + color = "WHITE"; + + opaqueBackgroundColor = "#2D2D2D!important"; + + + focusBackgroundColor = "#1F1F1F"; + + focusBorderBottom = "2px solid #0067C0"; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = "1px solid #9A9A9A"; + + + + #endif + + + #endif + + + constructor( object, collection ) { + + super( object, collection ); + + if( collection && collection.type == "collection" ) { + + for (var i = 0; i < collection.rows.length; i++) { + + var row = collection.rows[i]; + + this["option" + i] = row; + } + + } + + } + + + + change() { + + if( this.element.selectedOptions ) { + + var selectedElement = this.element.selectedOptions[ 0 ]; + + var selectedID = parseFloat( selectedElement.value ); + + this.value = selectedID; + + this.parent.value = selectedID; + + console.log("selected option", this.parent); + + } + + if( this.element.tagName == "SELECT" ) { + + var selectedElement = this.element.selectedOptions[ 0 ]; + + var element = this.element; + + var index = element.selectedIndex; + var options = element.options; + + var selectedOption = options[ index ]; + var selectedOptionValue = selectedOption.value; + + this.value = selectedOptionValue; + + this.parent.value = selectedOptionValue; + + console.log( "value is now:", this.value ); + } + + + if( this.update ) { + + this.update(); + + } + + + } + + addValue( value ) { + + if( !this.values.includes( value ) ) { + + this.values.push( value ); + } + + this.value = this.values.join(","); + + } + + removeValue( value ) { + + for( var c = 0; c < this.values.length;c++ ) { + + if( this.values[c] == value ) { + + delete this.values[c]; + + } + + } + + this.value = this.values.join(","); + + } + + valueExists( value ) { + + return this.values.includes( value ); + + } + + + + serverSign( object ) { + + this.create(); + + } + + + permission() { + + this.allow( permission.admin, "READ" ); + + this.allow( permission.admin, "WRITE" ); + + } + + addOption( value, label, selected ) { + + var optionElement = document.createElement("option") + + optionElement.text = label; + + optionElement.id = value; + + optionElement.value = value; + + if( label == "Select Country" ) { + + optionElement.setAttribute("disabled", "") + + optionElement.setAttribute("selected", "") + + + } + + if( selected ) { + + optionElement.setAttribute( "selected", "" ) + + } + + this.customElement.appendChild( optionElement ); + + } + +} + + + + + + diff --git a/application/elements/selectCollection.js b/application/elements/selectCollection.js new file mode 100644 index 0000000..daac4a1 --- /dev/null +++ b/application/elements/selectCollection.js @@ -0,0 +1,52 @@ + + +import collection from '/unify/collection.js'; + +import option from '/elements/option.js'; + + + + +export default class selectCollection extends collection{ + + constructor() { + + super( option ); + + } + + + addOption( label, value ) { +/* + var selectOptionObject = new option(); + + selectOptionObject.label = label; + selectOptionObject.value = value; + + this.addObject( selectOptionObject ); +*/ + } + + +} + +/* +//var selectCollection = new collection( option ); + +var selectOptionObject = new option(); + +selectOptionObject.label = "label a"; +selectOptionObject.value = "value a"; + +selectCollection.addObject( selectOptionObject ); + + +var selectOptionObject = new option(); + +selectOptionObject.label = "label b"; +selectOptionObject.value = "value b"; + +selectCollection.addObject( selectOptionObject ); + +export default selectCollection; +*/ \ No newline at end of file diff --git a/application/elements/selectRenderCollection.js b/application/elements/selectRenderCollection.js new file mode 100644 index 0000000..2435ecf --- /dev/null +++ b/application/elements/selectRenderCollection.js @@ -0,0 +1,179 @@ + + +import option from '/elements/option.js'; + +import selectCollection from '/elements/selectCollection.js'; + +import renderCollection from '/unify/renderCollection.js'; + +import document from '/unify/document.js'; + +import groups from '/user/group/user.group.permission.js'; + +var id = 0; + +export default class selectRenderCollection extends renderCollection { + + customElement = document.createElement("select"); + + useCustomElement = true; + + + + + boxMarginLeft = "auto"; + + border; + + shadow; + + #ifdef MACOS + + margin = 12; + + webkitAppearance = "none"; + + boxWidth = "20%"; + + //opacity = "20%"; + + background = "none"; + + border = "none"; + + fontWeight = "bold"; + + outline = "none"; + + boxShadow = "none"; + + margin = 10; + + + #ifdef LIGHT + + + + + #endif + + + #ifdef DARK + + color = "white"; + + background = "#2a2525f5"; + + #endif + + + #endif + + + #ifdef WINDOWS + + padding = "6px 12px"; + + height = "fit-content"; + + margin = 12; + + borderRadius = 6; + + border = "none"; + + #ifdef LIGHT + + background = "#F7FAFC"; + + #endif + + #ifdef DARK + + color = "white"; + + background = "#36373a"; + + #endif + + borderRadius = 2; + + + #endif + + addOption( value, label, selected ) { + + var optionElement = document.createElement("option") + + optionElement.text = label; + + optionElement.id = value; + + optionElement.value = value; + + if( label == "Select Country" ) { + + optionElement.setAttribute("disabled", "") + + optionElement.setAttribute("selected", "") + + + } + + if( selected ) { + + optionElement.setAttribute( "selected", "" ) + + } + + this.customElement.appendChild( optionElement ); + + } + + removeErrorMessages() { + + var errorBlocks = document.querySelectorAll(".errorBlock"); + + for (var i = 0; i < errorBlocks.length; i++) { + + errorBlocks[i].remove(); + + } + + } + + showError( text ) { + + this.removeErrorMessages(); + + var errorBlock = document.createElement("div"); + + errorBlock.innerText = text; + + errorBlock.className = "errorBlock"; + + this.boxElement.appendChild( errorBlock ); + + } + + focus() { + + var selectedIndex = this.customElement.selectedIndex; + + this.hightlight( selectedIndex ) + + + + this.customElement.focus(); + + } + + permission( object ) { + + this.allow( groups.admin , "WRITE" ); + + this.allow( groups.admin , "READ" ); + + } + +} \ No newline at end of file diff --git a/application/elements/tableCell.js b/application/elements/tableCell.js new file mode 100644 index 0000000..811bf75 --- /dev/null +++ b/application/elements/tableCell.js @@ -0,0 +1,11 @@ + + +export default class tableCell{ + + display = "table-cell"; + + layers = 1; + + renderToDOM = true; + +} \ No newline at end of file diff --git a/application/elements/taskbar/taskbar.js b/application/elements/taskbar/taskbar.js new file mode 100644 index 0000000..60fa77e --- /dev/null +++ b/application/elements/taskbar/taskbar.js @@ -0,0 +1,52 @@ + + +import flexbox from '/elements/flexbox.js'; + +import frostedGlass from '/elements/window/frostedGlass.js'; + +import draggable from '/elements/window/draggable.js'; + + + + +export default class taskbar extends flexbox{ + + selector = "#application"; + + position = "absolute"; + + left = "0"; + + bottom = "0" + + width = "100%"; + + height = 50; + #ifdef MACOS + + fontFamily = "sf-ui"; + + width = 600; + + #ifdef DARK + + background = "#161110bf"; + + + + #endif + + #ifdef LIGHT + + //background = "white"; + + background = "#fdfdfdbf" + + #endif + + backdropFilter = "blur(22px)"; + + #endif + + +} \ No newline at end of file diff --git a/application/elements/textarea.js b/application/elements/textarea.js new file mode 100644 index 0000000..0e0923f --- /dev/null +++ b/application/elements/textarea.js @@ -0,0 +1,306 @@ + + +import document from '/unify/document.js'; + +import tools from '/unify/tools.js'; + +export default class textarea{ + + outline = "none"; + + margin = 12; + + renderToDOM = true; + + #ifdef MACOS + + width = "70%"; + + #ifdef LIGHT + + background = "rgb(0 0 0 / 3%)"; + + background = "rgb(0 0 0 / 3%)"; + + color = "black"; + + #endif + + + #ifdef DARK + + background = "rgb(255 255 255 / 3%)"; + + background = "#3e3c3c!important"; + + color = "white"; + + #endif + + padding = 6; + + margin = 6; + + marginRight = 20; + + height = "fit-content"; + + borderRadius = 0; + + fontWeight = "bold"; + + fontSize = 10; + + border = "1px solid rgb(255 255 255 / 18%)"; + + #endif + + + #ifdef WINDOWS + + + margin = 12; + + padding = 12; + + + borderWidth = 1; + + borderRadius = 6; + + + borderColor = "#E5E5E5"; + + borderBottomColor = "#868686"; + + #ifdef LIGHT + + background = "#F7FAFC"; + + border = "1px solid #E5E5E5"; + + + #endif + + + #ifdef DARK + + background = "#2D2D2D" + + border = "1px solid #303030"; + + borderBottom = "2px solid #9A9A9A"; + + color = "WHITE"; + + #endif + + #endif + + + + #ifdef ANDROID + + margin = 4 + + height = "auto" + #ifdef LIGHT + + border = "1px solid #E5E5E5"; + + borderRadius = 20; + + background = "white"; + + padding = 6; + + #endif + + #endif + + + + focus() { + + #ifdef WINDOWS + + #ifdef LIGHT + + this.borderBottom = "2px solid #0067C0"; + + this.background = "white"; + + #endif + + #ifdef DARK + + + this.borderBottom = "2px solid #4CC2FF"; + + this.background = "#1F1F1F"; + + #endif + + #endif WINDOWS + + } + + blur() { + + + #ifdef WINDOWS + + #ifdef LIGHT + + this.background = "#fbfbfb"; + + this.borderBottom = "2px solid #868686"; + + #endif + + #ifdef DARK + + + this.background = "#2D2D2D" + + this.borderBottom = "1px solid #9A9A9A"; + + #endif + + #endif WINDOWS + + } + + + value = ""; + + layers = 1; + + + customElement = document.createElement("textarea"); + + useCustomElement = true; + //border = "1px solid #d8d8d9"; + + scrollbarColor = "#98adc8 #eaeaea"; + + constructor() { + + //super(); + + var that = this; + + if( this.customElement.addEventListener ) { + + this.customElement.addEventListener('keydown', function( e ) { + + if( e.keyCode === 9 ) { + + var start = this.selectionStart; + + var end = this.selectionEnd; + + var target = e.target; + + var value = target.value; + + // set textarea value to: text before caret + tab + text after caret + target.value = value.substring(0, start) + + " " + + value.substring(end); + + // put caret at right position again (add one for the tab) + this.selectionStart = this.selectionEnd = start + 1; + + // prevent the focus lose + e.preventDefault(); + + } + + }, false ); + + } + + } + + async keyup( event ){ + //console.log("event.target.value", event.target.value); + + this.value = event.target.value; + + } + + setup() { + + var that = this; + + that._useCustomElement = this.useCustomElement; + + this.__defineSetter__( "useCustomElement", function( value ) { + + that._useCustomElement = value; + + that.setupElement( value ); + + }); + + this.__defineGetter__( "useCustomElement", function( value ){ + + if( typeof that._useCustomElement == "undefined" ) { + + that._useCustomElement = false; + + return false; + + } else { + + return that._useCustomElement; + + } + }); + + + this.setupElement( this.useCustomElement ); + + } + + setupElement( value ) { + + this.customElement.setAttribute( "placeholder", this.placeholder ); + + + if( this.element ) { + + var parentNode = this.element.parentNode; + + if( this.useCustomElement ) { + + if( this.element.tagName != this.customElement.tagName ) { + + parentNode.replaceChild( this.customElement, this.element ); + + this.element = this.customElement; + + } + + } else { + + if( this.element.tagName != this.defaultElement.tagName ) { + + parentNode.replaceChild( this.defaultElement, this.element ); + + this.element = this.defaultElement; + + } + + } + + this.updateElementContent(); + + } + + + } + +} + diff --git a/application/elements/toggle.js b/application/elements/toggle.js new file mode 100644 index 0000000..136cb48 --- /dev/null +++ b/application/elements/toggle.js @@ -0,0 +1,96 @@ + + +export default class toggle{ + + boxCursor = "pointer"; + + cursor = "pointer"; + + boxBorderRadius = 16; + + boxBackground = "grey" + + boxWidth = 50; + + boxHeight = 24; + + height = 20; + + width = 20; + + margin = 2; + + borderRadius = "100%" + + background = "white"; + + transform; + + value = true; + + transition = "0.2s"; + + boxTransition = "0.2s"; + + create() { + + if( this.value ) { + + this.transform = "translateX(130%)"; + + this.boxBackground = "green"; + + + } else { + + this.transform = "translateX(0%)"; + + this.boxBackground = "grey"; + + } + + } + + boxClick( event ) { + + this.updateState( event ); + + + } + + click( event ) { + + this.updateState( event ); + + } + + + updateState( event ) { + + if( this.value ) { + + this.transform = "translateX(0%)"; + + this.boxBackground = "grey"; + + this.value = false; + + } else { + + this.transform = "translateX(130%)"; + + this.value = true; + + this.boxBackground = "green"; + + } + + if( this.change ) { + + this.change( event ); + + } + + } + +} diff --git a/application/elements/window/draggable.js b/application/elements/window/draggable.js new file mode 100644 index 0000000..e4330d6 --- /dev/null +++ b/application/elements/window/draggable.js @@ -0,0 +1,229 @@ +class vector2{ + + constructor( x, y ) { + + this.x = x; + this.y = y; + + } + + x = 0; + y = 0; + +} + +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + + +export default class draggable{ + + backfaceVisibility = false; + + position = "absolute"; + + zIndex; + +#ifdef CLIENT + + propegateEvent = false; + + transition = "none"; + + + transform; + + width; + + height; + + x; + + y; + + + transition = "width 1s, height 1s"; + + // Custom Properties + draggable = true; + + grab = false; + + lastPosition; + + currentPosition = new vector2( 0, 0 ); + + grabPosition = new vector2( 0, 0 ); + + + state = "normal"; + + + click() { + + this.grab = false; + + } + + mouseout() { + + //this.grab = false; + + } + + + async render( delta ) { + + #ifdef ANDROID + + this.transform = "translate(0px, 0px)"; + + return true; + + #endif + + if( this.draggable ) { + + if(!this.lastPosition) { + + return false; + + } + + var x = this.lastPosition.x; + + var y = this.lastPosition.y; + + + if( this.grab ) { + + + var x = this.mouse.x - this.grabPosition.x + this.lastPosition.x; + + var y = this.mouse.y - this.grabPosition.y + this.lastPosition.y; + + + } + + this.transform = "translate3d("+ x+"px, "+ y +"px, 0)"; + + this.currentPosition = new vector2( x , y ); + + if( this.updateBackgroundCoordinates ) { + + this.updateBackgroundCoordinates(); + + } + + } + } + + maximize() { + + this.restorePosition = this.transform; + + this.width = "100vw"; + + this.height = "100vh" + + this.draggable = false; + + this.transition = "transform 0.1s, width 0.1s, height 0.1s"; + + this.transform = "translate3d(0px, 0px)"; + + this.state = "maximized" + + //this.lastPosition = new vector2( 0,0 ); + + } + + async restore() { + + this.width = ""; + + this.height = ""; + + this.draggable = true; + + await delay(1000); + + this.transition = ""; + + } + + + + center() { + + this.element.style.zIndex = document.globalZIndex++; + + var domWindow = document.defaultView; + + this.windowHeight = domWindow.innerHeight; + + this.windowWidth = domWindow.innerWidth; + + + var boundBox = this.element.getBoundingClientRect(); + + + var width = boundBox.width; + + var height = boundBox.height; + + + var x = this.windowWidth / 2 - ( width / 2 ); + + var y = this.windowHeight / 2 - ( height / 2 ); + + + this.lastPosition = new vector2( Math.round(x), Math.round(y) ); + + } + + mouseup() { + + this.grab = false; + + this.border = "none" + + var boundBox = this.defaultElement.getBoundingClientRect(); + + var x = boundBox.x; + + var y = boundBox.y; + + this.lastPosition = this.currentPosition; + + + + } + + async mousedown( event ) { + + if( event.button != 0 ) { + + return false; + + } + + if( !this.lastPosition ) { + + this.lastPosition = this.currentPosition; + + } + + this.element.style.zIndex = document.globalZIndex++; + + this.grab = true; + + this.grabPosition = this.mouse; + + } + +#endif + +} + diff --git a/application/elements/window/frostedGlass.js b/application/elements/window/frostedGlass.js new file mode 100644 index 0000000..eb131c4 --- /dev/null +++ b/application/elements/window/frostedGlass.js @@ -0,0 +1,82 @@ + +export default class frostedGlass{ + + //backgroundImage = "url('/assets/images/frosted.png')"; + + backgroundSize; + + backgroundPosition; + + clickPosition = [0,0]; + + + + #ifdef WINDOWS + + #ifdef DARK + + //backgroundImage = "url('/assets/images/wallpapers/ventura/darkBlur.png')"; + + #endif + + #ifdef LIGHT + + //backgroundImage = "url('/assets/images/wallpapers/windows/lightBlur.png')"; + + #endif + + #endif + + + #ifdef MACOS + + #ifdef DARK + + //backgroundImage = "url('/assets/images/wallpapers/ventura/darkBlur.jpg')"; + + #endif + + #ifdef LIGHT + + //backgroundImage = "url('/assets/images/wallpapers/ventura/light/lightBlur.jpg')"; + + #endif + + #endif + + + updateBackgroundCoordinates() { + + var backgroundSize = window.innerWidth + "px " + window.innerHeight + "px" + + this.backgroundSize = backgroundSize; + + this.boxBackgroundSize = backgroundSize; + + + var boundBox = this.defaultElement.getBoundingClientRect(); + + var x = boundBox.x * -1; + + var y = boundBox.y * -1; + + var backgroundPosition = x + "px " + y + "px"; + + this.backgroundPosition = backgroundPosition; + + } + + create() { + + this.updateBackgroundCoordinates(); + + } + + + windowResize() { + + this.updateBackgroundCoordinates(); + + } + +} \ No newline at end of file diff --git a/application/elements/window/header.js b/application/elements/window/header.js new file mode 100644 index 0000000..0ad840a --- /dev/null +++ b/application/elements/window/header.js @@ -0,0 +1,276 @@ + + +import icon from "/elements/icon.js"; + + +class maximizeButton extends icon{ + + margin = 20; + + cursor = "pointer" + + width = 16; + + height = 16; + + backgroundSize = "contain!important"; + + #ifdef LIGHT + + filter = "invert(0)" + + #endif + + #ifdef DARK + + filter = "invert(1)" + + #endif + + + click() { + + var window = this.parent.parent.parent; + + + if( window.state == "maximized" ) { + + window.restore(); + + window.state = "normal"; + + this.setImage("assets/images/icons/maximize.svg") + + } else { + + window.maximize(); + + window.state = "maximized"; + + this.setImage("assets/images/icons/restore.svg") + + + } + } + + constructor() { + + super("maximize.svg") + + } + + transition = "1s" + +} + + + +class closeButton extends icon{ + + margin = 20; + + cursor = "pointer" + + width = 16; + + height = 16; + + backgroundSize = "contain!important"; + + #ifdef LIGHT + + filter = "invert(0)" + + #endif + + #ifdef DARK + + filter = "invert(1)" + + #endif + + + click() { + + this.parent.parent.parent.hide(); + + } + + constructor() { + + super("close.svg") + + } + + +} + + +class leftControl{ + + + + closeButton = new closeButton(); + + maximizeButton = new maximizeButton(); + + #ifdef DARK + + color = "#363636"; + + #endif + + height = "40px" + + display = "flex"; + + layers = 1; + + flex = "1"; + + flexDirection = "row" + +} + +class title{ + + //background = "blue"; + + setTitle( title ) { + + this.element.innerText = title; + + } + + padding = 20; + + height = "40px" + + display = "block"; + + layers = 1; + +} + + +class rightControl{ + + //background = "yellow"; + + height = "40px" + + display = "block"; + + flex = "1"; + + layers = 1; + +} + + +export default class windowHeader{ + + + + constructor( text, gridName ) { + + this.title.text = text; + + this.gridArea = gridName; + + } + + + + setTitle( title ) { + + this.title.setTitle( title ); + } + + boxShadow = "0px 1px 1px 0px #00000008"; + + marginBottom = 10; + + + leftControl = new leftControl(); + + title = new title(); + + rightControl = new rightControl(); + + + + width = "100%"; + + layers = 1; + + gridArea = "passwordLabel"; + + color = "black"; + + //padding = 20; + + fontWeight = "bold"; + + fontSize = 12; + + #ifdef WINDOWS + + #ifdef LIGHT + + + + + #endif + + + #ifdef DARK + + color = "white"; + + #endif + + + #endif + + + #ifdef MACOS + + borderTopLeftRadius = "4px" + + borderTopRightRadius = "4px" + + //padding = 10; + + //paddingLeft = 0; + + boxWidth = "100%"; + + + + + #ifdef LIGHT + + borderBottom = "1px solid #f1f1f1"; + + background = "white"; + + + #endif + + + #ifdef DARK + + color = "white"; + + borderBottom = "1px solid black"; + + background = "#1c1c1c"; + + #endif + + + #endif + + +} diff --git a/application/user/edit/edit.user.checkbox.js b/application/user/edit/edit.user.checkbox.js new file mode 100644 index 0000000..e2d7f16 --- /dev/null +++ b/application/user/edit/edit.user.checkbox.js @@ -0,0 +1,78 @@ + + +import checkbox from "/elements/checkbox.js" + +import user from "/user/user.js" + +import tools from "/unify/tools.js" + +export default class customCheckbox extends checkbox{ + + async create() { + + var selected = await this.checkSelected(); + + this.customElement.checked = selected; + + } + + debug = "true" + + node async checkSelected() { + + var editUser = this.parents("editUser"); + + var collection = editUser.selectedUsers; + + collection.sync(); + + var id = this.parent.id; + + tools.log("check selected??", id); + + var v = collection.rowExists( id ); + + console.log(v); + + return v; + + } + + async change() { + + this.value = this.customElement.checked; + + await this.changeCollection( this.value ); + + var editUser = this.parent.parent.parent.parent; + + editUser.showSelectedUser.sync(); + + } + + node async changeCollection( checked ) { + + var editUser = this.parents("editUser"); + + var collection = editUser.selectedUsers; + + var userObject = this.parent; + + tools.log(userObject ); + + + if( checked ) { + + collection.add( userObject ); + + } else { + + collection.remove( userObject ); + + } + + return 1234; + + } + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.checkbox.renderCollection.js b/application/user/edit/edit.user.checkbox.renderCollection.js new file mode 100644 index 0000000..211428d --- /dev/null +++ b/application/user/edit/edit.user.checkbox.renderCollection.js @@ -0,0 +1,25 @@ + +import groups from '/user/group/user.group.permission.js'; + +import renderCollection from "/unify/renderCollection.js"; + + +export default class checkRenderCollection extends renderCollection{ + + debug = true; + + display = "table" + + permission() { + + this.allow( groups.admin, "WRITE" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + this.allow( groups.visitor, "READ" ); + + } + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.checkbox.row.js b/application/user/edit/edit.user.checkbox.row.js new file mode 100644 index 0000000..15b4491 --- /dev/null +++ b/application/user/edit/edit.user.checkbox.row.js @@ -0,0 +1,19 @@ + +import label from '/elements/label.js'; + +import checkRenderCollection from "./edit.user.checkbox.renderCollection.js"; + +import checkbox from "./edit.user.checkbox.tableRow.js"; + +import user from "/user/user.js"; + +import collection from "/unify/collection.js"; + + +export default class checkboxRow{ + + label = new label("Select users"); + + renderCollection = new checkRenderCollection( checkbox , new collection( user ) ); + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.checkbox.tableRow.js b/application/user/edit/edit.user.checkbox.tableRow.js new file mode 100644 index 0000000..601dcdd --- /dev/null +++ b/application/user/edit/edit.user.checkbox.tableRow.js @@ -0,0 +1,37 @@ + +import checkbox from './edit.user.checkbox.js'; + +import radio from '/elements/radioButton.js'; + +import label from '/elements/label.js'; + +import user from "/user/user.js"; + + +export default class customCheckbox extends user{ + + setup() { + + console.log("customCheckbox", this); + + this.label.text = this.username.value; + + this.checkbox.id = this.id; + + } + + label = new label(); + + checkbox = new checkbox(); + + value = false; + + layers = 1; + + parseTable = false; + + display = "table-row"; + + layers = 1; + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.js b/application/user/edit/edit.user.js new file mode 100644 index 0000000..729b95e --- /dev/null +++ b/application/user/edit/edit.user.js @@ -0,0 +1,73 @@ + + +import user from "/user/user.js"; + +import groups from '/user/group/user.group.permission.js'; + +import label from '/elements/label.js'; + +import header from '/elements/header.js'; + +import usernameRow from "./edit.username.row.js"; + +import saveButtonRow from "./user.edit.button.row.js"; + +import page from "/elements/page.js"; + +import checkboxRow from "./edit.user.checkbox.row.js"; + +import selectRow from "./edit.user.select.row.js"; + +import option from "./edit.user.select.option.js"; + +import renderCollection from "./edit.user.select.renderCollection.js"; + + + +export default class editUser extends user, page{ + + padding = 20; + + debug = true; + + flexDirection = "column" + + header = new header("Edit user"); + + usernameRow = new usernameRow(); + + selectRow = new selectRow(); + + checkboxRow = new checkboxRow(); + + + showSelectedUser = new renderCollection( option, this.selectedUsers ); + + + saveButtonRow = new saveButtonRow(); + + + create() { + + this.selectRow.renderCollection.sync(); + + this.checkboxRow.renderCollection.sync(); + + + this.showSelectedUser.sync(); + + } + + permission() { + + this.allow( groups.admin, "WRITE" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + this.allow( groups.visitor, "READ" ); + + } + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.select.option.js b/application/user/edit/edit.user.select.option.js new file mode 100644 index 0000000..2be2a47 --- /dev/null +++ b/application/user/edit/edit.user.select.option.js @@ -0,0 +1,19 @@ + +import option from "/elements/option.js"; + +import user from "/user/user.js"; + + +export default class customOption extends option, user{ + + setup() { + + // use username as label + this.customElement.innerHTML = this.username.value; + + // username as value + this.customElement.value = this.id; + + } + +} diff --git a/application/user/edit/edit.user.select.renderCollection.js b/application/user/edit/edit.user.select.renderCollection.js new file mode 100644 index 0000000..4c018a9 --- /dev/null +++ b/application/user/edit/edit.user.select.renderCollection.js @@ -0,0 +1,198 @@ + + +import renderCollection from "/unify/renderCollection.js"; + +import groups from '/user/group/user.group.permission.js'; + +import document from "/unify/document.js"; + + +export default class customSelect extends renderCollection{ + + customElement = document.createElement("select"); + + useCustomElement = true; + + debug = true; + + + #ifdef MACOS + + width = "70%"; + + #ifdef LIGHT + + + + + borderBottom = "1px solid #dedede" + + background = "#f7f7f7"; + + + color = "black"; + + opaqueBackgroundColor = "#f7f7f7"; + + + + focusBackgroundColor = "#f7f7f7"; + + focusBorderBottom = "1px solid #dedede"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + color = "#b1b1b1"; + + + + #endif + + + #ifdef DARK + + background = "rgb(255 255 255 / 3%)"; + + color = "white"; + + opaqueBackgroundColor = "rgb(255 255 255 / 3%)"; + + + + focusBackgroundColor = "rgb(255 255 255 / 3%)"; + + focusBorderBottom = ""; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = ""; + + + #endif + + + + padding = 6; + + margin = 6; + + marginRight = 20; + + height = "fit-content"; + + borderRadius = 0; + + fontWeight = "bold"; + + fontSize = 10; + + border = "1px solid rgb(255 255 255 / 18%)"; + + padding = 12; + + fontSize = ""; + + borderRadius = 6; + + borderBottom = "none"; + + width = "auto" + + + + + + #endif + + + + + #ifdef WINDOWS + + borderBottom = "2px solid #868686" + + borderRadius = 6; + + padding = 8; + + margin = 12; + + #ifdef LIGHT + + background = "#F7FAFC"; + + border = "1px solid #E5E5E5"; + + opaqueBackgroundColor = "#F7FAFC"; + + + focusBackgroundColor = "white"; + + focusBorderBottom = "2px solid #4CC2FF"; + + + blurBackgroundColor = "#F7FAFC"; + + blurBorderBottom = "1px solid #E5E5E5"; + + + #endif + + + #ifdef DARK + + background = "#2D2D2D!important" + + webkitBoxShadow = "0 0 0px 30px #2D2D2D inset!important"; + + webkitTextFillColor = "white"; + + color = "white" + + transition = "background-color 5000s ease-in-out 0s"; + + + border = "1px solid #303030"; + + borderBottom = "2px solid #9A9A9A"; + + color = "WHITE"; + + opaqueBackgroundColor = "#2D2D2D!important"; + + + focusBackgroundColor = "#1F1F1F"; + + focusBorderBottom = "2px solid #0067C0"; + + + blurBackgroundColor = "#fbfbfb"; + + blurBorderBottom = "1px solid #9A9A9A"; + + + + #endif + + + #endif + + + permission() { + + this.allow( groups.admin, "WRITE" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + this.allow( groups.visitor, "READ" ); + + } + +} \ No newline at end of file diff --git a/application/user/edit/edit.user.select.row.js b/application/user/edit/edit.user.select.row.js new file mode 100644 index 0000000..5bcc444 --- /dev/null +++ b/application/user/edit/edit.user.select.row.js @@ -0,0 +1,19 @@ + +import label from '/elements/label.js'; + +import collection from "/unify/collection.js"; + +import user from "/user/user.js"; + +import option from "./edit.user.select.option.js"; + +import renderCollection from "./edit.user.select.renderCollection.js"; + + +export default class optionRow{ + + label = new label("Select user"); + + renderCollection = new renderCollection( option , new collection( user ) ); + +} \ No newline at end of file diff --git a/application/user/edit/edit.username.js b/application/user/edit/edit.username.js new file mode 100644 index 0000000..ae9acf7 --- /dev/null +++ b/application/user/edit/edit.username.js @@ -0,0 +1,10 @@ + +import username from "../user.username.js"; + +import input from "/elements/input.js"; + + +export default class editUsername extends username, input{ + + +} \ No newline at end of file diff --git a/application/user/edit/edit.username.row.js b/application/user/edit/edit.username.row.js new file mode 100644 index 0000000..2ee38c6 --- /dev/null +++ b/application/user/edit/edit.username.row.js @@ -0,0 +1,14 @@ + +import label from '/elements/label.js'; + + +import editUsername from "./edit.username.js"; + + +export default class usernameRow{ + + label = new label("Username"); + + username = new editUsername(); + +} \ No newline at end of file diff --git a/application/user/edit/user.edit.button.js b/application/user/edit/user.edit.button.js new file mode 100644 index 0000000..d19f3d5 --- /dev/null +++ b/application/user/edit/user.edit.button.js @@ -0,0 +1,13 @@ +import button from '/elements/button.js'; + +export default class userEditButton extends button { + + label = "Save"; + + async click( event, object ){ + + await this.parent.parent.save(); + + } + +} \ No newline at end of file diff --git a/application/user/edit/user.edit.button.row.js b/application/user/edit/user.edit.button.row.js new file mode 100644 index 0000000..77e0ea6 --- /dev/null +++ b/application/user/edit/user.edit.button.row.js @@ -0,0 +1,13 @@ + + +import empty from '/elements/empty.js'; + +import userEditButton from "./user.edit.button.js"; + +export default class saveButtonRow{ + + empty = new empty(); + + userEditButton = new userEditButton(); + +} \ No newline at end of file diff --git a/application/user/group/user.group.admin.js b/application/user/group/user.group.admin.js new file mode 100644 index 0000000..8d36bd2 --- /dev/null +++ b/application/user/group/user.group.admin.js @@ -0,0 +1,24 @@ + +import option from '/elements/option.js'; + +import datatype from '/unify/datatype.js'; + + + +export default class admin extends option { + + + value = 1.0; + + label = "Admin"; + + type = "userGroup"; + + constructor() { + + super(); + + + } + +} \ No newline at end of file diff --git a/application/user/group/user.group.js b/application/user/group/user.group.js new file mode 100644 index 0000000..f2df30a --- /dev/null +++ b/application/user/group/user.group.js @@ -0,0 +1,137 @@ + + +import collection from "/unify/collection.js"; +import datatype from '/unify/datatype.js'; + + +import option from '/elements/option.js'; + + + +class visitor extends option{ + + value = 2.0; + + label = "Visitor"; + + type = "userGroup"; + + constructor() { + + super(); + + } +} + + +class member extends option{ + + value = 0.0; + + ander = 0.0; + + label = "Member"; + + type = "userGroup"; + + constructor() { + + super(); + + + + } + +} + + +class admin extends option { + + value = 1.0; + + label = "Admin"; + + type = "userGroup"; + + constructor() { + + super(); + + + } + +} + + +export default class groups { + + datatype = 'TEXT'; + + value = 2.0; + + enabled = false; + + type = "column" + + change() { + + var children = this.getChildren(); + + for(var c = 0; c { + crypto.pbkdf2(password, salt, iterations, keylen, digest, (err, key) => { + + err ? rej(err) : res(key); + + }); + }); + } + + + node async registerUser( username, password, passwordAgain ) { + +/* + // Validation + if( !this.username.isValid() ) { + + object.status = "error"; + + object.error = "please fill in a valid username." ; + + return object; + + } +*/ + + var table = this.table; + + var users = this.find( "username", username ); + + var saltRounds = 10; + + //var salt = bcrypt.genSaltSync( saltRounds ); + //var hash = bcrypt.hashSync( password, salt ); + + var salt = crypto.randomBytes(32).toString('base64'); + + var iterations = 100; + + + if( !password ) { + + return false; + + } + + if( password != passwordAgain ) { + + return false; + + } + + var hash = await crypto.pbkdf2Sync( password, salt, iterations, 64,'SHA256' ); + + console.log("hash", hash.toString('hex')); + + console.log("salt", salt); + + if( users.length > 0 ) { + + table.status = "user_exists"; + + return table; + + } + + table.username.value = username; + + table.hash.value = await hash.toString('hex'); + + table.salt.value = salt; + + table.signed.value = true; + + table.groups.value = 1; + + table.createInstance(); + + table.save(); + + table.status = "created_user"; + + return table; + + } + + permission() { + + this.allow( groups.visitor , "PROCESS" ); + this.allow( groups.member , "PROCESS" ); + this.allow( groups.admin , "PROCESS" ); + + } + +} + + diff --git a/application/user/user.email.js b/application/user/user.email.js new file mode 100644 index 0000000..7b0f407 --- /dev/null +++ b/application/user/user.email.js @@ -0,0 +1,10 @@ +import column from '/unify/column.js'; + + + +export default class email extends column { + + +} + + diff --git a/application/user/user.hash.js b/application/user/user.hash.js new file mode 100644 index 0000000..997d05e --- /dev/null +++ b/application/user/user.hash.js @@ -0,0 +1,16 @@ + + +import datatype from '/unify/datatype.js'; + +export default class hash { + + datatype = datatype.VARCHAR; + + scope = "private"; + + display = "none"; + +} + + + diff --git a/application/user/user.js b/application/user/user.js new file mode 100644 index 0000000..0727035 --- /dev/null +++ b/application/user/user.js @@ -0,0 +1,40 @@ + +import username from './user.username.js'; + +import salt from './user.salt.js'; + +import hash from './user.hash.js'; + +import sessionKey from './user.sessionKey.js'; + +import groups from './group/user.group.js'; + +import table from '/unify/table.js'; + + +import email from './user.email.js'; + + +import collection from "/unify/collection.js"; + + +export default class user extends table { + + username = new username(); + + salt = new salt(); + + hash = new hash(); + + sessionKey = new sessionKey(); + + // Every user needs to have an groups field, This is for the permissions. + groups = new groups(); + + email = new email(); + + selectedUsers = new collection( user ); + +} + + diff --git a/application/user/user.password.js b/application/user/user.password.js new file mode 100644 index 0000000..6a90be8 --- /dev/null +++ b/application/user/user.password.js @@ -0,0 +1,15 @@ + + +import datatype from '/unify/datatype.js'; + +import inputPassword from '../elements/inputPassword.js'; + +export default class password extends inputPassword { + + + scope = "private"; + +} + + + diff --git a/application/user/user.publicKey.js b/application/user/user.publicKey.js new file mode 100644 index 0000000..1ce49b9 --- /dev/null +++ b/application/user/user.publicKey.js @@ -0,0 +1,12 @@ + +import datatype from '/unify/datatype.js'; + +export default class publicKey{ + + datatype = datatype.VARCHAR; + + display = "none"; + + renderToDOM = false; + +} diff --git a/application/user/user.salt.js b/application/user/user.salt.js new file mode 100644 index 0000000..31559ab --- /dev/null +++ b/application/user/user.salt.js @@ -0,0 +1,19 @@ + + +import input from '../elements/input.js'; + +import datatype from '/unify/datatype.js'; + +export default class salt { + + datatype = datatype.VARCHAR; + + scope = "private"; + + value = ""; + + display = "none"; +} + + + diff --git a/application/user/user.sessionKey.js b/application/user/user.sessionKey.js new file mode 100644 index 0000000..8be5c20 --- /dev/null +++ b/application/user/user.sessionKey.js @@ -0,0 +1,16 @@ + + +import datatype from '/unify/datatype.js'; + +export default class sessionKey { + + datatype = datatype.VARCHAR; + + scope = "private"; + + display = "none"; + +} + + + diff --git a/application/user/user.username.js b/application/user/user.username.js new file mode 100644 index 0000000..0992029 --- /dev/null +++ b/application/user/user.username.js @@ -0,0 +1,12 @@ + +import column from '/unify/column.js'; + + + +export default class username extends column { + + +} + + + diff --git a/application/user/userList/header/user.userList.header.actions.js b/application/user/userList/header/user.userList.header.actions.js new file mode 100644 index 0000000..9db5719 --- /dev/null +++ b/application/user/userList/header/user.userList.header.actions.js @@ -0,0 +1,29 @@ + +import groups from '/user/group/user.group.permission.js'; + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + + +export default class userListHeaderActions extends gridViewColumn { + + text = "Actions"; + + enableDELETE() { + + this.show(); + + } + + disableDELETE() { + + this.hide(); + + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/user/userList/header/user.userList.header.js b/application/user/userList/header/user.userList.header.js new file mode 100644 index 0000000..d5e2807 --- /dev/null +++ b/application/user/userList/header/user.userList.header.js @@ -0,0 +1,18 @@ + + +import user from '/user/user.js'; + +import username from './user.userList.header.username.js'; + +import actions from './user.userList.header.actions.js'; + +import gridViewRow from '/elements/gridView/gridView.header.row.js'; + + +export default class userListHeader extends user, gridViewRow { + + username = new username(); + + actions = new actions(); + +} \ No newline at end of file diff --git a/application/user/userList/header/user.userList.header.username.js b/application/user/userList/header/user.userList.header.username.js new file mode 100644 index 0000000..50c39c1 --- /dev/null +++ b/application/user/userList/header/user.userList.header.username.js @@ -0,0 +1,10 @@ + + +import gridViewColumn from '/elements/gridView/gridView.header.row.column.js'; + + +export default class userListHeaderUsername extends gridViewColumn{ + + text = "Username"; + +} \ No newline at end of file diff --git a/application/user/userList/item/user.userList.item.actions.deleteButton.js b/application/user/userList/item/user.userList.item.actions.deleteButton.js new file mode 100644 index 0000000..7b47fcc --- /dev/null +++ b/application/user/userList/item/user.userList.item.actions.deleteButton.js @@ -0,0 +1,32 @@ + +import button from "/elements/button.js"; + +import groups from '/user/group/user.group.permission.js'; + +export default class deleteButton extends button { + + text = "Delete"; + + propegateEvent = false; + + + async click() { + + var sure = confirm("Are you sure you want to delete this item"); + + if( sure ) { + + await this.parent.parent.delete(); + + this.parent.parent.remove(); + + } + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/user/userList/item/user.userList.item.actions.js b/application/user/userList/item/user.userList.item.actions.js new file mode 100644 index 0000000..ee7efff --- /dev/null +++ b/application/user/userList/item/user.userList.item.actions.js @@ -0,0 +1,23 @@ + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + +import deleteButton from "./user.userList.item.actions.deleteButton.js" + + +export default class userListItemActions extends gridViewColumn, gridViewColumn{ + + useCustomElement = false; + + padding = 20; + + display = "table-cell"; + + layers = 1; + + paddingLeft = 30; + + borderRadius; + + deleteButton = new deleteButton(); + +} \ No newline at end of file diff --git a/application/user/userList/item/user.userList.item.js b/application/user/userList/item/user.userList.item.js new file mode 100644 index 0000000..9084725 --- /dev/null +++ b/application/user/userList/item/user.userList.item.js @@ -0,0 +1,96 @@ +import user from '/user/user.js'; + +import username from './user.userList.item.username.js'; + +import actions from './user.userList.item.actions.js'; + +import groups from '/user/group/user.group.permission.js'; + +import gridViewRow from '/elements/gridView/gridView.body.row.js'; + + + +export default class userListItem extends user, gridViewRow { + + username = new username(); + + actions = new actions(); + + cursor = "pointer"; + + background; + + #ifdef MACOS + + fontSize = 14; + + #endif + + + #ifdef DARK + + mouseHoverColor = "#363333"; + + #endif + + #ifdef LIGHT + + mouseHoverColor = "rgb(255 255 255 / 95%)"; + + #endif + + async click() { + + this.stateMachine.composeState( "User", this.id ); + + await this.loadPage( this.id ); + + } + + state async loadPage( id ) { + + var rightSide = this.parents("rightSide"); + + rightSide.hideChildren(); + + var editUser = rightSide.editUser; + + editUser.id = this.id; + + editUser.show(); + + await editUser.sync(); + + } + + mouseover() { + + this.background = this.mouseHoverColor; + + } + + mouseleave() { + + this.background = "none"; + + } + + enableDELETE() { + + this.actions.show(); + + } + + disableDELETE() { + + this.actions.hide(); + + } + + permission() { + + this.allow( groups.admin, "DELETE" ); + + } + +} \ No newline at end of file diff --git a/application/user/userList/item/user.userList.item.username.js b/application/user/userList/item/user.userList.item.username.js new file mode 100644 index 0000000..4b923e5 --- /dev/null +++ b/application/user/userList/item/user.userList.item.username.js @@ -0,0 +1,12 @@ + + +import userName from '/user/user.username.js'; + +import gridViewColumn from '/elements/gridView/gridView.body.row.column.js'; + + +export default class userListItemTitle extends userName, gridViewColumn{ + + + +} \ No newline at end of file diff --git a/application/user/userList/search.js b/application/user/userList/search.js new file mode 100644 index 0000000..3e9f5fd --- /dev/null +++ b/application/user/userList/search.js @@ -0,0 +1,31 @@ + +import input from "/elements/input.js"; + + + + +export default class searchBar extends input { + + placeholder = "Search." + + placeholderColor = "#8e8e8e" + + webkitTextFillColor = "none"; + + async keyup( event ) { + + this.value = this.customElement.value; + + var value = this.value; + + console.log("search input", value); + + var newsItems = this.parent.userTable.body; + + newsItems.value = value; + + newsItems.sync(); + + } + +} \ No newline at end of file diff --git a/application/user/userList/user.userList.page.js b/application/user/userList/user.userList.page.js new file mode 100644 index 0000000..411b096 --- /dev/null +++ b/application/user/userList/user.userList.page.js @@ -0,0 +1,24 @@ + +import header from '/elements/header.js'; + +import userTable from './user.userList.table.js'; + +import search from './search.js'; + +import page from '/elements/page.js'; + + + +export default class editPage extends page { + + header = new header("Users"); + + search = new search(); + + userTable = new userTable(); + + + flexDirection = "column" + + +} \ No newline at end of file diff --git a/application/user/userList/user.userList.table.body.js b/application/user/userList/user.userList.table.body.js new file mode 100644 index 0000000..cef8f1f --- /dev/null +++ b/application/user/userList/user.userList.table.body.js @@ -0,0 +1,50 @@ + + +import renderCollection from '/unify/renderCollection.js'; + +import groups from '/user/group/user.group.permission.js'; + +import gridViewBody from '/elements/gridView/gridView.body.js'; + +import OR from '/unify/sql/OR.js'; + +import AND from '/unify/sql/AND.js'; + +import LIKE from '/unify/sql/LIKE.js'; + + +export default class userListTableBody extends renderCollection, gridViewBody { + + debug = true; + + + + async create() { + + await this.sync(); + + } + + preprocess( object ) { + + var filter = object.getFilter(); + + filter.search = LIKE( filter.username, this.value ); + + //filter.search = OR( LIKE( filter.title, this.value ), LIKE( filter.body, this.value ) ); + + filter.direction = "desc"; + + } + + permission() { + + this.allow( groups.visitor, "READ" ); + + this.allow( groups.member, "READ" ); + + this.allow( groups.admin, "READ" ); + + } + +} \ No newline at end of file diff --git a/application/user/userList/user.userList.table.header.js b/application/user/userList/user.userList.table.header.js new file mode 100644 index 0000000..0c17aa6 --- /dev/null +++ b/application/user/userList/user.userList.table.header.js @@ -0,0 +1,13 @@ + +import userListHeaderRow from "./header/user.userList.header.js"; + +import document from '/unify/document.js'; + +import gridViewHeader from '/elements/gridView/gridView.header.js'; + + +export default class userListTableHeader extends gridViewHeader { + + userListHeaderRow = new userListHeaderRow(); + +} \ No newline at end of file diff --git a/application/user/userList/user.userList.table.js b/application/user/userList/user.userList.table.js new file mode 100644 index 0000000..3738b5c --- /dev/null +++ b/application/user/userList/user.userList.table.js @@ -0,0 +1,23 @@ + + +import userListTableHeader from "./user.userList.table.header.js"; + +import userListTableBody from "./user.userList.table.body.js"; + +import collection from '/unify/collection.js'; + +import userListItem from '../userList/item/user.userList.item.js'; + +import user from '/user/user.js'; + +import gridView from '/elements/gridView/gridView.js'; + + + +export default class userListTable extends gridView{ + + header = new userListTableHeader(); + + body = new userListTableBody( userListItem, new collection( user ) ); + +} \ No newline at end of file diff --git a/assets/bundle.js b/assets/bundle.js new file mode 100644 index 0000000..410a7e0 --- /dev/null +++ b/assets/bundle.js @@ -0,0 +1,248073 @@ +var __defProp = Object.defineProperty; +var __name = (target, value2) => __defProp(target, "name", { value: value2, configurable: true }); + +// framework/unify/document.js +var documentTool = class { + static { + __name(this, "documentTool"); + } + createElementDummy(object93) { + object93.createElement = function(tag) { + var object94 = new Object(); + object94.tag = tag; + return false; + }; + } + createElementNSDummy(object93) { + object93.createElementNS = function(tag) { + var object94 = new Object(); + object94.tag = tag; + return false; + }; + } + createDummyDomMethods(object93) { + this.createElementDummy(object93); + this.createElementNSDummy(object93); + } + bindCustomStyleTerms(object93) { + object93.customStyleTerms = ["background", "width", "height", "flexDirection", "color", "border", "margin", "padding", "boxBackground"]; + } + addBoxProperties(object93) { + for (var c31 = 0; c31 < object93.customStyleTerms.length; c31++) { + object93.customStyleTerms[object93.customStyleTerms[c31]] = ""; + object93.customStyleTerms["box" + this.CamelCase(object93.customStyleTerms[c31])] = ""; + } + } + createCustomStyleTerms(object93) { + this.bindCustomStyleTerms(object93); + this.addBoxProperties(object93); + } + getDocument() { + if (typeof document == "undefined") { + var object93 = new Object(); + this.createDummyDomMethods(object93); + this.createCustomStyleTerms(object93); + this.type = "server"; + return object93; + } else { + document.type = "client"; + return document; + } + } + CamelCase(string) { + if (string) { + string = string.toUpperCase(); + string = string[0].toUpperCase() + string.slice(1, string.lenth).toLowerCase(); + return string; + } + } +}; +var object2 = new documentTool(); +var document_default = object2.getDocument(); + +// framework/client/cssRules.js +var cssRules = class { + static { + __name(this, "cssRules"); + } + style = ""; + styleTypes = new Array(); + addStyleListener(propertyTerm, cssSuffix) { + var styleType = new Object(); + styleType.propertyTerm = propertyTerm; + styleType.cssSuffix = cssSuffix; + styleType.css = ""; + this.styleTypes.push(styleType); + } +}; + +// framework/client/cssManager.js +var cssManager = class { + static { + __name(this, "cssManager"); + } + rules = new Array(); + addRule(selector, body61) { + var rule = new Object(); + rule.selector = selector; + rule.body = body61; + this.rules[selector] = body61; + } + composeCss(selector, body61) { + if (body61 == "") { + return ""; + } + return "\n" + selector + "{ \n" + body61 + "\n } \n"; + } + getRule(selector, body61) { + selector = tools_default.cleanRollup(selector); + if (this.rules[selector]) { + return ""; + } else { + this.addRule(selector, body61); + return this.composeCss(selector, body61); + } + } +}; + +// framework/unify/definitions.js +var definitions = class { + static { + __name(this, "definitions"); + } + css = JSON.parse('{"accentColor":"","additiveSymbols":"","alignContent":"","alignItems":"","alignSelf":"","alignmentBaseline":"","all":"","animation":"","animationDelay":"","animationDirection":"","animationDuration":"","animationFillMode":"","animationIterationCount":"","animationName":"","animationPlayState":"","animationTimingFunction":"","appRegion":"","appearance":"","ascentOverride":"","aspectRatio":"","backdropFilter":"","backfaceVisibility":"","background":"","backgroundAttachment":"","backgroundBlendMode":"","backgroundClip":"","backgroundColor":"","backgroundImage":"","backgroundOrigin":"","backgroundPosition":"","backgroundPositionX":"","backgroundPositionY":"","backgroundRepeat":"","backgroundRepeatX":"","backgroundRepeatY":"","backgroundSize":"","baselineShift":"","blockSize":"","border":"","borderBlock":"","borderBlockColor":"","borderBlockEnd":"","borderBlockEndColor":"","borderBlockEndStyle":"","borderBlockEndWidth":"","borderBlockStart":"","borderBlockStartColor":"","borderBlockStartStyle":"","borderBlockStartWidth":"","borderBlockStyle":"","borderBlockWidth":"","borderBottom":"","borderBottomColor":"","borderBottomLeftRadius":"","borderBottomRightRadius":"","borderBottomStyle":"","borderBottomWidth":"","borderCollapse":"","borderColor":"","borderEndEndRadius":"","borderEndStartRadius":"","borderImage":"","borderImageOutset":"","borderImageRepeat":"","borderImageSlice":"","borderImageSource":"","borderImageWidth":"","borderInline":"","borderInlineColor":"","borderInlineEnd":"","borderInlineEndColor":"","borderInlineEndStyle":"","borderInlineEndWidth":"","borderInlineStart":"","borderInlineStartColor":"","borderInlineStartStyle":"","borderInlineStartWidth":"","borderInlineStyle":"","borderInlineWidth":"","borderLeft":"","borderLeftColor":"","borderLeftStyle":"","borderLeftWidth":"","borderRadius":"","borderRight":"","borderRightColor":"","borderRightStyle":"","borderRightWidth":"","borderSpacing":"","borderStartEndRadius":"","borderStartStartRadius":"","borderStyle":"","borderTop":"","borderTopColor":"","borderTopLeftRadius":"","borderTopRightRadius":"","borderTopStyle":"","borderTopWidth":"","borderWidth":"","bottom":"","boxShadow":"","boxSizing":"","breakAfter":"","breakBefore":"","breakInside":"","bufferedRendering":"","captionSide":"","caretColor":"","clear":"","clip":"","clipPath":"","clipRule":"","color":"","colorInterpolation":"","colorInterpolationFilters":"","colorRendering":"","colorScheme":"","columnCount":"","columnFill":"","columnGap":"","columnRule":"","columnRuleColor":"","columnRuleStyle":"","columnRuleWidth":"","columnSpan":"","columnWidth":"","columns":"","contain":"","containIntrinsicBlockSize":"","containIntrinsicHeight":"","containIntrinsicInlineSize":"","containIntrinsicSize":"","containIntrinsicWidth":"","content":"","contentVisibility":"","counterIncrement":"","counterReset":"","counterSet":"","cursor":"","cx":"","cy":"","d":"","descentOverride":"","direction":"","display":"","dominantBaseline":"","emptyCells":"","fallback":"","fill":"","fillOpacity":"","fillRule":"","filter":"","flex":"","flexBasis":"","flexDirection":"","flexFlow":"","flexGrow":"","flexShrink":"","flexWrap":"","float":"","floodColor":"","floodOpacity":"","font":"","fontDisplay":"","fontFamily":"","fontFeatureSettings":"","fontKerning":"","fontOpticalSizing":"","fontSize":"","fontStretch":"","fontStyle":"","fontSynthesis":"","fontSynthesisSmallCaps":"","fontSynthesisStyle":"","fontSynthesisWeight":"","fontVariant":"","fontVariantCaps":"","fontVariantEastAsian":"","fontVariantLigatures":"","fontVariantNumeric":"","fontVariationSettings":"","fontWeight":"","forcedColorAdjust":"","gap":"","grid":"","gridArea":"","gridAutoColumns":"","gridAutoFlow":"","gridAutoRows":"","gridColumn":"","gridColumnEnd":"","gridColumnGap":"","gridColumnStart":"","gridGap":"","gridRow":"","gridRowEnd":"","gridRowGap":"","gridRowStart":"","gridTemplate":"","gridTemplateAreas":"","gridTemplateColumns":"","gridTemplateRows":"","height":"","hyphens":"","imageOrientation":"","imageRendering":"","inherits":"","initialValue":"","inlineSize":"","inset":"","insetBlock":"","insetBlockEnd":"","insetBlockStart":"","insetInline":"","insetInlineEnd":"","insetInlineStart":"","isolation":"","justifyContent":"","justifyItems":"","justifySelf":"","left":"","letterSpacing":"","lightingColor":"","lineBreak":"","lineGapOverride":"","lineHeight":"","listStyle":"","listStyleImage":"","listStylePosition":"","listStyleType":"","margin":"","marginBlock":"","marginBlockEnd":"","marginBlockStart":"","marginBottom":"","marginInline":"","marginInlineEnd":"","marginInlineStart":"","marginLeft":"","marginRight":"","marginTop":"","marker":"","markerEnd":"","markerMid":"","markerStart":"","mask":"","maskType":"","maxBlockSize":"","maxHeight":"","maxInlineSize":"","maxWidth":"","maxZoom":"","minBlockSize":"","minHeight":"","minInlineSize":"","minWidth":"","minZoom":"","mixBlendMode":"","negative":"","objectFit":"","objectPosition":"","offset":"","offsetDistance":"","offsetPath":"","offsetRotate":"","opacity":"","order":"","orientation":"","orphans":"","outline":"","outlineColor":"","outlineOffset":"","outlineStyle":"","outlineWidth":"","overflow":"","overflowAnchor":"","overflowClipMargin":"","overflowWrap":"","overflowX":"","overflowY":"","overscrollBehavior":"","overscrollBehaviorBlock":"","overscrollBehaviorInline":"","overscrollBehaviorX":"","overscrollBehaviorY":"","pad":"","padding":"","paddingBlock":"","paddingBlockEnd":"","paddingBlockStart":"","paddingBottom":"","paddingInline":"","paddingInlineEnd":"","paddingInlineStart":"","paddingLeft":"","paddingRight":"","paddingTop":"","page":"","pageBreakAfter":"","pageBreakBefore":"","pageBreakInside":"","pageOrientation":"","paintOrder":"","perspective":"","perspectiveOrigin":"","placeContent":"","placeItems":"","placeSelf":"","pointerEvents":"","position":"","prefix":"","quotes":"","r":"","range":"","resize":"","right":"","rowGap":"","rubyPosition":"","rx":"","ry":"","scrollBehavior":"","scrollMargin":"","scrollMarginBlock":"","scrollMarginBlockEnd":"","scrollMarginBlockStart":"","scrollMarginBottom":"","scrollMarginInline":"","scrollMarginInlineEnd":"","scrollMarginInlineStart":"","scrollMarginLeft":"","scrollMarginRight":"","scrollMarginTop":"","scrollPadding":"","scrollPaddingBlock":"","scrollPaddingBlockEnd":"","scrollPaddingBlockStart":"","scrollPaddingBottom":"","scrollPaddingInline":"","scrollPaddingInlineEnd":"","scrollPaddingInlineStart":"","scrollPaddingLeft":"","scrollPaddingRight":"","scrollPaddingTop":"","scrollSnapAlign":"","scrollSnapStop":"","scrollSnapType":"","scrollbarGutter":"","shapeImageThreshold":"","shapeMargin":"","shapeOutside":"","shapeRendering":"","size":"","sizeAdjust":"","speak":"","speakAs":"","src":"","stopColor":"","stopOpacity":"","stroke":"","strokeDasharray":"","strokeDashoffset":"","strokeLinecap":"","strokeLinejoin":"","strokeMiterlimit":"","strokeOpacity":"","strokeWidth":"","suffix":"","symbols":"","syntax":"","system":"","tabSize":"","tableLayout":"","textAlign":"","textAlignLast":"","textAnchor":"","textCombineUpright":"","textDecoration":"","textDecorationColor":"","textDecorationLine":"","textDecorationSkipInk":"","textDecorationStyle":"","textDecorationThickness":"","textIndent":"","textOrientation":"","textOverflow":"","textRendering":"","textShadow":"","textSizeAdjust":"","textTransform":"","textUnderlineOffset":"","textUnderlinePosition":"","top":"","touchAction":"","transform":"","transformBox":"","transformOrigin":"","transformStyle":"","transition":"","transitionDelay":"","transitionDuration":"","transitionProperty":"","transitionTimingFunction":"","unicodeBidi":"","unicodeRange":"","userSelect":"","userZoom":"","vectorEffect":"","verticalAlign":"","visibility":"","webkitAlignContent":"","webkitAlignItems":"","webkitAlignSelf":"","webkitAnimation":"","webkitAnimationDelay":"","webkitAnimationDirection":"","webkitAnimationDuration":"","webkitAnimationFillMode":"","webkitAnimationIterationCount":"","webkitAnimationName":"","webkitAnimationPlayState":"","webkitAnimationTimingFunction":"","webkitAppRegion":"","webkitAppearance":"","webkitBackfaceVisibility":"","webkitBackgroundClip":"","webkitBackgroundOrigin":"","webkitBackgroundSize":"","webkitBorderAfter":"","webkitBorderAfterColor":"","webkitBorderAfterStyle":"","webkitBorderAfterWidth":"","webkitBorderBefore":"","webkitBorderBeforeColor":"","webkitBorderBeforeStyle":"","webkitBorderBeforeWidth":"","webkitBorderBottomLeftRadius":"","webkitBorderBottomRightRadius":"","webkitBorderEnd":"","webkitBorderEndColor":"","webkitBorderEndStyle":"","webkitBorderEndWidth":"","webkitBorderHorizontalSpacing":"","webkitBorderImage":"","webkitBorderRadius":"","webkitBorderStart":"","webkitBorderStartColor":"","webkitBorderStartStyle":"","webkitBorderStartWidth":"","webkitBorderTopLeftRadius":"","webkitBorderTopRightRadius":"","webkitBorderVerticalSpacing":"","webkitBoxAlign":"","webkitBoxDecorationBreak":"","webkitBoxDirection":"","webkitBoxFlex":"","webkitBoxOrdinalGroup":"","webkitBoxOrient":"","webkitBoxPack":"","webkitBoxReflect":"","webkitBoxShadow":"","webkitBoxSizing":"","webkitClipPath":"","webkitColumnBreakAfter":"","webkitColumnBreakBefore":"","webkitColumnBreakInside":"","webkitColumnCount":"","webkitColumnGap":"","webkitColumnRule":"","webkitColumnRuleColor":"","webkitColumnRuleStyle":"","webkitColumnRuleWidth":"","webkitColumnSpan":"","webkitColumnWidth":"","webkitColumns":"","webkitFilter":"","webkitFlex":"","webkitFlexBasis":"","webkitFlexDirection":"","webkitFlexFlow":"","webkitFlexGrow":"","webkitFlexShrink":"","webkitFlexWrap":"","webkitFontFeatureSettings":"","webkitFontSmoothing":"","webkitHighlight":"","webkitHyphenateCharacter":"","webkitJustifyContent":"","webkitLineBreak":"","webkitLineClamp":"","webkitLocale":"","webkitLogicalHeight":"","webkitLogicalWidth":"","webkitMarginAfter":"","webkitMarginBefore":"","webkitMarginEnd":"","webkitMarginStart":"","webkitMask":"","webkitMaskBoxImage":"","webkitMaskBoxImageOutset":"","webkitMaskBoxImageRepeat":"","webkitMaskBoxImageSlice":"","webkitMaskBoxImageSource":"","webkitMaskBoxImageWidth":"","webkitMaskClip":"","webkitMaskComposite":"","webkitMaskImage":"","webkitMaskOrigin":"","webkitMaskPosition":"","webkitMaskPositionX":"","webkitMaskPositionY":"","webkitMaskRepeat":"","webkitMaskRepeatX":"","webkitMaskRepeatY":"","webkitMaskSize":"","webkitMaxLogicalHeight":"","webkitMaxLogicalWidth":"","webkitMinLogicalHeight":"","webkitMinLogicalWidth":"","webkitOpacity":"","webkitOrder":"","webkitPaddingAfter":"","webkitPaddingBefore":"","webkitPaddingEnd":"","webkitPaddingStart":"","webkitPerspective":"","webkitPerspectiveOrigin":"","webkitPerspectiveOriginX":"","webkitPerspectiveOriginY":"","webkitPrintColorAdjust":"","webkitRtlOrdering":"","webkitRubyPosition":"","webkitShapeImageThreshold":"","webkitShapeMargin":"","webkitShapeOutside":"","webkitTapHighlightColor":"","webkitTextCombine":"","webkitTextDecorationsInEffect":"","webkitTextEmphasis":"","webkitTextEmphasisColor":"","webkitTextEmphasisPosition":"","webkitTextEmphasisStyle":"","webkitTextFillColor":"","webkitTextOrientation":"","webkitTextSecurity":"","webkitTextSizeAdjust":"","webkitTextStroke":"","webkitTextStrokeColor":"","webkitTextStrokeWidth":"","webkitTransform":"","webkitTransformOrigin":"","webkitTransformOriginX":"","webkitTransformOriginY":"","webkitTransformOriginZ":"","webkitTransformStyle":"","webkitTransition":"","webkitTransitionDelay":"","webkitTransitionDuration":"","webkitTransitionProperty":"","webkitTransitionTimingFunction":"","webkitUserDrag":"","webkitUserModify":"","webkitUserSelect":"","webkitWritingMode":"","whiteSpace":"","widows":"","width":"","willChange":"","wordBreak":"","wordSpacing":"","wordWrap":"","writingMode":"","x":"","y":"","zIndex":"","zoom":""}'); + alphabet = new Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"); + browserEvents = new Array("screenchange", "fullscreenerror", "webkitfullscreenchange", "webkitfullscreenerror", "beforexrselect", "abort", "blur", "cancel", "canplay", "canplaythrough", "change", "click", "close", "contextmenu", "cuechange", "dblclick", "drag", "dragend", "dragenter", "dragleave", "dragover", "dragstart", "drop", "durationchange", "emptied", "ended", "error", "focus", "formdata", "input", "invalid", "keydown", "keypress", "keyup", "load", "loadeddata", "loadedmetadata", "loadstart", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mousewheel", "pause", "play", "playing", "progress", "ratechange", "reset", "resize", "scroll", "securitypolicyviolation", "seeked", "seeking", "select", "slotchange", "stalled", "submit", "suspend", "timeupdate", "toggle", "volumechange", "waiting", "webkitanimationend", "webkitanimationiteration", "webkitanimationstart", "webkittransitionend", "wheel", "auxclick", "gotpointercapture", "lostpointercapture", "pointerdown", "pointermove", "pointerup", "pointercancel", "pointerover", "pointerout", "pointerenter", "pointerleave", "selectstart", "selectionchange", "animationend", "animationiteration", "animationstart", "transitionrun", "transitionstart", "transitionend", "transitioncancel", "copy", "cut", "paste", "contextlost", "contextrestored", "pointerrawupdate"); + invalid = new Array("display", "__display", "propertyName", "__text", "text", "__sourcePath", "os", "tint", "device", "__os", "__device", "__tint"); +}; +var definitions_default = new definitions(); + +// framework/client/css.js +var css = class { + static { + __name(this, "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(property2) { + for (var i = 0; i < this.skipBoxTerms.length; i++) { + if (this.boxTermWithoutPrefix[i].includes(property2)) { + property2 = this.skipBoxTerms[i]; + } + } + return property2; + } + parseObject(object93) { + var objectName = object93.propertyName; + object93.css = new cssRules(); + object93.boxRules = new cssRules(); + object93.cssRules = new cssRules(); + object93.cssRules.addStyleListener("hover", ":hover"); + object93.cssRules.addStyleListener("visited", ":visited"); + object93.cssRules.addStyleListener("link", ":link"); + object93.cssRules.addStyleListener("active", ":active"); + object93.cssRules.addStyleListener("placeholder", "::placeholder"); + object93.cssRules.addStyleListener("scrollbar", "::-webkit-scrollbar"); + object93.cssRules.addStyleListener("scrollbarTrack", "::-webkit-scrollbar-track"); + object93.cssRules.addStyleListener("scrollbarThumb", "::-webkit-scrollbar-thumb"); + object93.cssRules.addStyleListener("scrollbarThumbHover", "::-webkit-scrollbar-thumb:hover"); + } + parseCSSValue(value2) { + if (typeof value2 == "number") { + value2 += "px"; + } + return value2; + } + createStyleRule(normalizedProperty, value2) { + if (!value2) { + return ""; + } + value2 = this.parseCSSValue(value2); + normalizedProperty = this.PerformPropertyGridCorrection(normalizedProperty); + return " " + normalizedProperty + ":" + value2 + "; \n"; + } + compareUpperCase(term) { + const compare = /* @__PURE__ */ __name(function(current) { + if (term.indexOf(current) != -1) { + return true; + } + }, "compare"); + const n = definitions_default.alphabet; + var map = n.map(compare); + return map; + } + hasUpperCase(a32) { + let regExp = /[A-Z]/; + return regExp.test(a32); + } + replaceUpperCase(word) { + var map = this.compareUpperCase(word); + var letter = definitions_default.alphabet[map.indexOf(true)]; + return word.replace(letter, "-" + letter.toLowerCase()); + } + normalizePropertyName(name) { + return tools_default.firstLowerCase(name.replace("__", "").replace("box", "")); + } + // needs caching + normalizeProperty(name) { + if (name.slice(0, 6) == "webkit") { + name = "-" + name; + } + for (var i = 0; i < 6; i++) { + if (this.hasUpperCase(name)) { + name = this.replaceUpperCase(name); + } + } + return name; + } + setter(object93, domStyleObject, propertyName2, property2, value2) { + object93["__" + propertyName2] = value2; + value2 = this.parseCSSValue(value2); + property2 = this.PerformPropertyGridCorrection(property2); + var NSTabNames = new Array("svg", "circle"); + domStyleObject.setProperty(property2, value2); + } + createSetter(property2, objectProperty, object93, domStyleObject) { + var css2 = this; + object93["__" + objectProperty] = object93[objectProperty]; + object93.__defineSetter__(objectProperty, this.setter.bind(this, object93, domStyleObject, objectProperty, property2)); + } + getter(object93, objectProperty, value2) { + var newValue = object93["__" + 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_default.isCustomNumber(newValue)) { + return parseFloat(newValue); + } else { + return newValue; + } + } + createGetter(property2, objectProperty, object93, domStyleObject) { + object93.__defineGetter__(objectProperty, this.getter.bind(this, object93, objectProperty)); + } + parseProperty(property2, object93) { + var propertyName2 = property2.name; + var propertyValue = property2.value; + var normalizedProperty = this.normalizeProperty(propertyName2); + var slicedProperty = propertyName2.toLowerCase().slice(0, 3); + if (slicedProperty == "box") { + object93.boxRules.style += this.parseCssTerm(object93, propertyName2, propertyValue, object93.elements[0], "box"); + } else { + object93.css.style += this.parseCssTerm(object93, propertyName2, propertyValue, object93.element); + } + this.parseExtraStyleSuffixes(object93, propertyName2, propertyValue); + } + parseExtraStyleSuffixes(object93, propertyName2, propertyValue) { + var styleTypes = object93.cssRules.styleTypes; + for (var i = 0; i < styleTypes.length; i++) { + var cssType = styleTypes[i]; + var propertyTerm = cssType.propertyTerm; + var slicedProperty = propertyName2.slice(0, propertyTerm.length); + if (slicedProperty == propertyTerm && propertyName2.length > slicedProperty.length) { + cssType.css += this.parseCssTerm(object93, propertyName2, propertyValue, object93.elements[0], propertyTerm); + } + } + } + parseCssTerm(object93, propertyName2, propertyValue, element2, term = "") { + var cssPropertyName = tools_default.firstLowerCase(propertyName2.replace(term, "")); + var normalizedProperty = this.normalizeProperty(cssPropertyName); + if (this.propertyIsStyle(normalizedProperty)) { + if (!term || term == "box") { + this.createSetter(normalizedProperty, propertyName2, object93, element2.style); + this.createGetter(normalizedProperty, propertyName2, object93, element2.style); + } + return this.createStyleRule(normalizedProperty, propertyValue); + } else { + return ""; + } + } + clearCache() { + this.cssCache.rules = new Array(); + } + parseCssRule(object93, objectPropertyName, propertyName2, propertyValue) { + var normalizedProperty = this.normalizeProperty(objectPropertyName); + object93.boxRules.style += this.createStyleRule(normalizedProperty, propertyValue); + this.createSetter(objectPropertyName, propertyName2, object93, object93.elements[0].style); + this.createGetter(objectPropertyName, propertyName2, object93, object93.elements[0].style); + } + createSelector(className2, afterTerm) { + var selector = "." + className2; + selector += "." + this.device; + selector += "." + this.os; + selector += "." + this.tint; + if (afterTerm) { + selector += afterTerm; + } + return selector; + } + createStyleSheet(object93) { + var objectName = tools_default.createCSSClassName(object93); + var body61 = object93.css.style; + if (object93.customElement) { + var selector = this.createSelector(objectName + "Element"); + this.global_css += this.cssCache.getRule(selector, body61); + var selector = this.createSelector(objectName + "Grid"); + this.global_css += this.cssCache.getRule(selector, body61); + } else { + var selector = this.createSelector(objectName + "Grid"); + this.global_css += this.cssCache.getRule(selector, body61); + } + if (object93.boxRules) { + var selector = this.createSelector(objectName + "Box"); + var body61 = object93.boxRules.style; + this.global_css += this.cssCache.getRule(selector, body61); + } + var styleTypes = object93.cssRules.styleTypes; + for (var i = 0; i < styleTypes.length; i++) { + var cssType = styleTypes[i]; + if (object93.useCustomElement) { + var selector = this.createSelector(objectName + "Element", cssType.cssSuffix); + } else { + var selector = this.createSelector(objectName + "Grid", cssType.cssSuffix); + } + var body61 = cssType.css; + if (body61 != "") { + this.global_css += this.cssCache.getRule(selector, body61); + } + } + if (!object93.parent) { + this.writeCssToPage(this.global_css); + this.global_css = ""; + } + if (object93.dynamic) { + this.writeCssToPage(this.global_css); + this.global_css = ""; + } + } + writeCssToPage(css2) { + if (css2 == "") { + return false; + } + var style = document_default.createElement("style"); + style.innerHTML = css2; + document_default.head.appendChild(style); + } + removeStripe(name) { + var splitName = name.split("-"); + if (splitName.length > 1) { + return splitName[1].toLowerCase(); + } else { + return name; + } + } + getStyleSheetObject() { + if (!document_default.body) { + return definitions_default.css; + return object; + } + if (document_default.body.style) { + var bodyStyle = document_default.body.style; + bodyStyle.webkitBoxShadow = ""; + return bodyStyle; + } + if (document_default.body.styleSheets) { + return document_default.styleSheets[1].cssRules[0].style; + } else { + return document_default.customStyleTerms; + } + } + camelCaseToDash(name) { + for (var i = 0; i < 4; i++) { + if (this.hasUpperCase(name)) { + name = this.replaceUpperCase(name); + } + } + 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_default.css); + if (styleTerms.includes(name.toLowerCase())) { + return true; + } else { + return false; + } + } +}; + +// framework/unify/math/vector2.js +var vector2 = class { + static { + __name(this, "vector2"); + } + constructor(x, y) { + this.x = x; + this.y = y; + } + x = 0; + y = 0; +}; + +// framework/unify/consoleColors.js +var consoleColors = class { + static { + __name(this, "consoleColors"); + } + colors = new Array(); + backgroundColors = new Array(); + addColor(colorName, colorCode) { + var color = new Object(); + color.name = colorName; + color.code = colorCode; + this.colors.push(color); + } + addBackgroundColor(colorName, colorCode) { + var color = new Object(); + color.name = colorName; + color.code = colorCode; + this.backgroundColors.push(color); + } + constructor() { + this.createTextColors(); + this.createBackgroundColors(); + return this.createMethods(); + } + createTextColors() { + this.addColor("white", 37); + this.addColor("black", 30); + this.addColor("blue", 34); + this.addColor("cyan", 36); + this.addColor("green", 32); + this.addColor("magenta", 35); + this.addColor("red", 31); + this.addColor("yellow", 33); + this.addColor("brightBlack", 90); + this.addColor("brightRed", 91); + this.addColor("brightGreen", 92); + this.addColor("brightYellow", 93); + this.addColor("brightBlue", 94); + this.addColor("brightMagenta", 95); + this.addColor("brightCyan", 96); + this.addColor("brightWhite", 97); + } + createBackgroundColors() { + this.addBackgroundColor("bgBlack", 40); + this.addBackgroundColor("bgRed", 41); + this.addBackgroundColor("bgGreen", 42); + this.addBackgroundColor("bgYellow", 43); + this.addBackgroundColor("bgBlue", 44); + this.addBackgroundColor("bgMagenta", 45); + this.addBackgroundColor("bgCyan", 46); + this.addBackgroundColor("bgWhite", 47); + this.addBackgroundColor("bgBrightBlack", 100); + this.addBackgroundColor("bgBrightRed", 101); + this.addBackgroundColor("bgBrightGreen", 102); + this.addBackgroundColor("bgBrightYellow", 103); + this.addBackgroundColor("bgBrightBlue", 104); + this.addBackgroundColor("bgBrightMagenta", 105); + this.addBackgroundColor("bgBrightCyan", 106); + this.addBackgroundColor("bgBrightWhite", 107); + } + createMethodsForTextColor(color, colorMethods) { + var name = color.name; + var code = color.code; + var open = "\x1B[" + code + "m"; + var close = "\x1B[39m"; + colorMethods[name] = function(value2) { + return open + value2 + close; + }; + } + createMethodsForBackgroundColor(color, colorMethods) { + var name = color.name; + var code = color.code; + var open = "\x1B[" + code + "m"; + var close = "\x1B[49m"; + colorMethods[name] = function(value2) { + return open + value2 + close; + }; + } + createMethods() { + var colors = this.colors; + var colorMethods = new Array(); + for (var i = 0; i < colors.length; i++) { + var textColor = colors[i]; + this.createMethodsForTextColor(textColor, colorMethods); + } + var backgroundColors = this.backgroundColors; + for (var i = 0; i < backgroundColors.length; i++) { + var backgroundColor = backgroundColors[i]; + this.createMethodsForBackgroundColor(backgroundColor, colorMethods); + } + return colorMethods; + } +}; +var consoleColors_default = new consoleColors(); + +// framework/unify/tools.js +var tools2 = class { + static { + __name(this, "tools"); + } + css = new css(); + isUnifyObject(propertyName2, propertyValue) { + const rejectClassNames = new Array("core", "cssRules", "stateMachine", "socketManager", "animationManager", "permissionManager", "permissionObject", "fileLoader", "WriteStream", "client"); + const rejectPropertyNames = new Array("objectToManipulate", "parent", "client", "queryRoot", "queryChildren", "queryCount"); + if (propertyValue && typeof propertyValue.parseUnify == "boolean" && propertyValue.parseUnify == false) { + return false; + } + if (propertyValue == null) { + return false; + } + if (!propertyValue) { + return false; + } + var className2 = this.getClassName(propertyValue); + if (rejectPropertyNames.includes(propertyName2)) { + return false; + } + if (rejectClassNames.includes(className2)) { + return false; + } + if (Array.isArray(propertyValue)) { + return false; + } + if (this.getEnvironment() == "Browser") { + if (propertyValue instanceof HTMLElement) { + return false; + } + } + if (typeof propertyValue == "object") { + return true; + } else { + return false; + } + } + reverseString(string) { + var splitString = string.split(""); + var reverseArray = splitString.reverse(); + var joinArray = reverseArray.join(""); + return joinArray; + } + slash(path2) { + const isExtendedLengthPath = /^\\\\\?\\/.test(path2); + if (isExtendedLengthPath) { + return path2; + } + return path2.replace(/\\/g, "/"); + } + serializeString(json) { + if (Buffer.isBuffer(json)) { + return json.toString(); + } else { + return json; + } + } + isJsonString(str) { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; + } + serializeJSON(json) { + if (this.isJsonString(json)) { + return JSON.parse(json); + } + } + createOrderedArray(array) { + var keys2 = Object.keys(array); + var output = new Array(); + for (var i = 0; i < keys2.length; i++) { + var key = keys2[i]; + output[i] = array[key]; + } + return output; + } + getEnvironment() { + if (typeof document != "undefined") { + return "Browser"; + } + if (global) { + return "Node"; + } + } + // Security + getObjectByPath(application32, applicationPath) { + var objectName = applicationPath.pop(); + if (!application32[objectName] || typeof application32[objectName] != "string") { + } + var currentApplication = application32[objectName]; + if (!currentApplication) { + } + if (applicationPath.length > 0) { + return this.getObjectByPath(currentApplication, applicationPath); + } else { + return currentApplication; + } + } + isNumber(value2) { + return typeof value2 === "number" && isFinite(value2); + } + isNumberObject(n) { + return Object.prototype.toString.apply(n) === "[object Number]"; + } + isCustomNumber(n) { + return this.isNumber(n) || this.isNumberObject(n); + } + structuredClone(object93) { + var prototype = Object.getPrototypeOf(object93); + var create2 = Object.create(prototype); + return Object.assign(create2, object93); + } + extendedClassIsColumn() { + } + isUnifyColumn(object93) { + var extendedClasses = this.getExtendedClassesMulti(object93); + var isColumn = false; + for (var j = 0; j < extendedClasses.length; j++) { + var extendedClass = extendedClasses[j]; + var className2 = this.getClassName(extendedClass); + if (className2 == "column") { + isColumn = object93; + } + } + return isColumn; + } + filterPrims(item, prims, type) { + if (prims[type].hasOwnProperty(item)) { + return false; + } else { + prims[type][item] = true; + return true; + } + } + filterObjects(item) { + var filterObjects = this.filterObjects; + if (filterObjects.indexOf(item) >= 0) { + return false; + } else { + filterObjects.push(item); + return filterObjects; + } + } + uniqueFilter(item) { + var type = typeof item; + var prims = this.prims; + if (type in prims) { + return this.filterPrims(item, prims, type); + } else { + return this.filterObjects(item); + } + } + uniqueArrayRows(a32) { + this.prims = new Object(); + this.prims.boolean = new Object(); + this.prims.number = new Object(); + this.prims.string = new Object(); + this.filterObjects = new Array(); + return a32.filter(this.uniqueFilter.bind(this)); + } + simpleClone(object93) { + var prototype = Object.getPrototypeOf(object93); + var created = Object.create(prototype); + let clone2 = Object.assign(created, object93); + return clone2; + } + getPrototypeRecursive(object93, properties = new Array()) { + properties.push(...Object.getOwnPropertyNames(object93)); + var prototype = Object.getPrototypeOf(object93); + if (prototype) { + return this.getPrototypeRecursive(prototype, properties); + } else { + return properties; + } + } + filterFunctions(element2, index, arr) { + var nextElement = arr[index + 1]; + var elementType = typeof this[element2]; + if (element2 != nextElement && elementType == "function") { + return true; + } + } + getAllFuncs(object93) { + var properties = this.getPrototypeRecursive(object93); + var sorted = properties.sort(); + var filterd = sorted.filter(this.filterFunctions.bind(object93)); + return filterd; + } + createRandomKey(numCharacters) { + var token = ""; + for (var i = 0; i < numCharacters; i++) { + token += Math.floor(Math.random() * 10); + } + return token; + } + isCSSProperty(propertyName2) { + var object93 = definitions_default.css; + if (typeof object93[propertyName2] !== "undefined") { + return true; + } else { + return false; + } + } + hasUserPrototype(obj) { + return obj.constructor !== Object; + } + addTabToArrayLines(lines, numSpaces) { + var tabbedRows = new Array(); + for (var i = 0; i < lines.length; i++) { + var row181 = lines[i]; + tabbedRows[i] = "".padEnd(numSpaces) + row181; + } + return tabbedRows; + } + addTabToBeginOfString(string, numSpaces) { + var lines = string.split("\n"); + var tabbedRows = this.addTabToArrayLines(lines, numSpaces); + return tabbedRows.join("\n"); + } + addTabToBegin(string, numSpaces) { + if (typeof string == "string") { + return this.addTabToBeginOfString(string, numSpaces); + } else { + return string; + } + } + getChildFromEntry(parent, entry, children) { + const invalid = new Array("parent", "table", "user"); + var name = this.getClassNameByEntry(entry); + var child = this.getObjectByEntry(entry); + if (!this.isUnifyObject(name, child)) { + return false; + } + if (invalid.includes(name)) { + return false; + } + child.propertyName = name; + child.parent = parent; + children.push(child); + } + getChildren(object93, bindParent = true) { + var children = new Array(); + var entries = Object.entries(object93); + for (var c31 = 0; c31 < entries.length; c31++) { + var entry = entries[c31]; + this.getChildFromEntry(object93, entry, children); + } + return children; + } + addPropertyToArray(property2, properties) { + const invalid = new Array("user"); + if (this.isUnifyObject(property2.name, property2.value)) { + return false; + } + if (invalid.includes(property2.name)) { + return false; + } + properties.push(property2); + } + createPropertyFromEntry(entry) { + var name = this.getClassNameByEntry(entry); + var object93 = this.getObjectByEntry(entry); + var property2 = new Object(); + property2.name = name; + property2.value = object93; + return property2; + } + getProperties(object93) { + var properties = new Array(); + var entries = Object.entries(object93); + for (var c31 = 0; c31 < entries.length; c31++) { + var entry = entries[c31]; + var property2 = this.createPropertyFromEntry(entry); + this.addPropertyToArray(property2, properties); + } + return properties; + } + replaceChildWithFragment(source, newType) { + const frag = document.createDocumentFragment(); + while (source.firstChild) { + frag.appendChild(source.firstChild); + } + const newElem = document.createElement(newType); + newElem.appendChild(frag); + source.parentNode.replaceChild(newElem, source); + } + replaceElement(source, newType, parentElement) { + if (parentElement) { + source.parentNode = parentElement; + } + if (source.tagName != newType.toUpperCase()) { + this.replaceChildWithFragment(source, newType); + } + } + parseObject(object93) { + var entries = Object.entries(object93); + return entries[0]; + } + getFirstEntry(object93) { + var entries = Object.entries(object93); + if (entries[0]) { + return entries[0]; + } else { + return false; + } + } + getExtendedClass(object93) { + if (!object93.prototype) { + object93 = object93.constructor; + } + return object93.prototype.__proto__; + } + removeDuplicates(arr) { + return arr.filter((item, index) => arr.indexOf(item) === index); + } + removeEmptyRows(arr) { + return arr.filter((n) => n); + } + isVisible(element2) { + if (!element2) { + return false; + } + if (!element2.offsetWidth) { + return false; + } + return element2.offsetWidth > 0 || element2.offsetHeight > 0; + } + getExtendedObjects(object93) { + if (!object93.getClassName) { + return false; + } + if (typeof document == "undefined") { + var extendedObjects = global.extendMap[object93.getClassName()]; + } else { + var extendedObjects = document.extendMap[object93.getClassName()]; + } + return extendedObjects; + } + getSingleExtendedClassInArray(object93) { + if (!object93.prototype) { + object93 = object93.constructor; + } + var extendedClass = this.getExtendedClass(object93); + if (!extendedClass) { + return false; + } else { + return new Array(new extendedClass.constructor()); + } + } + getExtendedClassesMulti(object93) { + var extendedObjects = this.getExtendedObjects(object93); + if (extendedObjects) { + return extendedObjects; + } else { + return this.getSingleExtendedClassInArray(object93); + } + } + getExtendedClassName(object93) { + return this.getClassName(this.getExtendedClass(object93)); + } + logError(message) { + console.log(this.consoleColors().red(message)); + } + debugVar(object93, variable) { + var colors = this.consoleColors(); + var path2 = this.getApplicationPath(object93); + var pathColor = colors.red("(" + path2.toString() + ")"); + var variableColor = colors.magenta(variable); + console.log(variableColor + pathColor); + } + logParameter2(parameter2) { + if (typeof parameter2 == "string") { + console.log(parameter2); + } else { + this.logObject(parameter2); + } + } + log(parameter1, parameter2, parameter3) { + var colors = this.consoleColors(); + if (typeof parameter1 == "string") { + console.log(colors.yellow("\n\n" + parameter1)); + } else { + this.logObject(parameter1); + } + if (parameter2) { + this.logParameter2(parameter2); + } + } + logObject(object93) { + var colors = this.consoleColors(); + var path2 = this.getApplicationPath(object93); + var pathColor = colors.red("(" + path2.reverse().toString() + ")"); + console.log(pathColor + " " + this.getClassName(object93)); + console.log(this.serialize(object93)); + } + saveImportDefault(importObject) { + if (importObject.default) { + return importObject.default; + } else { + console.log("error2 ", url, " does not exist"); + } + } + async saveImport(url2) { + var importObject = await import(url2); + if (importObject) { + return this.saveImportDefault(importObject); + } else { + console.log("error1 ", url2, " does not exist"); + } + } + getApplicationDepth(object93) { + return this.getApplicationPath(object93).length; + } + getParentApplicationPath(object93, array) { + array.push(object93.propertyName); + return this.getApplicationPath(object93.parent, array); + } + getApplicationPath(object93, array = new Array()) { + if (object93.parent) { + return this.getParentApplicationPath(object93, array); + } else { + return array; + } + } + getClassName(object93) { + if (object93.__className) { + return object93.__className; + } + if (!object93) { + return false; + } + return object93.constructor.name; + } + getID(object93) { + if (object93.id) { + return object93.id; + } else { + return ""; + } + } + getClassNameByObject(object93) { + if (typeof object93 == "string") { + return object93; + } + var entry = this.parseObject(object93); + var className2 = this.getClassNameByEntry(entry); + return className2; + } + getClassNameByEntry(entry) { + return entry[0]; + } + getObjectByEntry(entry) { + if (entry[1]) { + return entry[1]; + } else { + return false; + } + } + logObject(object93, message) { + if (object93.debug) { + console.log(message, object93.getClassName(), "\n"); + } + } + getFirstEntryName(object93) { + var entries = Object.entries(object93); + return entries[0][0]; + } + getPropertyNameWithID(object93) { + if (object93.id) { + return this.CamelCase(object93.propertyName) + "_" + object93.id; + } else { + return this.CamelCase(object93.propertyName); + } + if (!propertyName) { + return ""; + } + } + createCSSClassName(object93) { + var propertyName2 = this.getPropertyNameWithID(object93); + if (object93.parent) { + object93 = object93.parent; + } + return this.getClassName(object93) + propertyName2; + } + CamelCase(string) { + if (!string) { + return false; + } + string = string.toUpperCase(); + string = string[0].toUpperCase() + string.slice(1, string.length).toLowerCase(); + return string; + } + firstLowerCase(string) { + if (string) { + return string[0].toLowerCase() + string.slice(1, string.length); + } else { + return false; + } + } + cleanRollup(term) { + return term; + } + cleanEntry(entry) { + const invalid = new Array("parent", "table", "user", "objectToManipulate"); + var name = this.getClassNameByEntry(entry); + var object93 = this.getObjectByEntry(entry); + if (invalid.includes(name)) { + delete object93[name]; + } + } + cleanObject(object93) { + var entries = Object.entries(this); + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + this.cleanEntry(entry); + } + } + objectExtendsTablePrimitive(object93) { + var extendedClass = this.getExtendedClass(object93); + if (!extendedClass) { + return false; + } + var className2 = this.getClassName(extendedClass); + if (className2 == "table") { + return true; + } else { + return false; + } + } + objectIsTable(object93) { + if (!object93) { + return false; + } + if (!object93.prototype) { + object93 = object93.constructor; + } + return this.objectExtendsTablePrimitive(object93); + } + extendIsRenderCollection(object93) { + var extendedClass = this.getExtendedClass(object93); + var className2 = this.getClassName(extendedClass); + if (className2 == "renderCollection") { + return true; + } else { + return false; + } + } + objectIsRenderCollection(object93) { + var className2 = this.getClassName(object93); + if (className2 == "renderCollection") { + return true; + } + if (!object93.prototype) { + object93 = object93.constructor; + } + return this.extendIsRenderCollection(object93); + } + getTableName(object93) { + if (!this.objectIsTable(object93)) { + object93 = this.getTableFromObject(object93); + } + var className2 = this.getClassName(object93); + return className2; + } + isTableInHierarchy(object93) { + } + getParentWithTable(object93, tableName) { + if (this.getClassName(this.getTableFromObject(object93)) == tableName) { + return object93; + } else { + return this.getParentWithTable(object93.parent, tableName); + } + } + classNameIsTable(className2) { + if (className2 == "table") { + return true; + } else { + return false; + } + } + evaluateExtendedClass(object93, extendedClass) { + var className2 = this.getClassName(extendedClass); + if (this.classNameIsTable(className2)) { + return object93; + } + var table33 = this.getTableFromObject(extendedClass); + if (table33) { + return table33; + } else { + return false; + } + } + getTableFromExtendedClasses(object93, extendedClasses) { + for (var i = 0; i < extendedClasses.length; i++) { + var extendedClass = extendedClasses[i]; + var table33 = this.evaluateExtendedClass(object93, extendedClass); + if (table33) { + return table33; + } + } + } + getTableFromObject(object93) { + var className2 = this.getClassName(object93); + if (className2) { + var extendedClasses = this.getExtendedClassesMulti(object93); + return this.getTableFromExtendedClasses(object93, extendedClasses); + } else { + console.log("classname not found", object93); + } + } + isServerValue(name, value2) { + const invalid = new Array("style", "type", "label", "flexDirection", "boxPadding", "width", "DOM_ELEMENT"); + const valid = new Array("rows"); + if (valid.includes(name)) { + return true; + } + if (invalid.includes(name)) { + return false; + } + if (this.css.propertyIsStyle(name)) { + return false; + } + if (typeof value2 == "number") { + return true; + } + if (typeof value2 == "string") { + return true; + } else { + return false; + } + } + deleteNormalBrowserEvent(object93, browserEvent) { + if (object93[browserEvent]) { + delete object93[browserEvent]; + } + } + deleteServerBrowserEvent(object93, browserEvent) { + if (object93["server" + this.CamelCase(browserEvent)]) { + delete object93["server" + this.CamelCase(browserEvent)]; + } + } + groomBrowserEvents(object93) { + var browserEvents = definitions_default.browserEvents; + for (var i = 0; i < browserEvents.length; i++) { + var browserEvent = browserEvents[i]; + this.deleteNormalBrowserEvent(object93, browserEvent); + this.deleteServerBrowserEvent(object93, browserEvent); + } + } + getCircularReplacer(key, value2) { + if (typeof value2 === "object" && value2 !== null) { + if (this.seen.has(value2)) { + return; + } + this.seen.add(value2); + } + return value2; + } + sizeOf(object93) { + this.seen = /* @__PURE__ */ new WeakSet(); + var stringObject = JSON.stringify(object93, this.getCircularReplacer.bind(this)); + var finalObject = JSON.parse(stringObject); + return global.objectSizeof(finalObject); + } + groomCssProperties(object93, propertyName2) { + var propertyNameWithoutBox = propertyName2.replace("box", ""); + if (this.css.propertyHasStyle(propertyNameWithoutBox)) { + delete object93[propertyName2]; + } + } + groomRemainingProperties(object93, propertyName2, propertyValue) { + } + groomPermissionMethods(object93) { + if (object93.enableWRITE) { + delete object93.enableWRITE; + } + if (object93.disableWRITE) { + delete object93.disableWRITE; + } + if (object93.enableREAD) { + delete object93.enableREAD; + } + if (object93.disableREAD) { + delete object93.disableREAD; + } + if (object93.enableDELETE) { + delete object93.enableDELETE; + } + if (object93.disableDELETE) { + delete object93.disableDELETE; + } + } + groomBrowserMethods(object93) { + if (object93.create) { + delete object93.create; + } + if (object93.update) { + delete object93.update; + } + if (object93.afterLoad) { + delete object93.afterLoad; + } + } + groomEntry(entry, object93) { + var propertyName2 = this.getClassNameByEntry(entry); + var propertyValue = this.getObjectByEntry(entry); + this.groomPermissionMethods(object93); + this.groomBrowserMethods(object93); + this.groomBrowserEvents(object93); + this.groomCssProperties(object93, propertyName2); + this.groomRemainingProperties(object93, propertyName2, propertyValue); + if (this.isUnifyObject(propertyName2, propertyValue)) { + this.groomApplicationObject(propertyValue); + } + return object93; + } + groomApplicationObject(object93) { + var entries = Object.entries(object93); + for (var c31 = 0; c31 < entries.length; c31++) { + var entry = entries[c31]; + this.groomEntry(entry, object93); + } + return object93; + } + serializeEntry(entry, serializedObject2) { + var propertyName2 = this.getClassNameByEntry(entry); + var propertyValue = this.getObjectByEntry(entry); + this.serializeProperty(propertyName2, propertyValue, serializedObject2); + } + serializeEntries(entries) { + var serializedObject2 = new Object(); + for (var c31 = 0; c31 < entries.length; c31++) { + var entry = entries[c31]; + this.serializeEntry(entry, serializedObject2); + } + return serializedObject2; + } + serialize(object93, is_root = true, cut) { + var entries = Object.entries(object93); + this.serializeEntries(entries); + return this.createOuterObject(object93, serializedObject, is_root); + } + serializeServerProperty(object93, propertyName2, propertyValue) { + object93[propertyName2] = propertyValue; + } + serializedUnifyObject(object93, propertyName2, propertyValue) { + object93[propertyName2] = this.serialize(propertyValue, false); + } + serializeProperty(propertyName2, propertyValue, object93) { + if (this.isServerValue(propertyName2, propertyValue)) { + this.serializeServerProperty(object93, propertyName2, propertyValue); + } + if (this.isUnifyObject(propertyName2, propertyValue)) { + this.serializedUnifyObject(object93, propertyName2, propertyValue); + } + return object93; + } + isArray(array) { + if (!array) { + return false; + } + return Array.isArray(array); + } + validateNumber(value2) { + if (typeof value2 == "number") { + return value2; + } else { + return false; + } + } + validateString(value2) { + if (typeof value2 == "string") { + return value2; + } else { + return false; + } + } + validateValue(value2) { + if (typeof value2 == "string" || typeof value2 == "number" || typeof value2 == "boolean") { + return value2; + } else { + return false; + } + } + validateBoolean(value2) { + if (typeof value2 == "boolean") { + return value2; + } else { + return false; + } + } + validateArray(values) { + if (!this.isArray(values)) { + return false; + } + for (var c31 = 0; c31 < values.length; c31++) { + values[c31] = this.validateString(values[c31]); + } + return values; + } + is_allowed_value(value2) { + if (this.is_int(value2)) { + return true; + } + if (this.is_text(value2)) { + return true; + } + if (this.is_boolean(value2)) { + return true; + } + if (this.is_object(value2)) { + return true; + } + return false; + } + is_float(value2) { + if (typeof value2 == "number") { + return true; + } else { + return false; + } + } + is_number(value2) { + if (typeof value2 == "number") { + return true; + } else { + return false; + } + } + is_object(value2) { + if (typeof value2 == "object") { + return true; + } else { + return false; + } + } + is_text(value2) { + if (typeof value2 == "string") { + return true; + } else { + return false; + } + } + is_string(value2) { + if (typeof value2 == "string") { + return true; + } else { + return false; + } + } + is_boolean() { + if (typeof value == "boolean") { + return true; + } else { + return false; + } + } + is_int(value2) { + if (typeof value2 == "number") { + return true; + } else { + return false; + } + } + createOuterObjectWithRoot() { + var objectName = this.getClassName(object); + var output = new Object(); + output[objectName] = serializedObject; + return output; + } + createOuterObject(object93, serializedObject2, is_root) { + if (is_root) { + return this.createOuterObjectWithRoot(object93, serializedObject2); + } else { + return serializedObject2; + } + } + consoleColors() { + return consoleColors_default; + } + getFirstObjectFromEntries(entries) { + var firstChild = entries[0][1]; + if (firstChild) { + return firstChild; + } else { + return object; + } + } + getFirstChild(object93) { + var entries = Object.entries(object93); + if (entries[0]) { + return this.getFirstObjectFromEntries(entries); + } + } +}; +String.prototype.replaceAll = /* @__PURE__ */ __name(function replaceAll(search, replace) { + return this.split(search).join(replace); +}, "replaceAll"); +var tools_default = new tools2(); + +// framework/client/dom.js +var dom = class { + static { + __name(this, "dom"); + } + addDOMToSelector = true; + setElement() { + var objectName = tools_default.createCSSClassName(object); + element.className = this.getClassName(object.editable, objectName); + } + getClassName(editable, objectName) { + if (editable) { + return objectName + "Element"; + } else { + return objectName + "Grid grid"; + } + } + createSetter(object93) { + object93.__defineSetter__("text", function(value2) { + if (typeof value2 == "number") { + value2 = value2.toString(); + } + object93.__text = value2; + object93.updateElementContent(); + }); + } + createGetter(object93) { + object93.__defineGetter__("text", function() { + return object93.__text; + }); + } + createSetterAndGetters(object93) { + object93.__text = object93.text; + this.createSetter(object93); + this.createGetter(object93); + } + createDOMElements(object93, objectName) { + object93.elements = []; + if (object93.layers == 2) { + object93.boxElement = this.createDiv(objectName, "box", object93.id); + object93.elements.push(object93.boxElement); + } + object93.defaultElement = this.createDiv(objectName, "grid", object93.id); + if (object93.useCustomElement) { + object93.element = object93.customElement; + } else { + object93.element = object93.defaultElement; + } + object93.elements.push(object93.element); + } + addClasses(object93, objectName) { + var type = "Element"; + var mainClassName = objectName; + object93.customElement.classList.add(mainClassName + type); + object93.customElement.classList.add(type); + object93.customElement.classList.add(this.device); + object93.customElement.classList.add(this.tint); + object93.customElement.classList.add(this.os); + } + updateZIndex(object93) { + if (!object93.zIndex && object93.setZIndex) { + object93.element.style["z-index"] = tools_default.getApplicationDepth(object93); + if (object93.inverseZIndex) { + object93.element.style["z-index"] = 1e3 - tools_default.getApplicationDepth(object93); + } + } + } + attachUnifyObjectToElements(object93) { + for (var c31 = 0; c31 < object93.elements.length; c31++) { + object93.elements[c31].object = object93; + } + } + parseObject(object93) { + var objectName = tools_default.createCSSClassName(object93); + this.createDOMElements(object93, objectName); + if (object93.customElement) { + this.addClasses(object93, objectName); + } else { + object93.customElement = object93.defaultElement; + } + this.createSetterAndGetters(object93); + object93.updateElementContent(); + this.updateZIndex(object93); + this.attachUnifyObjectToElements(object93); + if (!object93.selector && object93.parent && object93.addToDom) { + this.parseProperty(objectName, object93, object93.parent); + } + } + addElementToDOMParent(object93, propertyValue) { + if (propertyValue.propertyName[0] == "_") { + object93.elements[object93.elements.length - 1].prepend(propertyValue.elements[0]); + } else { + if (object93.elements) { + object93.elements[object93.elements.length - 1].appendChild(propertyValue.elements[0]); + } + } + } + addElementToBody(propertyValue) { + document_default.body.appendChild(propertyValue.elements[0]); + } + parseProperty(propertyName2, propertyValue, object93) { + if (tools_default.isUnifyObject(propertyName2, propertyValue)) { + if (propertyValue.absolute) { + this.addElementToBody(propertyValue); + return true; + } + this.addElementToDOMParent(object93, propertyValue); + } + } + parseInnerElements(object93) { + var elements = object93.elements; + for (var c31 = elements.length - 1; c31 > 0; c31--) { + elements[c31 - 1].appendChild(elements[c31]); + } + if (object93.selector && this.addDOMToSelector) { + this.appendToSelector(object93, elements); + } + } + appendToSelector(object93, elements) { + var selector = object93.selector; + var element2 = document_default.querySelector(selector); + if (element2) { + element2.appendChild(elements[0]); + } + } + createDiv(divName, type, id2) { + var div = document_default.createElement("div"); + var mainClassName = divName + tools_default.CamelCase(type.toUpperCase()); + div.classList.add(mainClassName); + if (id2) { + div.classList.add(mainClassName.replace("_" + id2, "").replace(id2, "")); + } + div.classList.add(type); + div.classList.add(this.device); + div.classList.add(this.tint); + div.classList.add(this.os); + return div; + } +}; + +// framework/client/event.js +var event = class { + static { + __name(this, "event"); + } + name; + className; + callback; +}; + +// framework/client/eventManager.js +var eventManager = class { + static { + __name(this, "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); + 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(className2, eventName, callback) { + var newEvent = new event(); + newEvent.className = className2; + newEvent.name = eventName; + newEvent.callback = callback; + this.events.push(newEvent); + } + getClientEvents(classname, eventName) { + var events = []; + for (var c31 = 0; c31 < this.events.length; c31++) { + var event2 = this.events[c31]; + if (event2.className == classname && event2.name == eventName) { + events.push(event2); + } + } + return events; + } + parentHasEvent(object93, eventTerm) { + if (!object93) { + return false; + } + if (object93[eventTerm]) { + return true; + } + if (object93.parent) { + return this.parentHasEvent(object93.parent, eventTerm); + } else { + return false; + } + } + update_value(object93) { + if (object93.value && object93.value != "undefined") { + object93._value = object93.value; + } + } + createInputSetter(object93, element2) { + object93.__defineSetter__("value", function(value2) { + if (object93.datatype == "BOOLEAN") { + object93._value = value2; + element2.value = object93._value; + } + if (value2 && value2 != void 0 && value2 != "undefined") { + object93._value = value2; + element2.value = object93._value; + } + if (value2 == "") { + object93._value = false; + element2.value = ""; + } + if (typeof value2 == "number") { + object93._value = value2; + element2.value = object93._value; + } + }); + } + createUploadSetter(object93, element2) { + object93.__defineSetter__("value", function(value2) { + if (value2 != "undefined") { + object93._value = value2; + } + if (element2.value) { + } + }); + } + createSetter(object93, element2) { + this.update_value(object93); + if (object93.inputType != "file") { + this.createInputSetter(object93, element2); + } else { + this.createUploadSetter(object93, element2); + } + } + createGetter(object93) { + object93.__defineGetter__("value", function(value2) { + if (typeof object93._value == "undefined") { + return ""; + } else { + return object93._value; + } + }); + } + parseEvents(object93) { + if (object93.defaultElement) { + this.createSetter(object93, object93.defaultElement); + this.createGetter(object93); + } + if (object93.customElement) { + this.createSetter(object93, object93.customElement); + this.createGetter(object93); + } + var eventTerms = this.eventTerms; + for (var c31 = 0; c31 < eventTerms.length; c31++) { + var eventTerm = eventTerms[c31]; + this.parseEvent(object93, eventTerm); + } + } + defineEventCallback(object93, element2, eventTerm) { + var eventManager2 = this; + if (!this.parentHasEvent(object93.parent, eventTerm) || object93.selector) { + var eventNormalized = eventTerm.replace("box", ""); + if (object93.getClassName() != "fileChooserSelectButton") { + element2["on" + eventNormalized] = function(event2) { + eventManager2.createEventCallback(event2, eventManager2); + }; + } + } + } + createWindowResizeEventListener(object93) { + } + parseElement(object93, element2, eventTerm, box = false) { + element2.object = object93; + element2.eventTerm = eventTerm; + this.defineEventCallback(object93, element2, eventTerm); + } + parseDefaultElement(object93, eventTerm) { + if (object93[eventTerm]) { + this.parseElement(object93, object93.defaultElement, eventTerm); + if (object93.customElement) { + this.parseElement(object93, object93.customElement, eventTerm); + } + } + } + parseBoxElement(object93, eventTerm) { + if (object93["box" + tools_default.CamelCase(eventTerm)]) { + if (object93.boxElement) { + var element2 = object93.boxElement; + } else { + var element2 = object93.defaultElement; + } + this.parseElement(object93, element2, "box" + tools_default.CamelCase(eventTerm), true); + } + } + parseEvent(object93, eventTerm) { + this.parseDefaultElement(object93, eventTerm); + this.parseBoxElement(object93, eventTerm); + } + callMethod(object93, event2, eventTerm) { + if (object93[eventTerm]) { + object93.lastEvent = eventTerm; + object93[eventTerm](event2, object93); + } + } + createEventListener(event2, object93, box = false) { + var eventTerm = event2.type.replace("on", ""); + if (box) { + eventTerm = "box" + tools_default.CamelCase(eventTerm); + } + this.callMethod(object93, event2, eventTerm); + if (!object93.isRoot && object93.parent) { + if (object93.propegateEvent) { + this.createEventListener(event2, object93.parent); + } + } + } + createEventListeners(event2, target, eventManager2, object93) { + if (object93.boxElement && target.className == object93.boxElement.className) { + eventManager2.createEventListener(event2, object93, true); + } else if (target.className == object93.defaultElement.className) { + eventManager2.createEventListener(event2, object93); + } else if (target.className == object93.customElement.className) { + eventManager2.createEventListener(event2, object93); + } + } + logEvent(event2, target) { + } + createEventCallback(event2, eventManager2) { + var target = event2.target; + var object93 = target.object; + if (!object93) { + console.error("This element does not have an object", target); + return false; + } + this.logEvent(event2, target); + this.createEventListeners(event2, target, eventManager2, object93); + } +}; + +// framework/unify/socketMessage.js +var socketMessage = class { + static { + __name(this, "socketMessage"); + } + id = 0; + type = "promise"; + data = false; +}; + +// framework/client/promiseManager.js +var promiseManager = class { + static { + __name(this, "promiseManager"); + } + promises = new Array(); + messages = new Array(); + socketManager; + addPromise(promiseObject) { + this.promises.push(promiseObject); + } + addMessage(message) { + this.messages.push(message); + } + getPromiseByID(id2) { + var promises = this.promises; + for (var c31 = 0; c31 < promises.length; c31++) { + var currentPromise = promises[c31]; + if (currentPromise.id == id2) { + return currentPromise; + } + } + console.error("Promise with id " + id2 + " not found:", this); + return false; + } + getMessageByID(id2) { + var messages = this.messages; + for (var c31 = 0; c31 < messages.length; c31++) { + var message = messages[c31]; + if (message.id == id2) { + return message; + } + } + } + createPromiseFunction(messageID, object93 = false) { + var promiseManager32 = this; + function promiseFunction(resolveFunction) { + var promiseObject = {}; + promiseObject.id = messageID; + promiseObject.resolve = resolveFunction; + promiseObject.object = object93; + promiseManager32.addPromise(promiseObject); + } + __name(promiseFunction, "promiseFunction"); + return promiseFunction; + } +}; + +// framework/unify/clonedeep.js +var LARGE_ARRAY_SIZE = 200; +var HASH_UNDEFINED = "__lodash_hash_undefined__"; +var MAX_SAFE_INTEGER = 9007199254740991; +var argsTag = "[object Arguments]"; +var arrayTag = "[object Array]"; +var boolTag = "[object Boolean]"; +var dateTag = "[object Date]"; +var errorTag = "[object Error]"; +var funcTag = "[object Function]"; +var genTag = "[object GeneratorFunction]"; +var mapTag = "[object Map]"; +var numberTag = "[object Number]"; +var objectTag = "[object Object]"; +var promiseTag = "[object Promise]"; +var regexpTag = "[object RegExp]"; +var setTag = "[object Set]"; +var stringTag = "[object String]"; +var symbolTag = "[object Symbol]"; +var weakMapTag = "[object WeakMap]"; +var arrayBufferTag = "[object ArrayBuffer]"; +var dataViewTag = "[object DataView]"; +var float32Tag = "[object Float32Array]"; +var float64Tag = "[object Float64Array]"; +var int8Tag = "[object Int8Array]"; +var int16Tag = "[object Int16Array]"; +var int32Tag = "[object Int32Array]"; +var uint8Tag = "[object Uint8Array]"; +var uint8ClampedTag = "[object Uint8ClampedArray]"; +var uint16Tag = "[object Uint16Array]"; +var uint32Tag = "[object Uint32Array]"; +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; +var reFlags = /\w*$/; +var reIsHostCtor = /^\[object .+?Constructor\]$/; +var reIsUint = /^(?:0|[1-9]\d*)$/; +var cloneableTags = {}; +cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; +cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; +var freeGlobal = typeof global == "object" && global && global.Object === Object && global; +var freeSelf = typeof self == "object" && self && self.Object === Object && self; +var root = freeGlobal || freeSelf || Function("return this")(); +var freeExports = typeof exports == "object" && exports && !exports.nodeType && exports; +var freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module; +var moduleExports = freeModule && freeModule.exports === freeExports; +function addMapEntry(map, pair) { + map.set(pair[0], pair[1]); + return map; +} +__name(addMapEntry, "addMapEntry"); +function addSetEntry(set, value2) { + set.add(value2); + return set; +} +__name(addSetEntry, "addSetEntry"); +function arrayEach(array, iteratee) { + var index = -1, length = array ? array.length : 0; + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; +} +__name(arrayEach, "arrayEach"); +function arrayPush(array, values) { + var index = -1, length = values.length, offset = array.length; + while (++index < length) { + array[offset + index] = values[index]; + } + return array; +} +__name(arrayPush, "arrayPush"); +function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, length = array ? array.length : 0; + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; +} +__name(arrayReduce, "arrayReduce"); +function baseTimes(n, iteratee) { + var index = -1, result = Array(n); + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} +__name(baseTimes, "baseTimes"); +function getValue(object93, key) { + return object93 == null ? void 0 : object93[key]; +} +__name(getValue, "getValue"); +function isHostObject(value2) { + var result = false; + if (value2 != null && typeof value2.toString != "function") { + try { + result = !!(value2 + ""); + } catch (e) { + } + } + return result; +} +__name(isHostObject, "isHostObject"); +function mapToArray(map) { + var index = -1, result = Array(map.size); + map.forEach(function(value2, key) { + result[++index] = [key, value2]; + }); + return result; +} +__name(mapToArray, "mapToArray"); +function overArg(func, transform) { + return function(arg2) { + return func(transform(arg2)); + }; +} +__name(overArg, "overArg"); +function setToArray(set) { + var index = -1, result = Array(set.size); + set.forEach(function(value2) { + result[++index] = value2; + }); + return result; +} +__name(setToArray, "setToArray"); +var arrayProto = Array.prototype; +var funcProto = Function.prototype; +var objectProto = Object.prototype; +var coreJsData = root["__core-js_shared__"]; +var maskSrcKey = function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ""); + return uid ? "Symbol(src)_1." + uid : ""; +}(); +var funcToString = funcProto.toString; +var hasOwnProperty = objectProto.hasOwnProperty; +var objectToString = objectProto.toString; +var reIsNative = RegExp( + "^" + funcToString.call(hasOwnProperty).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$" +); +var Buffer2 = moduleExports ? root.Buffer : void 0; +var Symbol2 = root.Symbol; +var Uint8Array2 = root.Uint8Array; +var getPrototype = overArg(Object.getPrototypeOf, Object); +var objectCreate = Object.create; +var propertyIsEnumerable = objectProto.propertyIsEnumerable; +var splice = arrayProto.splice; +var nativeGetSymbols = Object.getOwnPropertySymbols; +var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0; +var nativeKeys = overArg(Object.keys, Object); +var DataView = getNative(root, "DataView"); +var Map = getNative(root, "Map"); +var Promise2 = getNative(root, "Promise"); +var Set = getNative(root, "Set"); +var WeakMap = getNative(root, "WeakMap"); +var nativeCreate = getNative(Object, "create"); +var dataViewCtorString = toSource(DataView); +var mapCtorString = toSource(Map); +var promiseCtorString = toSource(Promise2); +var setCtorString = toSource(Set); +var weakMapCtorString = toSource(WeakMap); +var symbolProto = Symbol2 ? Symbol2.prototype : void 0; +var symbolValueOf = symbolProto ? symbolProto.valueOf : void 0; +function Hash(entries) { + var index = -1, length = entries ? entries.length : 0; + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} +__name(Hash, "Hash"); +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; +} +__name(hashClear, "hashClear"); +function hashDelete(key) { + return this.has(key) && delete this.__data__[key]; +} +__name(hashDelete, "hashDelete"); +function hashGet(key) { + var data2 = this.__data__; + if (nativeCreate) { + var result = data2[key]; + return result === HASH_UNDEFINED ? void 0 : result; + } + return hasOwnProperty.call(data2, key) ? data2[key] : void 0; +} +__name(hashGet, "hashGet"); +function hashHas(key) { + var data2 = this.__data__; + return nativeCreate ? data2[key] !== void 0 : hasOwnProperty.call(data2, key); +} +__name(hashHas, "hashHas"); +function hashSet(key, value2) { + var data2 = this.__data__; + data2[key] = nativeCreate && value2 === void 0 ? HASH_UNDEFINED : value2; + return this; +} +__name(hashSet, "hashSet"); +Hash.prototype.clear = hashClear; +Hash.prototype["delete"] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; +function ListCache(entries) { + var index = -1, length = entries ? entries.length : 0; + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} +__name(ListCache, "ListCache"); +function listCacheClear() { + this.__data__ = []; +} +__name(listCacheClear, "listCacheClear"); +function listCacheDelete(key) { + var data2 = this.__data__, index = assocIndexOf(data2, key); + if (index < 0) { + return false; + } + var lastIndex = data2.length - 1; + if (index == lastIndex) { + data2.pop(); + } else { + splice.call(data2, index, 1); + } + return true; +} +__name(listCacheDelete, "listCacheDelete"); +function listCacheGet(key) { + var data2 = this.__data__, index = assocIndexOf(data2, key); + return index < 0 ? void 0 : data2[index][1]; +} +__name(listCacheGet, "listCacheGet"); +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} +__name(listCacheHas, "listCacheHas"); +function listCacheSet(key, value2) { + var data2 = this.__data__, index = assocIndexOf(data2, key); + if (index < 0) { + data2.push([key, value2]); + } else { + data2[index][1] = value2; + } + return this; +} +__name(listCacheSet, "listCacheSet"); +ListCache.prototype.clear = listCacheClear; +ListCache.prototype["delete"] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; +function MapCache(entries) { + var index = -1, length = entries ? entries.length : 0; + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} +__name(MapCache, "MapCache"); +function mapCacheClear() { + this.__data__ = { + "hash": new Hash(), + "map": new (Map || ListCache)(), + "string": new Hash() + }; +} +__name(mapCacheClear, "mapCacheClear"); +function mapCacheDelete(key) { + return getMapData(this, key)["delete"](key); +} +__name(mapCacheDelete, "mapCacheDelete"); +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} +__name(mapCacheGet, "mapCacheGet"); +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} +__name(mapCacheHas, "mapCacheHas"); +function mapCacheSet(key, value2) { + getMapData(this, key).set(key, value2); + return this; +} +__name(mapCacheSet, "mapCacheSet"); +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype["delete"] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; +function Stack(entries) { + this.__data__ = new ListCache(entries); +} +__name(Stack, "Stack"); +function stackClear() { + this.__data__ = new ListCache(); +} +__name(stackClear, "stackClear"); +function stackDelete(key) { + return this.__data__["delete"](key); +} +__name(stackDelete, "stackDelete"); +function stackGet(key) { + return this.__data__.get(key); +} +__name(stackGet, "stackGet"); +function stackHas(key) { + return this.__data__.has(key); +} +__name(stackHas, "stackHas"); +function stackSet(key, value2) { + var cache = this.__data__; + if (cache instanceof ListCache) { + var pairs = cache.__data__; + if (!Map || pairs.length < LARGE_ARRAY_SIZE - 1) { + pairs.push([key, value2]); + return this; + } + cache = this.__data__ = new MapCache(pairs); + } + cache.set(key, value2); + return this; +} +__name(stackSet, "stackSet"); +Stack.prototype.clear = stackClear; +Stack.prototype["delete"] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; +function arrayLikeKeys(value2, inherited) { + var result = isArray(value2) || isArguments(value2) ? baseTimes(value2.length, String) : []; + var length = result.length, skipIndexes = !!length; + for (var key in value2) { + if ((inherited || hasOwnProperty.call(value2, key)) && !(skipIndexes && (key == "length" || isIndex(key, length)))) { + result.push(key); + } + } + return result; +} +__name(arrayLikeKeys, "arrayLikeKeys"); +function assignValue(object93, key, value2) { + var objValue = object93[key]; + if (!(hasOwnProperty.call(object93, key) && eq(objValue, value2)) || value2 === void 0 && !(key in object93)) { + object93[key] = value2; + } +} +__name(assignValue, "assignValue"); +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; +} +__name(assocIndexOf, "assocIndexOf"); +function baseAssign(object93, source) { + return object93 && copyObject(source, keys(source), object93); +} +__name(baseAssign, "baseAssign"); +function baseClone(value2, isDeep, isFull, customizer, key, object93, stack) { + var result; + if (customizer) { + result = object93 ? customizer(value2, key, object93, stack) : customizer(value2); + } + if (result !== void 0) { + return result; + } + if (!isObject(value2)) { + return value2; + } + var isArr = isArray(value2); + if (isArr) { + result = initCloneArray(value2); + if (!isDeep) { + return copyArray(value2, result); + } + } else { + var tag = getTag(value2), isFunc = tag == funcTag || tag == genTag; + if (isBuffer(value2)) { + return cloneBuffer(value2, isDeep); + } + if (tag == objectTag || tag == argsTag || isFunc && !object93) { + if (isHostObject(value2)) { + return object93 ? value2 : {}; + } + result = initCloneObject(isFunc ? {} : value2); + if (!isDeep) { + return copySymbols(value2, baseAssign(result, value2)); + } + } else { + if (!cloneableTags[tag]) { + return object93 ? value2 : {}; + } + result = initCloneByTag(value2, tag, baseClone, isDeep); + } + } + stack || (stack = new Stack()); + var stacked = stack.get(value2); + if (stacked) { + return stacked; + } + stack.set(value2, result); + if (!isArr) { + var props = isFull ? getAllKeys(value2) : keys(value2); + } + arrayEach(props || value2, function(subValue, key2) { + if (props) { + key2 = subValue; + subValue = value2[key2]; + } + assignValue(result, key2, baseClone(subValue, isDeep, isFull, customizer, key2, value2, stack)); + }); + return result; +} +__name(baseClone, "baseClone"); +function baseCreate(proto) { + return isObject(proto) ? objectCreate(proto) : {}; +} +__name(baseCreate, "baseCreate"); +function baseGetAllKeys(object93, keysFunc, symbolsFunc) { + var result = keysFunc(object93); + return isArray(object93) ? result : arrayPush(result, symbolsFunc(object93)); +} +__name(baseGetAllKeys, "baseGetAllKeys"); +function baseGetTag(value2) { + return objectToString.call(value2); +} +__name(baseGetTag, "baseGetTag"); +function baseIsNative(value2) { + if (!isObject(value2) || isMasked(value2)) { + return false; + } + var pattern = isFunction(value2) || isHostObject(value2) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value2)); +} +__name(baseIsNative, "baseIsNative"); +function baseKeys(object93) { + if (!isPrototype(object93)) { + return nativeKeys(object93); + } + var result = []; + for (var key in Object(object93)) { + if (hasOwnProperty.call(object93, key) && key != "constructor") { + result.push(key); + } + } + return result; +} +__name(baseKeys, "baseKeys"); +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var result = new buffer.constructor(buffer.length); + buffer.copy(result); + return result; +} +__name(cloneBuffer, "cloneBuffer"); +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array2(result).set(new Uint8Array2(arrayBuffer)); + return result; +} +__name(cloneArrayBuffer, "cloneArrayBuffer"); +function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); +} +__name(cloneDataView, "cloneDataView"); +function cloneMap(map, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map); + return arrayReduce(array, addMapEntry, new map.constructor()); +} +__name(cloneMap, "cloneMap"); +function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; +} +__name(cloneRegExp, "cloneRegExp"); +function cloneSet(set, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set); + return arrayReduce(array, addSetEntry, new set.constructor()); +} +__name(cloneSet, "cloneSet"); +function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; +} +__name(cloneSymbol, "cloneSymbol"); +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} +__name(cloneTypedArray, "cloneTypedArray"); +function copyArray(source, array) { + var index = -1, length = source.length; + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} +__name(copyArray, "copyArray"); +function copyObject(source, props, object93, customizer) { + object93 || (object93 = {}); + var index = -1, length = props.length; + while (++index < length) { + var key = props[index]; + var newValue = customizer ? customizer(object93[key], source[key], key, object93, source) : void 0; + assignValue(object93, key, newValue === void 0 ? source[key] : newValue); + } + return object93; +} +__name(copyObject, "copyObject"); +function copySymbols(source, object93) { + return copyObject(source, getSymbols(source), object93); +} +__name(copySymbols, "copySymbols"); +function getAllKeys(object93) { + return baseGetAllKeys(object93, keys, getSymbols); +} +__name(getAllKeys, "getAllKeys"); +function getMapData(map, key) { + var data2 = map.__data__; + return isKeyable(key) ? data2[typeof key == "string" ? "string" : "hash"] : data2.map; +} +__name(getMapData, "getMapData"); +function getNative(object93, key) { + var value2 = getValue(object93, key); + return baseIsNative(value2) ? value2 : void 0; +} +__name(getNative, "getNative"); +var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray; +var getTag = baseGetTag; +if (DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag || Map && getTag(new Map()) != mapTag || Promise2 && getTag(Promise2.resolve()) != promiseTag || Set && getTag(new Set()) != setTag || WeakMap && getTag(new WeakMap()) != weakMapTag) { + getTag = /* @__PURE__ */ __name(function(value2) { + var result = objectToString.call(value2), Ctor = result == objectTag ? value2.constructor : void 0, ctorString = Ctor ? toSource(Ctor) : void 0; + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: + return dataViewTag; + case mapCtorString: + return mapTag; + case promiseCtorString: + return promiseTag; + case setCtorString: + return setTag; + case weakMapCtorString: + return weakMapTag; + } + } + return result; + }, "getTag"); +} +function initCloneArray(array) { + var length = array.length, result = array.constructor(length); + if (length && typeof array[0] == "string" && hasOwnProperty.call(array, "index")) { + result.index = array.index; + result.input = array.input; + } + return result; +} +__name(initCloneArray, "initCloneArray"); +function initCloneObject(object93) { + return typeof object93.constructor == "function" && !isPrototype(object93) ? baseCreate(getPrototype(object93)) : {}; +} +__name(initCloneObject, "initCloneObject"); +function initCloneByTag(object93, tag, cloneFunc, isDeep) { + var Ctor = object93.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object93); + case boolTag: + case dateTag: + return new Ctor(+object93); + case dataViewTag: + return cloneDataView(object93, isDeep); + case float32Tag: + case float64Tag: + case int8Tag: + case int16Tag: + case int32Tag: + case uint8Tag: + case uint8ClampedTag: + case uint16Tag: + case uint32Tag: + return cloneTypedArray(object93, isDeep); + case mapTag: + return cloneMap(object93, isDeep, cloneFunc); + case numberTag: + case stringTag: + return new Ctor(object93); + case regexpTag: + return cloneRegExp(object93); + case setTag: + return cloneSet(object93, isDeep, cloneFunc); + case symbolTag: + return cloneSymbol(object93); + } +} +__name(initCloneByTag, "initCloneByTag"); +function isIndex(value2, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && (typeof value2 == "number" || reIsUint.test(value2)) && (value2 > -1 && value2 % 1 == 0 && value2 < length); +} +__name(isIndex, "isIndex"); +function isKeyable(value2) { + var type = typeof value2; + return type == "string" || type == "number" || type == "symbol" || type == "boolean" ? value2 !== "__proto__" : value2 === null; +} +__name(isKeyable, "isKeyable"); +function isMasked(func) { + return !!maskSrcKey && maskSrcKey in func; +} +__name(isMasked, "isMasked"); +function isPrototype(value2) { + var Ctor = value2 && value2.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto; + return value2 === proto; +} +__name(isPrototype, "isPrototype"); +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) { + } + try { + return func + ""; + } catch (e) { + } + } + return ""; +} +__name(toSource, "toSource"); +function cloneDeep(value2) { + return baseClone(value2, true, true); +} +__name(cloneDeep, "cloneDeep"); +function eq(value2, other) { + return value2 === other || value2 !== value2 && other !== other; +} +__name(eq, "eq"); +function isArguments(value2) { + return isArrayLikeObject(value2) && hasOwnProperty.call(value2, "callee") && (!propertyIsEnumerable.call(value2, "callee") || objectToString.call(value2) == argsTag); +} +__name(isArguments, "isArguments"); +var isArray = Array.isArray; +function isArrayLike(value2) { + return value2 != null && isLength(value2.length) && !isFunction(value2); +} +__name(isArrayLike, "isArrayLike"); +function isArrayLikeObject(value2) { + return isObjectLike(value2) && isArrayLike(value2); +} +__name(isArrayLikeObject, "isArrayLikeObject"); +var isBuffer = nativeIsBuffer || stubFalse; +function isFunction(value2) { + var tag = isObject(value2) ? objectToString.call(value2) : ""; + return tag == funcTag || tag == genTag; +} +__name(isFunction, "isFunction"); +function isLength(value2) { + return typeof value2 == "number" && value2 > -1 && value2 % 1 == 0 && value2 <= MAX_SAFE_INTEGER; +} +__name(isLength, "isLength"); +function isObject(value2) { + var type = typeof value2; + return !!value2 && (type == "object" || type == "function"); +} +__name(isObject, "isObject"); +function isObjectLike(value2) { + return !!value2 && typeof value2 == "object"; +} +__name(isObjectLike, "isObjectLike"); +function keys(object93) { + return isArrayLike(object93) ? arrayLikeKeys(object93) : baseKeys(object93); +} +__name(keys, "keys"); +function stubArray() { + return []; +} +__name(stubArray, "stubArray"); +function stubFalse() { + return false; +} +__name(stubFalse, "stubFalse"); +var clonedeep_default = cloneDeep; + +// framework/server/console.js +var Console = class { + static { + __name(this, "Console"); + } + objects = new Array(); + currentObject = false; + filename = false; + enabled = false; + enabledPaths = new Array(); + rows = new Array(); + tableName = false; + maxChars = new Array(0, 0, 0, 0, 0, 0); + padding = 4; + setFilename(filename) { + this.filename = filename; + } + createNameObject(parameter) { + if (!parameter) { + return false; + } + if (typeof parameter == "string") { + return parameter; + } + var object93 = {}; + object93[tools_default.getClassName(parameter)] = parameter; + return object93; + } + getObjectByPath(objectA) { + var objects = this.objects; + for (var c31 = 0; c31 < objects.length; c31++) { + var objectB = objects[c31]; + if (objectA.applicationPathString == objectB.applicationPathString) { + return objectB; + } + } + return false; + } + enableLog(path2) { + this.enabledPaths.push(path2); + } + register(object93) { + this.log("--------------------------", object93.getClassName()); + } + sendObjectToDebugger(object93) { + var parameters = {}; + parameters.action = "addObject"; + parameters.object = cycle.decycle(object93); + var socketManager2 = global.socketManager; + var clients = socketManager2.clients; + for (var c31 = 0; c31 < clients.length; c31++) { + var client2 = clients[c31]; + if (this.enabled) { + client2.debugMessage(parameters); + } + } + } + table(parameter1) { + if (global.clusterID == 1) { + console.table(parameter1); + } + } + warning(parameter1, parameter2, parameter3) { + if (global.clusterID == 1) { + if (parameter3) { + console.log(parameter1, parameter2, parameter3); + } else if (parameter2) { + console.log(parameter1, parameter2); + } else if (parameter1) { + console.log(tools_default.consoleColors().green(parameter1)); + } + } + } + valid(parameter1, parameter2, parameter3) { + if (global.clusterID == 1) { + if (parameter3) { + console.log(parameter1, parameter2, parameter3); + } else if (parameter2) { + console.log(tools_default.consoleColors().cyan(parameter1), tools_default.consoleColors().cyan(parameter2)); + } else if (parameter1) { + console.log(tools_default.consoleColors().green(parameter1)); + } + } + } + log(parameter1, parameter2, parameter3) { + if (parameter3) { + console.log(parameter1, parameter2, parameter3); + } else if (parameter2) { + console.log(parameter1, parameter2); + } else if (parameter1) { + var parameter1 = clonedeep_default(parameter1); + tools_default.cleanObject(parameter1); + console.log(parameter1); + } + } + setWidth(width) { + this.maxChars = width; + } + addColumn(a32, b32, c31, d31) { + var row181 = new Array(); + if (a32) { + row181.push(a32); + this.maxChars[0] = Math.max(this.maxChars[0], a32.length); + if (b32) { + row181.push(b32); + this.maxChars[1] = Math.max(this.maxChars[1], b32.length); + } + if (c31) { + row181.push(c31); + this.maxChars[2] = Math.max(this.maxChars[2], c31.length); + } + if (d31) { + row181.push(d31); + this.maxChars[3] = Math.max(this.maxChars[3], d31.length); + } + } + this.rows.push(row181); + } + logTable() { + for (var i = 0; i < this.rows.length; i++) { + var row181 = this.rows[i]; + if (row181[0]) { + console.log(" ", row181[0].padEnd(this.maxChars[0] + this.padding), row181[1]); + } else if (row181[0]) { + } + } + console.log("\n"); + this.rows = new Array(); + } +}; +var console_default = new Console(); + +// framework/unify/querySQL.js +var querySQL = class { + static { + __name(this, "querySQL"); + } + __className = "querySQL"; + type = "select"; + columns = new Array(); + table; + sync = true; + values = new Array(); + objects = new Array(); + where = new Array(); + groups = new Array(); + union = new Array(); + order = new Array(); + direction; + limit; + count; + from; + to; + joins = new Array(); + filter = false; + filterAddress = ""; + constructor(query) { + if (query) { + var items = Object.entries(query); + var queryString = ""; + for (var c31 = 0; c31 < items.length; c31++) { + var currentQuery = items[c31]; + var name = tools_default.getClassNameByEntry(currentQuery); + var value2 = tools_default.getObjectByEntry(currentQuery); + this[name] = value2; + } + } + } + orderBy(order) { + this.order.push(order); + } + addUnion(unionQuery) { + this.union.push(unionQuery); + } + setFilterAddress(filter) { + this.filterAddress = filter; + } + setFilter(filterAddress) { + this.filter = filterAddress; + } + addJoin(join) { + if (!join.name) { + console.error("join requires name", this, join); + } + this.joins.push(join); + } + addColumn(columnName) { + this.columns.push(columnName); + } + addGroup(columnName) { + var group = new Object(); + group.columnName = columnName; + this.groups.push(group); + } + getWhereByColumnName(name) { + for (var i = 0; i < this.where.length; i++) { + var where = this.where[i]; + if (where.columnName == name) { + return where.value; + } + } + return false; + } + find(columnName, value2, type = "=", quotation = true, or = false) { + var where = {}; + where.columnName = columnName; + where.value = value2; + where.type = type; + where.quotation = quotation; + where.or = or; + this.where.push(where); + } + getColumnByName(name) { + for (var i = 0; i < this.values.length; i++) { + var column31 = this.values[i]; + if (column31.name == name) { + return column31; + } + } + return false; + } + setColumn(columnName, value2) { + if (typeof value2 == "boolean") { + if (value2) { + value2 = "true"; + } else { + value2 = "false"; + } + } + var column31 = {}; + column31.name = columnName; + column31.value = value2; + this.values.push(column31); + } + setValue(columnName, value2) { + var column31 = {}; + if (typeof value2 == "boolean") { + if (value2) { + value2 = "true"; + } else { + value2 = "false"; + } + } + column31.name = columnName; + column31.value = value2; + this.values.push(column31); + } + set(columnName, value2) { + var column31 = {}; + column31.name = columnName; + column31.value = value2; + this.values.push(column31); + } + getColumnNames() { + var columnNames = new Array(); + for (var c31 = 0; c31 < this.values.length; c31++) { + columnNames.push(this.values[c31].name); + } + return columnNames.join(", "); + } + getValues() { + var values = new Array(); + for (var c31 = 0; c31 < this.values.length; c31++) { + values.push(this.values[c31].value); + } + return values; + } + extractColumns(object93, queryName) { + var children = object93.getChildren(); + this.addColumn(queryName + ".id"); + for (var c31 = 0; c31 < children.length; c31++) { + var child = children[c31]; + if (child.datatype) { + this.addColumn(queryName + "." + child.propertyName); + } + if (child.type == "table") { + var name = child.propertyName; + var columnName = name + "_id"; + this.addColumn(queryName + "." + columnName); + } + } + } + /* doesnt make sense + addRows( rows ) { + + for (var i = 0; i < rows.length; i++) { + + this.addRow( rows[i] ); + + } + + } + */ + addRow(row181) { + const entries = Object.entries(row181); + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + this.addColumn(entry[0]); + this.setColumn(entry[0], entry[1]); + } + } + addObject(object93) { + if (this.objects.length == 0) { + this.table = tools_default.getTableName(object93); + if (!this.table) { + this.table = tools_default.getTableName(object93.parent); + this.setColumn(object93.propertyName, object93.value); + } else { + if (object93.user && object93.user.id) { + var properties = object93.getProperties(); + for (var c31 = 0; c31 < properties.length; c31++) { + var property2 = properties[c31]; + if (property2.value == "userplaceholder" && property2.name != "user") { + this.setColumn(property2.name + "_id", object93.user.id); + } + } + } + var children = object93.getChildren(); + for (var c31 = 0; c31 < children.length; c31++) { + var child = children[c31]; + if (child.datatype) { + if (typeof child.constraints == "object") { + if (child.constraints.includes("AUTOINCREMENT")) { + continue; + } + } + this.setColumn(child.propertyName, child.value, child.extendsClass("table")); + } + if (child.type == "table" && child.extendsTable()) { + var name = child.propertyName; + var columnName = name + "_id"; + var id2 = child.id; + if (id2) { + this.setColumn(columnName, id2); + } + } + } + } + if (this.type.toLowerCase() == "update") { + this.find("id", object93.id); + } + } + this.objects.push(object93); + } + queryUpdateChildren() { + var objects = this.objects; + var id2 = 0; + for (var c31 = 0; c31 < objects.length; c31++) { + var object93 = objects[c31]; + var values = new Array(); + var children = object93.getChildren(); + for (var c31 = 0; c31 < children.length; c31++) { + var child = children[c31]; + if (child.datatype) { + values.push(child.value); + } + } + values.push(object93.id); + } + } +}; + +// framework/unify/joinSQL.js +var joinSide = class { + static { + __name(this, "joinSide"); + } + table; + column; +}; +var joinSQL = class extends querySQL { + static { + __name(this, "joinSQL"); + } + __className = "joinSQL"; + type = "join"; + left = new joinSide(); + right = new joinSide(); + joins = new Array(); + querys = new Array(); + addJoin(join) { + this.joins.push(join); + } + addQuery(query) { + this.querys.push(query); + } +}; + +// framework/server/collection/collection.queryChildren.js +var queryChildren = class { + static { + __name(this, "queryChildren"); + } + createQuery(joinTableName, joinQuery, id2) { + var query = new querySQL(); + query.table = joinTableName; + query.debug = joinQuery.debug; + query.find(this.collection.getLeft() + "_id", id2); + return query; + } + createJoin(joinQuery) { + var join = new joinSQL(joinQuery); + join.table = this.collection.tableName; + join.name = "children"; + join.left.table = join.name; + join.right.column = this.collection.getRight() + "_id"; + join.find("signed", "true"); + return join; + } + query(joinQuery, filterObject) { + var object93 = this.collection.getObject(); + var leftTable = this.collection.getParentName(); + var rightTable = object93.propertyName; + var id2 = this.collection.getID(object93); + var joinTableName = leftTable + "_" + rightTable; + var query = this.createQuery(joinTableName, joinQuery, id2); + var join = this.createJoin(joinQuery, join); + if (filterObject) { + this.collection.filterQuery(join, filterObject); + if (filterObject.search) { + this.collection.searchQuery(join, filterObject); + } + } + query.addJoin(join); + var result = global.database.query(query); + return result; + } +}; + +// framework/server/collection/collection.queryRoot.js +var queryRoot = class { + static { + __name(this, "queryRoot"); + } + prepareSelectQuery(query, object93, userQuery) { + query.table = this.collection.getTableName(); + query.type = "select"; + query.setFilterAddress("./"); + query.extractColumns(object93, query.table); + query.find("signed", "true"); + query.find("joined", "false"); + query.debug = userQuery.debug; + return query; + } + createChildrenJoin(joinTableName, collectionObject, object93) { + var childObject = new collectionObject.object(); + var childObjectName = tools_default.getClassName(childObject); + var childrenJoin = new joinSQL(); + childrenJoin.table = childObjectName; + childrenJoin.joinType = "INNER"; + childrenJoin.name = "childrenJoin"; + childrenJoin.left.table = joinTableName; + childrenJoin.left.column = collectionObject.getRight() + "_id"; + childrenJoin.right.table = childrenJoin.name; + childrenJoin.right.column = "id"; + childrenJoin.find("signed", "true"); + childrenJoin.find("joined", "true"); + return childrenJoin; + } + createParentJoin(joinTableName, collectionObject) { + var parentJoin = new joinSQL(); + parentJoin.table = this.collection.getTableName(); + parentJoin.joinType = "INNER"; + parentJoin.name = "parentJoin"; + parentJoin.left.table = joinTableName; + parentJoin.left.column = collectionObject.getLeft() + "_id"; + parentJoin.right.table = parentJoin.name; + parentJoin.right.column = "id"; + return parentJoin; + } + createJoinQuery(joinTableName, object93) { + var query = new querySQL(); + query.table = joinTableName; + query.type = "select"; + query.extractColumns(object93, "parentJoin"); + return query; + } + searchChildrenJoin(child, childrenJoin, filterObject) { + if (filterObject.search) { + var searchables = filterObject.search.findPath("./" + child.propertyName); + for (var i = 0; i < searchables.length; i++) { + var currentSearchable = searchables[i]; + var columnName = currentSearchable.getColumnName(); + var searchValue = currentSearchable.getValue(); + var operator = currentSearchable.getOperator(); + if (!searchValue) { + var searchValue = ""; + } + childrenJoin.find(columnName, searchValue, operator, true, true); + } + } + } + composeJoinQuery(query, collectionObject, childrenJoin, parentJoin) { + query.addGroup(collectionObject.getLeft() + "_id"); + query.addJoin(childrenJoin); + query.addJoin(parentJoin); + } + createJoinTableName(collectionObject) { + var leftTable = this.collection.getTableName(); + var rightTable = collectionObject.propertyName; + var joinTableName = leftTable + "_" + rightTable; + return joinTableName; + } + queryFilterChild(unionQuery, object93, child, filterObject) { + var collectionObject = object93[child.propertyName]; + var tableName = collectionObject.tableName; + var joinTableName = this.createJoinTableName(collectionObject); + var joinQuery = this.createJoinQuery(joinTableName, object93); + var childrenJoin = this.createChildrenJoin(joinTableName, collectionObject, object93); + var parentJoin = this.createParentJoin(joinTableName, collectionObject); + this.composeJoinQuery(joinQuery, collectionObject, childrenJoin, parentJoin); + this.searchChildrenJoin(child, childrenJoin, filterObject); + unionQuery.addUnion(joinQuery); + } + queryChildren(filterObject, unionQuery, client2) { + var children = filterObject.getChildren(); + var joined = false; + for (var c31 = 0; c31 < children.length; c31++) { + var child = children[c31]; + if (child.type == "collection") { + var object93 = new this.collection.object(); + core.parse(object93, client2); + if (filterObject.search && filterObject.search.findPath("./" + child.propertyName)) { + this.queryFilterChild(unionQuery, object93, child, filterObject); + } + } + } + } + query(userQuery, filterObject, client2) { + var core3 = this.collection.getCore(); + var object93 = new this.collection.object(); + var query = new querySQL(); + this.prepareSelectQuery(query, object93, userQuery); + this.collection.searchQuery(query, filterObject); + var unionQuery = new querySQL(); + unionQuery.addUnion(query); + this.collection.filterQuery(unionQuery, filterObject); + this.queryChildren(filterObject, unionQuery, client2); + unionQuery.debug = userQuery.debug; + var parentResult = global.database.query(unionQuery); + return parentResult; + } +}; + +// framework/server/collection/collection.queryCount.js +var queryCount = class { + static { + __name(this, "queryCount"); + } + createJoin() { + var join = new joinSQL(); + join.table = this.tableName; + join.name = "children"; + join.left.table = join.name; + join.right.column = this.getRight() + "_id"; + join.find("signed", "true"); + return join; + } + createQuery() { + var object93 = this.getObject(); + var leftTable = this.parentName; + var rightTable = object93.propertyName; + var id2 = this.collection.getID(); + var joinTableName = leftTable + "_" + rightTable; + var query = new querySQL(); + query.table = joinTableName; + query.find(this.getLeft() + "_id", id2); + return query; + } + query() { + var query = this.createQuery(); + var join = this.createJoin(); + query.addJoin(join); + return global.database.query(query).length; + } +}; + +// framework/server/collection/collection.js +var collection2 = class { + static { + __name(this, "collection"); + } + __className = "collection"; + queryChildren = new queryChildren(); + queryRoot = new queryRoot(); + queryCount = new queryCount(); + constructor() { + this.queryChildren.collection = this; + this.queryRoot.collection = this; + this.queryCount.collection = this; + } + querySelect(userQuery, filterObject, client2) { + if (!userQuery) { + userQuery = new querySQL(); + } + if (this.parent) { + return this.queryChildren.query(userQuery, filterObject); + } else { + return this.queryRoot.query(userQuery, filterObject, client2); + } + } + countRows() { + return this.queryCount.query(); + } + filterQuery(query, filterObject) { + this.prepareOrder(query, filterObject); + if (filterObject.direction) { + query.direction = filterObject.direction; + } + if (filterObject.limit) { + query.limit = filterObject.limit; + } + if (filterObject.from) { + query.offset = filterObject.from; + } + if (filterObject.offset) { + query.offset = filterObject.offset; + } + } + prepareOrder(unionQuery, filterObject) { + if (filterObject.order) { + var searchable2 = filterObject.order.findPath(".")[0]; + if (searchable2) { + var columnName = searchable2.getColumnName(); + unionQuery.orderBy(columnName); + } + } + } + searchQuery(query, filterObject) { + if (filterObject.search) { + var searchables = filterObject.search.findPath("."); + for (var i = 0; i < searchables.length; i++) { + var currentSearchable = searchables[i]; + var columnName = currentSearchable.getColumnName(); + var searchValue = currentSearchable.getValue(); + var operator = currentSearchable.getOperator(); + if (!searchValue) { + var searchValue = ""; + } + query.find(columnName, searchValue, operator, true, true); + } + } + } + getID(object93) { + var id2 = object93.id; + if (!id2) { + id2 = object93.parent.id; + } + if (!id2) { + id2 = this.id; + } + return id2; + } + rowExists(id2) { + var rows = this.rows; + for (var i = 0; i < rows.length; i++) { + var currentChild = rows[i]; + if (id2 == currentChild.id) { + return true; + } + } + return false; + } + getRowByID(id2) { + var rows = this.rows; + for (var i = 0; i < rows.length; i++) { + var currentChild = rows[i]; + if (id2 == currentChild.id) { + return currentChild; + } + } + return false; + } + findID(rows, id2) { + for (var i = 0; i < rows.length; i++) { + var currentChild = rows[i]; + console.log("find id", id2, currentChild.id); + if (id2 == currentChild.id) { + return true; + } + } + return false; + } + delete(object93) { + this.remove(object93); + } + remove(object93) { + var row_id = object93.id; + var joinTable = this.tableName + "_" + this.propertyName; + var query = new querySQL(); + query.type = "delete"; + query.table = joinTable; + query.find(this.getLeft() + "_id", this.parent.id); + query.find(this.getRight() + "_id", row_id); + global.database.query(query); + } + add(object93) { + var row_id = object93.id; + var query = new querySQL(); + var parentName = this.getParentName(); + var joinTable = parentName + "_" + this.propertyName; + query.type = "insert"; + query.table = joinTable; + query.setColumn(this.getLeft() + "_id", this.parent.id); + query.setColumn(this.getRight() + "_id", row_id); + global.database.query(query); + } + getObject() { + if (this.propertyName == "storageCollection") { + return this.parent; + } else { + return this; + } + } + queryInsert(parent_id, last_insert_id) { + var joinTable = this.parentName + "_" + this.propertyName; + var left = this.getLeft(); + var right = this.getRight(); + var query = new querySQL(); + query.type = "insert"; + query.table = joinTable; + query.setValue(right + "_id", last_insert_id); + query.setValue(left + "_id", parent_id); + return global.database.query(query); + } +}; + +// framework/unify/emptyObject.js +var emptyObject = class { + static { + __name(this, "emptyObject"); + } +}; + +// framework/unify/purify.js +function _typeof(obj) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj2) { + return typeof obj2; + } : function(obj2) { + return obj2 && "function" == typeof Symbol && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2; + }, _typeof(obj); +} +__name(_typeof, "_typeof"); +function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || /* @__PURE__ */ __name(function _setPrototypeOf2(o2, p2) { + o2.__proto__ = p2; + return o2; + }, "_setPrototypeOf"); + return _setPrototypeOf(o, p); +} +__name(_setPrototypeOf, "_setPrototypeOf"); +function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) + return false; + if (Reflect.construct.sham) + return false; + if (typeof Proxy === "function") + return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() { + })); + return true; + } catch (e) { + return false; + } +} +__name(_isNativeReflectConstruct, "_isNativeReflectConstruct"); +function _construct(Parent, args, Class) { + if (_isNativeReflectConstruct()) { + _construct = Reflect.construct; + } else { + _construct = /* @__PURE__ */ __name(function _construct2(Parent2, args2, Class2) { + var a32 = [null]; + a32.push.apply(a32, args2); + var Constructor = Function.bind.apply(Parent2, a32); + var instance = new Constructor(); + if (Class2) + _setPrototypeOf(instance, Class2.prototype); + return instance; + }, "_construct"); + } + return _construct.apply(null, arguments); +} +__name(_construct, "_construct"); +function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); +} +__name(_toConsumableArray, "_toConsumableArray"); +function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) + return _arrayLikeToArray(arr); +} +__name(_arrayWithoutHoles, "_arrayWithoutHoles"); +function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) + return Array.from(iter); +} +__name(_iterableToArray, "_iterableToArray"); +function _unsupportedIterableToArray(o, minLen) { + if (!o) + return; + if (typeof o === "string") + return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) + n = o.constructor.name; + if (n === "Map" || n === "Set") + return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) + return _arrayLikeToArray(o, minLen); +} +__name(_unsupportedIterableToArray, "_unsupportedIterableToArray"); +function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) + len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) + arr2[i] = arr[i]; + return arr2; +} +__name(_arrayLikeToArray, "_arrayLikeToArray"); +function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +__name(_nonIterableSpread, "_nonIterableSpread"); +var hasOwnProperty2 = Object.hasOwnProperty; +var setPrototypeOf = Object.setPrototypeOf; +var isFrozen = Object.isFrozen; +var getPrototypeOf = Object.getPrototypeOf; +var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +var freeze = Object.freeze; +var seal = Object.seal; +var create = Object.create; +var _ref = typeof Reflect !== "undefined" && Reflect; +var apply = _ref.apply; +var construct = _ref.construct; +if (!apply) { + apply = /* @__PURE__ */ __name(function apply2(fun, thisValue, args) { + return fun.apply(thisValue, args); + }, "apply"); +} +if (!freeze) { + freeze = /* @__PURE__ */ __name(function freeze2(x) { + return x; + }, "freeze"); +} +if (!seal) { + seal = /* @__PURE__ */ __name(function seal2(x) { + return x; + }, "seal"); +} +if (!construct) { + construct = /* @__PURE__ */ __name(function construct2(Func, args) { + return _construct(Func, _toConsumableArray(args)); + }, "construct"); +} +var arrayForEach = unapply(Array.prototype.forEach); +var arrayPop = unapply(Array.prototype.pop); +var arrayPush2 = unapply(Array.prototype.push); +var stringToLowerCase = unapply(String.prototype.toLowerCase); +var stringMatch = unapply(String.prototype.match); +var stringReplace = unapply(String.prototype.replace); +var stringIndexOf = unapply(String.prototype.indexOf); +var stringTrim = unapply(String.prototype.trim); +var regExpTest = unapply(RegExp.prototype.test); +var typeErrorCreate = unconstruct(TypeError); +function unapply(func) { + return function(thisArg) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + return apply(func, thisArg, args); + }; +} +__name(unapply, "unapply"); +function unconstruct(func) { + return function() { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + return construct(func, args); + }; +} +__name(unconstruct, "unconstruct"); +function addToSet(set, array, transformCaseFunc) { + transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase; + if (setPrototypeOf) { + setPrototypeOf(set, null); + } + var l = array.length; + while (l--) { + var element2 = array[l]; + if (typeof element2 === "string") { + var lcElement = transformCaseFunc(element2); + if (lcElement !== element2) { + if (!isFrozen(array)) { + array[l] = lcElement; + } + element2 = lcElement; + } + } + set[element2] = true; + } + return set; +} +__name(addToSet, "addToSet"); +function clone(object93) { + var newObject = create(null); + var property2; + for (property2 in object93) { + if (apply(hasOwnProperty2, object93, [property2])) { + newObject[property2] = object93[property2]; + } + } + return newObject; +} +__name(clone, "clone"); +function lookupGetter(object93, prop) { + while (object93 !== null) { + var desc = getOwnPropertyDescriptor(object93, prop); + if (desc) { + if (desc.get) { + return unapply(desc.get); + } + if (typeof desc.value === "function") { + return unapply(desc.value); + } + } + object93 = getPrototypeOf(object93); + } + function fallbackValue(element2) { + console.warn("fallback value for", element2); + return null; + } + __name(fallbackValue, "fallbackValue"); + return fallbackValue; +} +__name(lookupGetter, "lookupGetter"); +var html$1 = freeze(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "shadow", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]); +var svg$1 = freeze(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]); +var svgFilters = freeze(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]); +var svgDisallowed = freeze(["animate", "color-profile", "cursor", "discard", "fedropshadow", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]); +var mathMl$1 = freeze(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover"]); +var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]); +var text = freeze(["#text"]); +var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "pattern", "placeholder", "playsinline", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "xmlns", "slot"]); +var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]); +var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnsalign", "columnlines", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lspace", "lquote", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]); +var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]); +var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); +var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm); +var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); +var ARIA_ATTR = seal(/^aria-[\-\w]+$/); +var IS_ALLOWED_URI = seal( + /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i + // eslint-disable-line no-useless-escape +); +var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); +var ATTR_WHITESPACE = seal( + /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g + // eslint-disable-line no-control-regex +); +var DOCTYPE_NAME = seal(/^html$/i); +var getGlobal = /* @__PURE__ */ __name(function getGlobal2() { + return typeof window === "undefined" ? null : window; +}, "getGlobal"); +var _createTrustedTypesPolicy = /* @__PURE__ */ __name(function _createTrustedTypesPolicy2(trustedTypes, document2) { + if (_typeof(trustedTypes) !== "object" || typeof trustedTypes.createPolicy !== "function") { + return null; + } + var suffix = null; + var ATTR_NAME = "data-tt-policy-suffix"; + if (document2.currentScript && document2.currentScript.hasAttribute(ATTR_NAME)) { + suffix = document2.currentScript.getAttribute(ATTR_NAME); + } + var policyName = "dompurify" + (suffix ? "#" + suffix : ""); + try { + return trustedTypes.createPolicy(policyName, { + createHTML: /* @__PURE__ */ __name(function createHTML(html2) { + return html2; + }, "createHTML"), + createScriptURL: /* @__PURE__ */ __name(function createScriptURL(scriptUrl) { + return scriptUrl; + }, "createScriptURL") + }); + } catch (_) { + console.warn("TrustedTypes policy " + policyName + " could not be created."); + return null; + } +}, "_createTrustedTypesPolicy"); +function createDOMPurify() { + var window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); + var DOMPurify = /* @__PURE__ */ __name(function DOMPurify2(root2) { + return createDOMPurify(root2); + }, "DOMPurify"); + DOMPurify.version = "2.3.10"; + DOMPurify.removed = []; + if (!window2 || !window2.document || window2.document.nodeType !== 9) { + DOMPurify.isSupported = false; + return DOMPurify; + } + var originalDocument = window2.document; + var document2 = window2.document; + var DocumentFragment = window2.DocumentFragment, HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window2.HTMLFormElement, DOMParser = window2.DOMParser, trustedTypes = window2.trustedTypes; + var ElementPrototype = Element.prototype; + var cloneNode = lookupGetter(ElementPrototype, "cloneNode"); + var getNextSibling = lookupGetter(ElementPrototype, "nextSibling"); + var getChildNodes = lookupGetter(ElementPrototype, "childNodes"); + var getParentNode = lookupGetter(ElementPrototype, "parentNode"); + if (typeof HTMLTemplateElement === "function") { + var template = document2.createElement("template"); + if (template.content && template.content.ownerDocument) { + document2 = template.content.ownerDocument; + } + } + var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument); + var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML("") : ""; + var _document = document2, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName; + var importNode = originalDocument.importNode; + var documentMode = {}; + try { + documentMode = clone(document2).documentMode ? document2.documentMode : {}; + } catch (_) { + } + var hooks = {}; + DOMPurify.isSupported = typeof getParentNode === "function" && implementation && typeof implementation.createHTMLDocument !== "undefined" && documentMode !== 9; + var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE; + var IS_ALLOWED_URI$1 = IS_ALLOWED_URI; + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text))); + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml))); + var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, { + tagNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + attributeNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + allowCustomizedBuiltInElements: { + writable: true, + configurable: false, + enumerable: true, + value: false + } + })); + var FORBID_TAGS = null; + var FORBID_ATTR = null; + var ALLOW_ARIA_ATTR = true; + var ALLOW_DATA_ATTR = true; + var ALLOW_UNKNOWN_PROTOCOLS = false; + var SAFE_FOR_TEMPLATES = false; + var WHOLE_DOCUMENT = false; + var SET_CONFIG = false; + var FORCE_BODY = false; + var RETURN_DOM = false; + var RETURN_DOM_FRAGMENT = false; + var RETURN_TRUSTED_TYPE = false; + var SANITIZE_DOM = true; + var KEEP_CONTENT = true; + var IN_PLACE = false; + var USE_PROFILES = {}; + var FORBID_CONTENTS = null; + var DEFAULT_FORBID_CONTENTS = addToSet({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]); + var DATA_URI_TAGS = null; + var DEFAULT_DATA_URI_TAGS = addToSet({}, ["audio", "video", "img", "source", "image", "track"]); + var URI_SAFE_ATTRIBUTES = null; + var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ["alt", "class", "for", "id", "label", "name", "pattern", "placeholder", "role", "summary", "title", "value", "style", "xmlns"]); + var MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; + var SVG_NAMESPACE = "http://www.w3.org/2000/svg"; + var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; + var NAMESPACE = HTML_NAMESPACE; + var IS_EMPTY_INPUT = false; + var PARSER_MEDIA_TYPE; + var SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"]; + var DEFAULT_PARSER_MEDIA_TYPE = "text/html"; + var transformCaseFunc; + var CONFIG = null; + var formElement = document2.createElement("form"); + var isRegexOrFunction = /* @__PURE__ */ __name(function isRegexOrFunction2(testValue) { + return testValue instanceof RegExp || testValue instanceof Function; + }, "isRegexOrFunction"); + var _parseConfig = /* @__PURE__ */ __name(function _parseConfig2(cfg) { + if (CONFIG && CONFIG === cfg) { + return; + } + if (!cfg || _typeof(cfg) !== "object") { + cfg = {}; + } + cfg = clone(cfg); + PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes + SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; + transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? function(x) { + return x; + } : stringToLowerCase; + ALLOWED_TAGS = "ALLOWED_TAGS" in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = "ALLOWED_ATTR" in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR; + URI_SAFE_ATTRIBUTES = "ADD_URI_SAFE_ATTR" in cfg ? addToSet( + clone(DEFAULT_URI_SAFE_ATTRIBUTES), + // eslint-disable-line indent + cfg.ADD_URI_SAFE_ATTR, + // eslint-disable-line indent + transformCaseFunc + // eslint-disable-line indent + ) : DEFAULT_URI_SAFE_ATTRIBUTES; + DATA_URI_TAGS = "ADD_DATA_URI_TAGS" in cfg ? addToSet( + clone(DEFAULT_DATA_URI_TAGS), + // eslint-disable-line indent + cfg.ADD_DATA_URI_TAGS, + // eslint-disable-line indent + transformCaseFunc + // eslint-disable-line indent + ) : DEFAULT_DATA_URI_TAGS; + FORBID_CONTENTS = "FORBID_CONTENTS" in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS; + FORBID_TAGS = "FORBID_TAGS" in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {}; + FORBID_ATTR = "FORBID_ATTR" in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {}; + USE_PROFILES = "USE_PROFILES" in cfg ? cfg.USE_PROFILES : false; + ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; + RETURN_DOM = cfg.RETURN_DOM || false; + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; + RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; + FORCE_BODY = cfg.FORCE_BODY || false; + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; + IN_PLACE = cfg.IN_PLACE || false; + IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1; + NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE; + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) { + CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) { + CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === "boolean") { + CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements; + } + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + if (USE_PROFILES) { + ALLOWED_TAGS = addToSet({}, _toConsumableArray(text)); + ALLOWED_ATTR = []; + if (USE_PROFILES.html === true) { + addToSet(ALLOWED_TAGS, html$1); + addToSet(ALLOWED_ATTR, html); + } + if (USE_PROFILES.svg === true) { + addToSet(ALLOWED_TAGS, svg$1); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.svgFilters === true) { + addToSet(ALLOWED_TAGS, svgFilters); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.mathMl === true) { + addToSet(ALLOWED_TAGS, mathMl$1); + addToSet(ALLOWED_ATTR, mathMl); + addToSet(ALLOWED_ATTR, xml); + } + } + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = clone(ALLOWED_TAGS); + } + addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = clone(ALLOWED_ATTR); + } + addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); + } + if (cfg.ADD_URI_SAFE_ATTR) { + addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); + } + if (cfg.FORBID_CONTENTS) { + if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { + FORBID_CONTENTS = clone(FORBID_CONTENTS); + } + addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); + } + if (KEEP_CONTENT) { + ALLOWED_TAGS["#text"] = true; + } + if (WHOLE_DOCUMENT) { + addToSet(ALLOWED_TAGS, ["html", "head", "body"]); + } + if (ALLOWED_TAGS.table) { + addToSet(ALLOWED_TAGS, ["tbody"]); + delete FORBID_TAGS.tbody; + } + if (freeze) { + freeze(cfg); + } + CONFIG = cfg; + }, "_parseConfig"); + var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ["mi", "mo", "mn", "ms", "mtext"]); + var HTML_INTEGRATION_POINTS = addToSet({}, ["foreignobject", "desc", "title", "annotation-xml"]); + var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ["title", "style", "font", "a", "script"]); + var ALL_SVG_TAGS = addToSet({}, svg$1); + addToSet(ALL_SVG_TAGS, svgFilters); + addToSet(ALL_SVG_TAGS, svgDisallowed); + var ALL_MATHML_TAGS = addToSet({}, mathMl$1); + addToSet(ALL_MATHML_TAGS, mathMlDisallowed); + var _checkValidNamespace = /* @__PURE__ */ __name(function _checkValidNamespace2(element2) { + var parent = getParentNode(element2); + if (!parent || !parent.tagName) { + parent = { + namespaceURI: HTML_NAMESPACE, + tagName: "template" + }; + } + var tagName = stringToLowerCase(element2.tagName); + var parentTagName = stringToLowerCase(parent.tagName); + if (element2.namespaceURI === SVG_NAMESPACE) { + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === "svg"; + } + if (parent.namespaceURI === MATHML_NAMESPACE) { + return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); + } + return Boolean(ALL_SVG_TAGS[tagName]); + } + if (element2.namespaceURI === MATHML_NAMESPACE) { + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === "math"; + } + if (parent.namespaceURI === SVG_NAMESPACE) { + return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName]; + } + return Boolean(ALL_MATHML_TAGS[tagName]); + } + if (element2.namespaceURI === HTML_NAMESPACE) { + if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { + return false; + } + if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { + return false; + } + return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); + } + return false; + }, "_checkValidNamespace"); + var _forceRemove = /* @__PURE__ */ __name(function _forceRemove2(node) { + arrayPush2(DOMPurify.removed, { + element: node + }); + try { + node.parentNode.removeChild(node); + } catch (_) { + try { + node.outerHTML = emptyHTML; + } catch (_2) { + node.remove(); + } + } + }, "_forceRemove"); + var _removeAttribute = /* @__PURE__ */ __name(function _removeAttribute2(name, node) { + try { + arrayPush2(DOMPurify.removed, { + attribute: node.getAttributeNode(name), + from: node + }); + } catch (_) { + arrayPush2(DOMPurify.removed, { + attribute: null, + from: node + }); + } + node.removeAttribute(name); + if (name === "is" && !ALLOWED_ATTR[name]) { + if (RETURN_DOM || RETURN_DOM_FRAGMENT) { + try { + _forceRemove(node); + } catch (_) { + } + } else { + try { + node.setAttribute(name, ""); + } catch (_) { + } + } + } + }, "_removeAttribute"); + var _initDocument = /* @__PURE__ */ __name(function _initDocument2(dirty) { + var doc; + var leadingWhitespace; + if (FORCE_BODY) { + dirty = "" + dirty; + } else { + var matches = stringMatch(dirty, /^[\r\n\t ]+/); + leadingWhitespace = matches && matches[0]; + } + if (PARSER_MEDIA_TYPE === "application/xhtml+xml") { + dirty = '' + dirty + ""; + } + var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty; + if (NAMESPACE === HTML_NAMESPACE) { + try { + doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); + } catch (_) { + } + } + if (!doc || !doc.documentElement) { + doc = implementation.createDocument(NAMESPACE, "template", null); + try { + doc.documentElement.innerHTML = IS_EMPTY_INPUT ? "" : dirtyPayload; + } catch (_) { + } + } + var body61 = doc.body || doc.documentElement; + if (dirty && leadingWhitespace) { + body61.insertBefore(document2.createTextNode(leadingWhitespace), body61.childNodes[0] || null); + } + if (NAMESPACE === HTML_NAMESPACE) { + return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0]; + } + return WHOLE_DOCUMENT ? doc.documentElement : body61; + }, "_initDocument"); + var _createIterator = /* @__PURE__ */ __name(function _createIterator2(root2) { + return createNodeIterator.call( + root2.ownerDocument || root2, + root2, + // eslint-disable-next-line no-bitwise + NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, + null, + false + ); + }, "_createIterator"); + var _isClobbered = /* @__PURE__ */ __name(function _isClobbered2(elm) { + return elm instanceof HTMLFormElement && (typeof elm.nodeName !== "string" || typeof elm.textContent !== "string" || typeof elm.removeChild !== "function" || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== "function" || typeof elm.setAttribute !== "function" || typeof elm.namespaceURI !== "string" || typeof elm.insertBefore !== "function"); + }, "_isClobbered"); + var _isNode = /* @__PURE__ */ __name(function _isNode2(object93) { + return _typeof(Node) === "object" ? object93 instanceof Node : object93 && _typeof(object93) === "object" && typeof object93.nodeType === "number" && typeof object93.nodeName === "string"; + }, "_isNode"); + var _executeHook = /* @__PURE__ */ __name(function _executeHook2(entryPoint, currentNode, data2) { + if (!hooks[entryPoint]) { + return; + } + arrayForEach(hooks[entryPoint], function(hook) { + hook.call(DOMPurify, currentNode, data2, CONFIG); + }); + }, "_executeHook"); + var _sanitizeElements = /* @__PURE__ */ __name(function _sanitizeElements2(currentNode) { + var content; + _executeHook("beforeSanitizeElements", currentNode, null); + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) { + _forceRemove(currentNode); + return true; + } + var tagName = transformCaseFunc(currentNode.nodeName); + _executeHook("uponSanitizeElement", currentNode, { + tagName, + allowedTags: ALLOWED_TAGS + }); + if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) { + _forceRemove(currentNode); + return true; + } + if (tagName === "select" && regExpTest(/