{"id":20063792,"url":"https://github.com/hiperiondev/ladder-editor","last_synced_at":"2025-10-19T21:01:34.934Z","repository":{"id":112267665,"uuid":"522744018","full_name":"hiperiondev/ladder-editor","owner":"hiperiondev","description":"ladder-editor","archived":false,"fork":false,"pushed_at":"2022-08-12T14:36:07.000Z","size":71,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-12T22:43:08.343Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hiperiondev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-09T00:00:44.000Z","updated_at":"2022-10-26T15:35:22.000Z","dependencies_parsed_at":"2023-05-12T07:45:45.063Z","dependency_job_id":null,"html_url":"https://github.com/hiperiondev/ladder-editor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiperiondev%2Fladder-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiperiondev%2Fladder-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiperiondev%2Fladder-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiperiondev%2Fladder-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hiperiondev","download_url":"https://codeload.github.com/hiperiondev/ladder-editor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241491804,"owners_count":19971561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T13:43:49.277Z","updated_at":"2025-10-19T21:01:34.927Z","avatar_url":"https://github.com/hiperiondev.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ladder PLC Editor\n\nTest on: [LADDER-EDITOR](https://html-preview.github.io/?url=https://raw.githubusercontent.com/hiperiondev/ladder-editor/refs/heads/main/ladder_editor.html)\n\nThe Ladder PLC Editor is a web-based application designed for creating, editing, and simulating ladder logic diagrams for Programmable Logic Controller (PLC) programming. It leverages WebSockets for real-time communication with a server, enabling seamless program management, uniform network dimensions, and dynamic visual feedback through cell state updates.\n\nThe code was created entirely with AI, so I don't consider it my own creation and therefore release it without any restrictions for the use of all mankind.\n\n### Features\n- Grid redimension\n- Row autocomplete\n- Symbol identification (Blink symbol if click in Symbol Values table)\n- Easy change symbols in code (add or modify)\n- Save and load in JSON format\n- Undo/Redo function\n- WebSocket for comunnication with external runtime    \n    \n\n### Known issues\n- Does not always scale correctly on mobile devices\n\n## WebSocket Integration Overview\n\nThe editor connects to a server at `ws://\u003cIP\u003e/ws` when \u003cIP\u003e is from webeditor was loaded, using WebSockets, facilitating real-time data exchange for program persistence and simulation. Key functionalities include:\n\n- **Saving and Loading Programs**: Store and retrieve ladder logic configurations via the server or locally as JSON files.\n- **Uniform Network Dimensions**: Ensure all networks maintain consistent sizes based on a server flag.\n- **Cell State Visualization**: Highlight active cells in yellow during simulation, reflecting server updates.\n- **Connection Status Indicator**: Display the connection and server status using a color-coded indicator (red, yellow, green).\n\nBelow, we explore each feature, detailing their implementation and interaction with WebSockets.\n\n## WebSocket Connection and Status Management\n\nThe connection status is tracked via the `wsStatus` variable, which can be:\n\n- **Disconnected**: No connection to the server (`wsStatus = \"disconnected\"`).\n- **Connected, Not Running**: Connected, but the server is not simulating (`wsStatus = \"connected_not_running\"`).\n- **Connected, Running**: Connected, and the server is simulating (`wsStatus = \"connected_running\"`).\n\nThe `updateIndicator` function reflects this status in the user interface by changing the color of a circular indicator (`#ws-indicator`):\n\n| Status                  | Indicator Color | Description                              |\n|-------------------------|-----------------|------------------------------------------|\n| Disconnected            | Red             | No server connection.                    |\n| Connected, Not Running  | Yellow          | Connected, server not simulating.        |\n| Connected, Running      | Green           | Connected, server actively simulating.   |\n\n### Connection Lifecycle\n\n- **On Open (`ws.onopen`)**: The editor sends a `{ action: \"get_flag\" }` message to retrieve server configurations, such as the `sameDimensions` flag, and sets `wsStatus` to \"connected_not_running\".\n- **On Message (`ws.onmessage`)**: Processes incoming messages to update flags, load data, or apply cell states.\n- **On Close (`ws.onclose`) or Error (`ws.onerror`)**: Sets `wsStatus` to \"disconnected\", updates the indicator, and clears active cell highlights.\n\n## Saving and Loading Programs\n\n### Saving Programs\n\nThe `saveNetworks` function handles program saving, adapting to the connection status:\n\n- **Connected Mode (`wsStatus !== \"disconnected\"`)**:\n  - Collects data from all networks, including `id`, `rows`, `cols`, and `networkData`.\n  - Serializes the data into JSON and sends it to the server with `{ action: \"save\", data: [...] }`.\n  - Displays a toast notification: \"Saved to server.\"\n- **Disconnected Mode**:\n  - Serializes network data into a formatted JSON string.\n  - Creates a `Blob` with type `application/json` and generates a downloadable file (`ladder_networks.json`) using a temporary URL.\n  - Triggers an automatic download and revokes the URL.\n\n### Loading Programs\n\nThe `initiateLoad` function manages program loading:\n\n- **Connected Mode (`wsStatus !== \"disconnected\"`)**:\n  - Sends `{ action: \"load\" }` to the server, requesting saved network data.\n  - The server responds with a message processed in `ws.onmessage` under `data.action === \"load_response\"`.\n  - The response contains an array of network objects, which are validated and used to reconstruct the editor’s state:\n    - Clears existing networks and UI elements.\n    - Creates new `Network` instances with provided `rows`, `cols`, and `id`.\n    - Validates `networkData` using `validateNetworkData` to ensure symbol and data integrity.\n    - Renders networks and updates the symbol values table.\n    - Saves the state to history for undo/redo functionality.\n  - Shows a toast: \"Loaded from server.\"\n- **Disconnected Mode**:\n  - Triggers a file input (`#loadFile`) to allow users to upload a JSON file.\n  - The `loadNetworks` function reads the file using `FileReader`:\n    - Parses the JSON content, ensuring it’s an array of network objects.\n    - Validates dimensions (`rows`, `cols`) and enforces limits (`MAX_ROWS`, `MAX_COLS`).\n    - Reconstructs networks similarly to server loading, with validation via `validateNetworkData`.\n    - Updates the UI and history.\n\n### Data Validation\n\nThe `validateNetworkData` function ensures loaded data is compatible:\n\n- Checks each cell’s `symbol` against the `symbols` object, defaulting to \"NOP\" if invalid.\n- Converts `bar` to a boolean.\n- Validates `data` arrays, ensuring entries match the symbol’s `dataEntries` and use allowed types, defaulting to the first allowed type and value \"0\" if invalid.\n\nThis robust validation prevents errors from malformed data, whether loaded from the server or a file.\n\n## Uniform Network Dimensions\n\nThe editor supports uniform network dimensions, controlled by the `sameDimensionsFlag` boolean, received from the server in `ws.onmessage` when `data.flag === \"sameDimensions\"`.\n\n### Implementation\n\n- **Adding Networks (`addNetwork`)**:\n  - If `sameDimensionsFlag` is `true` and networks exist, new networks adopt the `rows` and `cols` of the first network (`networks[0]`).\n  - Otherwise, defaults to 8x8 dimensions.\n  - Creates a new `Network` instance, renders it, and updates the UI.\n\n- **Resizing Networks (`resizeNetwork`)**:\n  - Retrieves new dimensions from input fields (`rows-${id}`, `cols-${id}`).\n  - Validates inputs (positive numbers, within `MAX_ROWS` and `MAX_COLS`).\n  - If `sameDimensionsFlag` is `true`, applies the new dimensions to all networks using `network.resize(newRows, newCols)`.\n  - If `false`, only the specified network is resized.\n  - The `resize` method:\n    - Checks for symbol truncation if new dimensions are smaller.\n    - Creates a new `networkData` array, copying valid cells and marking multi-cell symbols’ additional rows as \"occupied\".\n    - Updates input fields and re-renders the network.\n\n### Behavior\n\nWhen `sameDimensionsFlag` is enabled, the editor ensures all networks maintain identical dimensions, simplifying program design for applications requiring consistent layouts. This is particularly useful in PLC programming, where uniform network sizes can align with hardware constraints or design standards.\n\n## Visual Feedback via Cell State Updates\n\nThe editor provides real-time visual feedback during simulation by highlighting active cells, controlled by server updates.\n\n### Implementation\n\n- **Server Updates**:\n  - When the server is running (`data.status === \"running\"` in `ws.onmessage`), it sends `cell_states`, an array of objects with `networkId`, `row`, `col`, and `state` (0 or 1).\n  - The `applyCellStates` function processes these updates:\n    - Calls `setAllCellsDefault` to remove the `active` class from all cells, resetting highlights.\n    - Iterates through `cell_states`, applying the `active` class to cells where `state === 1`.\n    - Selects cells using the selector `#network-${cs.networkId} td[data-row=\"${cs.row}\"][data-col=\"${cs.col}\"]`.\n\n- **Styling**:\n  - The CSS rule `td.active { background-color: yellow; }` highlights active cells in yellow, indicating active elements like closed contacts or energized coils.\n\n- **Reset on Status Change**:\n  - If the server stops running (`data.status === \"not_running\"`) or the connection is lost (`ws.onclose`, `ws.onerror`), `setAllCellsDefault` clears all `active` classes, ensuring the UI reflects the simulation’s state.\n\n### User Experience\n\nThis feature enhances the simulation experience by visually representing the ladder logic’s execution, allowing users to monitor program behavior in real time. The yellow highlight is intuitive, aligning with common conventions in PLC programming interfaces.\n\n## Additional Interactions\n\nWhile not directly tied to WebSockets, the editor includes a blinking feature for cell selection:\n\n- Clicking a row in the symbol values table (`#symbolValues`) toggles a `blinking` class on the corresponding cell and row, using animations defined in CSS (`backgroundBlink`, `strokeBlink`, `fillBlink`).\n- This is client-side and unrelated to WebSocket updates, serving as a navigation aid rather than a simulation feature.\n\n## WebSocket Event Handlers\n\nThe following table summarizes the WebSocket event handlers and their roles:\n\n| Event       | Function                              | Description                                                                 |\n|-------------|---------------------------------------|-----------------------------------------------------------------------------|\n| `onopen`    | Sends `{ action: \"get_flag\" }`        | Initiates connection, requests server flags, sets status to \"connected_not_running\". |\n| `onmessage` | Processes flags, loads, or states     | Handles `sameDimensions` flag, `load_response`, and status/cell state updates. |\n| `onclose`   | Resets status and UI                  | Sets `wsStatus` to \"disconnected\", updates indicator, clears cell highlights. |\n| `onerror`   | Resets status and UI                  | Same as `onclose`, handling connection errors.                              |\n\n## Key Functions\n\nThe following functions are central to WebSocket integration:\n\n| Function                | Description                                                                 |\n|-------------------------|-----------------------------------------------------------------------------|\n| `saveNetworks`          | Saves network data to the server or locally based on connection status.      |\n| `initiateLoad`          | Requests data from the server or triggers local file upload.                 |\n| `addNetwork`            | Creates new networks, respecting `sameDimensionsFlag` for uniform sizes.     |\n| `resizeNetwork`         | Resizes one or all networks based on `sameDimensionsFlag`.                   |\n| `applyCellStates`       | Updates cell highlights based on server-provided state updates.              |\n| `validateNetworkData`   | Ensures loaded data is valid, correcting symbols and data entries.           |\n\n# WebSocket Communication in Ladder Editor\n\n## WebSocket Connection Lifecycle\n\n1. **Connection Establishment**:\n   - The client establishes a WebSocket connection.\n   - Upon connection, the client sends a `{ action: \"get_flag\" }` message to request the \"sameDimensions\" flag.\n   - The connection status is tracked as \"disconnected\", \"connected_not_running\", or \"connected_running\", with a visual indicator (red, yellow, green).\n\n2. **Message Handling**:\n   - The client processes incoming messages to update flags, load networks, or apply cell states during simulation.\n\n3. **Connection Closure**:\n   - On connection close or error, the client sets the status to \"disconnected\", updates the indicator to red, and resets all cells to their default state.\n\n## Client to Server Messages\n\n### 1. Get Flag\nSent when the WebSocket connection opens to request the \"sameDimensions\" flag, which likely indicates if the server expects networks with consistent dimensions.\n\n**JSON Structure**:\n```json\n{\n  \"action\": \"get_flag\"\n}\n```\n\n### 2. Save Networks\nSent to save the current network configurations to the server. The `data` field contains an array of network objects.\n\n**JSON Structure**:\n```json\n{\n  \"action\": \"save\",\n  \"data\": [network objects]\n}\n```\n\n**Example**:\n```json\n{\n  \"action\": \"save\",\n  \"data\": [\n    {\n      \"id\": 0,\n      \"rows\": 2,\n      \"cols\": 2,\n      \"networkData\": [\n        [\n          {\n            \"symbol\": \"NO\",\n            \"bar\": false,\n            \"data\": [\n              {\n                \"name\": \"value\",\n                \"type\": \"I\",\n                \"value\": \"0.0\"\n              }\n            ]\n          },\n          {\n            \"symbol\": \"CONN\",\n            \"bar\": false,\n            \"data\": []\n          }\n        ],\n        [\n          {\n            \"symbol\": \"NOP\",\n            \"bar\": true,\n            \"data\": []\n          },\n          {\n            \"symbol\": \"Q\",\n            \"bar\": false,\n            \"data\": [\n              {\n                \"name\": \"value\",\n                \"type\": \"Q\",\n                \"value\": \"0.0\"\n              }\n            ]\n          }\n        ]\n      ]\n    }\n  ]\n}\n```\n\n### 3. Load Networks\nSent to request network configurations from the server.\n\n**JSON Structure**:\n```json\n{\n  \"action\": \"load\"\n}\n```\n\n## Server to Client Messages\n\n### 1. Flag Response\nResponse to the \"get_flag\" action, providing the value of the \"sameDimensions\" flag.\n\n**JSON Structure**:\n```json\n{\n  \"flag\": \"sameDimensions\",\n  \"value\": boolean\n}\n```\n\n**Example**:\n```json\n{\n  \"flag\": \"sameDimensions\",\n  \"value\": true\n}\n```\n\n### 2. Load Response\nResponse to the \"load\" action, providing an array of network objects. The structure mirrors the save message's `data` field.\n\n**JSON Structure**:\n```json\n{\n  \"action\": \"load_response\",\n  \"data\": [network objects]\n}\n```\n\n**Example**:\n```json\n{\n  \"action\": \"load_response\",\n  \"data\": [\n    {\n      \"id\": 0,\n      \"rows\": 2,\n      \"cols\": 2,\n      \"networkData\": [\n        [\n          {\n            \"symbol\": \"NO\",\n            \"bar\": false,\n            \"data\": [\n              {\n                \"name\": \"value\",\n                \"type\": \"I\",\n                \"value\": \"0.0\"\n              }\n            ]\n          },\n          {\n            \"symbol\": \"CONN\",\n            \"bar\": false,\n            \"data\": []\n          }\n        ],\n        [\n          {\n            \"symbol\": \"NOP\",\n            \"bar\": true,\n            \"data\": []\n          },\n          {\n            \"symbol\": \"Q\",\n            \"bar\": false,\n            \"data\": [\n              {\n                \"name\": \"value\",\n                \"type\": \"Q\",\n                \"value\": \"0.0\"\n              }\n            ]\n          }\n        ]\n      ]\n    }\n  ]\n}\n```\n\n### 3. Status Updates\nThe server sends status updates to indicate whether the simulation is running or not.\n\n#### Running Status\nWhen the simulation is running, the server sends cell state updates to reflect the active/inactive status of cells.\n\n**JSON Structure**:\n```json\n{\n  \"status\": \"running\",\n  \"cell_states\": [\n    {\n      \"networkId\": number,\n      \"row\": number,\n      \"col\": number,\n      \"state\": number\n    },\n    ...\n  ]\n}\n```\n\n**Example**:\n```json\n{\n  \"status\": \"running\",\n  \"cell_states\": [\n    {\n      \"networkId\": 0,\n      \"row\": 0,\n      \"col\": 0,\n      \"state\": 1\n    },\n    {\n      \"networkId\": 0,\n      \"row\": 0,\n      \"col\": 1,\n      \"state\": 0\n    },\n    {\n      \"networkId\": 0,\n      \"row\": 1,\n      \"col\": 0,\n      \"state\": 0\n    },\n    {\n      \"networkId\": 0,\n      \"row\": 1,\n      \"col\": 1,\n      \"state\": 1\n    }\n  ]\n}\n```\n\n#### Not Running Status\nWhen the simulation is not running, the server sends a simple status message.\n\n**JSON Structure**:\n```json\n{\n  \"status\": \"not_running\"\n}\n```\n\n## Data Structures\n\n### Network Object\nRepresents a single network in the ladder logic editor.\n\n| Field         | Type       | Description                                      |\n|---------------|------------|--------------------------------------------------|\n| `id`          | Number     | Unique identifier for the network.               |\n| `rows`        | Number     | Number of rows (default 8, max 100).             |\n| `cols`        | Number     | Number of columns (default 8, max 100).          |\n| `networkData` | Array      | 2D array of cell objects representing the grid.  |\n\nEach cell in `networkData` is an object with:\n\n| Field    | Type       | Description                                      |\n|----------|------------|--------------------------------------------------|\n| `symbol` | String     | Symbol type (e.g., \"NOP\", \"CONN\", \"NO\", \"Q\").    |\n| `bar`    | Boolean    | Indicates presence of a vertical bar.            |\n| `data`   | Array      | Array of data entries for the symbol.            |\n\nEach data entry in `data` is an object with:\n\n| Field    | Type       | Description                                      |\n|----------|------------|--------------------------------------------------|\n| `name`   | String     | Name of the data entry (e.g., \"value\").          |\n| `type`   | String     | Data type (e.g., \"I\", \"Q\", \"M\").                 |\n| `value`  | String     | Value of the data entry (e.g., \"0.0\").           |\n\n### Cell State\nRepresents the state of a cell during simulation.\n\n| Field       | Type       | Description                                      |\n|-------------|------------|--------------------------------------------------|\n| `networkId` | Number     | Identifier of the network.                       |\n| `row`       | Number     | Row index of the cell.                           |\n| `col`       | Number     | Column index of the cell.                        |\n| `state`     | Number     | State of the cell (e.g., 1 for active, 0 for inactive). |\n\n## Supported Symbols and Data Types\nThe editor supports various ladder logic symbols, each with specific data entry requirements. Examples include:\n\n| Symbol | Cells | Data Entries (Name, Allowed Types)         | Pins (Left, Right)       |\n|--------|-------|--------------------------------------------|--------------------------|\n| `NOP`  | 1     | []                                         | [false, false]           |\n| `CONN` | 1     | []                                         | [true, true]             |\n| `NO`   | 1     | [value, I,Q,M,D,T,C,IW,K,QW]               | [true, true]             |\n| `Q`    | 1     | [value, Q]                                 | [true, true]             |\n\nSupported data types include: NONE, M, Q, I, Cd, Cr, Td, Tr, IW, QW, C, T, D, CSTR, REAL, MS, 10MS, 100MS, SEC, MIN, K.\n\n## Additional Notes\n- The client validates network data before sending, ensuring `rows` and `cols` are within limits (max 100) and data entries match allowed types.\n- The server controls the simulation state, sending \"running\" or \"not_running\" updates without explicit client requests to start/stop.\n- The maximum number of networks is 10, and file uploads for loading networks are limited to 10MB.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhiperiondev%2Fladder-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhiperiondev%2Fladder-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhiperiondev%2Fladder-editor/lists"}