|
9386 | 9386 | border: 1px solid #333;
|
9387 | 9387 | z-index: 9999;
|
9388 | 9388 | font-family: monospace;
|
| 9389 | + |
| 9390 | + .devtools-section:not(:last-child) { |
| 9391 | + border-bottom: 1px solid #333; |
| 9392 | + } |
| 9393 | + |
| 9394 | + h3 { |
| 9395 | + margin: 0; |
| 9396 | + } |
9389 | 9397 | }
|
9390 | 9398 |
|
9391 | 9399 | #model-dev-tools-toggle-button {
|
|
9403 | 9411 |
|
9404 | 9412 | #model-devtools-time-travel-dialog {
|
9405 | 9413 | position: fixed;
|
9406 |
| - top: 50%; |
9407 |
| - left: 50%; |
9408 |
| - transform: translate(-50%, -50%); |
| 9414 | + bottom: 0; |
| 9415 | + right: 300px; |
9409 | 9416 | background: #2a2a2a;
|
9410 |
| - padding: 10px; |
9411 | 9417 | border: 1px solid #444;
|
9412 | 9418 | border-radius: 4px;
|
9413 |
| - max-height: 80vh; |
9414 |
| - overflow-y: auto; |
| 9419 | + height: 400px; |
| 9420 | + width: 300px; |
9415 | 9421 | z-index: 10000;
|
9416 | 9422 | color: #fff;
|
9417 | 9423 | font-family: monospace;
|
9418 | 9424 |
|
| 9425 | + .time-travel-items { |
| 9426 | + padding: 8px; height: calc(100% - 35px); |
| 9427 | + overflow: auto; |
| 9428 | + position: relative; |
| 9429 | + } |
| 9430 | + |
9419 | 9431 | .time-travel-item {
|
9420 | 9432 | padding: 8px;
|
9421 |
| - margin: 4px 0; |
| 9433 | + margin: 4px; |
9422 | 9434 | border: 1px solid #444;
|
9423 | 9435 | cursor: pointer;
|
9424 | 9436 | hover: background-color: #333;
|
| 9437 | + |
| 9438 | + button { |
| 9439 | + margin-top: 8px; |
| 9440 | + background: dodgerblue; |
| 9441 | + } |
9425 | 9442 | }
|
9426 | 9443 | }
|
9427 | 9444 |
|
|
9451 | 9468 | }
|
9452 | 9469 | }
|
9453 | 9470 | }
|
| 9471 | + |
| 9472 | + .dev-tools-header { |
| 9473 | + padding: 8px; |
| 9474 | + border-bottom: 1px solid #333; |
| 9475 | + display: flex; |
| 9476 | + justify-content: space-between; |
| 9477 | + } |
9454 | 9478 | </style>
|
9455 | 9479 | `;
|
9456 | 9480 | var ModelDevTools = class {
|
|
9478 | 9502 | const header2 = document.createElement("div");
|
9479 | 9503 | header2.innerHTML = `
|
9480 | 9504 | ${DevToolsWindowStyle}
|
9481 |
| - <div style="padding: 8px; border-bottom: 1px solid #333; display: flex; justify-content: space-between;"> |
| 9505 | + <div class="dev-tools-header"> |
9482 | 9506 | <span>Model DevTools</span>
|
9483 | 9507 | <div>
|
9484 | 9508 | <button id="devtools-time-travel" title="Time Travel">\u23F1</button>
|
|
9501 | 9525 | document.getElementById("devtools-time-travel").onclick = () => this.showTimeTravelDialog();
|
9502 | 9526 | }
|
9503 | 9527 | showTimeTravelDialog() {
|
9504 |
| - const dialog2 = document.createElement("div"); |
9505 |
| - dialog2.id = "model-devtools-time-travel-dialog"; |
| 9528 | + let dialog2 = document.getElementById("model-devtools-time-travel-dialog"); |
| 9529 | + if (!dialog2) { |
| 9530 | + dialog2 = document.createElement("div"); |
| 9531 | + dialog2.id = "model-devtools-time-travel-dialog"; |
| 9532 | + } |
9506 | 9533 | const statesList = this.history.map((snapshot, index) => `
|
9507 | 9534 | <div class="time-travel-item">
|
9508 | 9535 | <div>Time: ${new Date(snapshot.timestamp).toLocaleTimeString()}</div>
|
9509 | 9536 | <div>Type: ${snapshot.type}</div>
|
9510 | 9537 | <div>Property: ${snapshot.property || snapshot.event || snapshot.path || ""}</div>
|
9511 | 9538 | <div>Value: ${snapshot.oldValue + " -> " + snapshot.newValue}</div>
|
9512 |
| - <button style="margin-top: 8px; background: dodgerblue;" onclick="window.__MODEL_DEVTOOLS__.timeTravel(${index})"> |
| 9539 | + <button data-time-travel-index="${index}"> |
9513 | 9540 | Go to this state
|
9514 | 9541 | </button>
|
9515 | 9542 | </div>
|
9516 | 9543 | `).join("");
|
9517 | 9544 | dialog2.innerHTML = `
|
9518 |
| - <div style="display: flex; gap: 10px;"> |
9519 |
| - <h3 style="margin: 0">Time Travel</h3> |
| 9545 | + <div class="dev-tools-header"> |
| 9546 | + <span>Time Travel</span> |
9520 | 9547 | <button style="margin-left: auto" onclick="this.parentElement.parentElement.remove()">\xD7</button>
|
9521 | 9548 | </div>
|
9522 |
| - <div>${statesList || "Nothing to show!"}</div> |
| 9549 | + <div class="time-travel-items">${statesList || '<div style="height: 100%; display: flex; align-items: center; justify-content: center;">Nothing to show!</div>'}</div> |
9523 | 9550 | `;
|
9524 | 9551 | document.body.appendChild(dialog2);
|
| 9552 | + dialog2.querySelectorAll("[data-time-travel-index]").forEach((button2) => { |
| 9553 | + button2.onclick = () => { |
| 9554 | + const index = button2.getAttribute("data-time-travel-index"); |
| 9555 | + this.timeTravel(index); |
| 9556 | + }; |
| 9557 | + }); |
9525 | 9558 | if (!statesList) {
|
9526 | 9559 | setTimeout(() => {
|
9527 |
| - dialog2.remove(); |
9528 | 9560 | }, 2e3);
|
9529 | 9561 | }
|
9530 | 9562 | }
|
|
9658 | 9690 | <pre>${JSON.stringify(recentChanges, null, 2)}</pre>
|
9659 | 9691 | </div>
|
9660 | 9692 | `;
|
| 9693 | + const timeTravelDialog = document.getElementById("model-devtools-time-travel-dialog"); |
| 9694 | + if (timeTravelDialog) { |
| 9695 | + this.showTimeTravelDialog(); |
| 9696 | + } |
9661 | 9697 | }
|
9662 | 9698 | getComputedValues() {
|
9663 | 9699 | return Object.fromEntries(
|
|
9681 | 9717 | if (!this.options.timeTravel) return;
|
9682 | 9718 | if (index < 0 || index >= this.history.length) return;
|
9683 | 9719 | const snapshot = this.history[index];
|
9684 |
| - this.model.loadState(JSON.stringify(snapshot.state)); |
| 9720 | + this.model.loadStateFromSnapshot(snapshot.state); |
9685 | 9721 | this.currentIndex = index;
|
9686 | 9722 | }
|
9687 | 9723 | // Методи для аналізу продуктивності
|
|
10139 | 10175 | });
|
10140 | 10176 | }
|
10141 | 10177 | }
|
| 10178 | + loadStateFromSnapshot(snapshot) { |
| 10179 | + if (!snapshot) { |
| 10180 | + console.error("Snapshot is undefined or null"); |
| 10181 | + return; |
| 10182 | + } |
| 10183 | + try { |
| 10184 | + const computed = {}; |
| 10185 | + for (const key in snapshot) { |
| 10186 | + if (typeof snapshot[key] === "function") { |
| 10187 | + computed[key] = { |
| 10188 | + getter: snapshot[key], |
| 10189 | + value: null, |
| 10190 | + dependencies: [] |
| 10191 | + // Будет заполнено при первом вызове |
| 10192 | + }; |
| 10193 | + } else { |
| 10194 | + this.data[key] = snapshot[key]; |
| 10195 | + } |
| 10196 | + } |
| 10197 | + this.emit("restoreState", { |
| 10198 | + timestamp: Date.now(), |
| 10199 | + snapshot |
| 10200 | + }); |
| 10201 | + return true; |
| 10202 | + } catch (error) { |
| 10203 | + console.error("Error loading state from snapshot:", error); |
| 10204 | + this.emit("restoreStateError", { |
| 10205 | + error, |
| 10206 | + snapshot |
| 10207 | + }); |
| 10208 | + return false; |
| 10209 | + } |
| 10210 | + } |
10142 | 10211 | // Допоміжний метод для отримання всіх обчислюваних значень
|
10143 | 10212 | getComputedValues() {
|
10144 | 10213 | return Object.fromEntries(
|
|
10207 | 10276 | this.parseConditionals(rootElement);
|
10208 | 10277 | this.parse(rootElement);
|
10209 | 10278 | this.updateAllDOM();
|
| 10279 | + this.emit("init"); |
10210 | 10280 | return this;
|
10211 | 10281 | }
|
10212 | 10282 | // Ініціюємо DevTools
|
|
10215 | 10285 | }
|
10216 | 10286 | };
|
10217 | 10287 | var model_default = Model;
|
10218 |
| - var version6 = "0.5.0"; |
10219 |
| - var build_time6 = "01.03.2025, 23:19:15"; |
| 10288 | + var version6 = "0.7.0"; |
| 10289 | + var build_time6 = "02.03.2025, 00:39:42"; |
10220 | 10290 | model_default.info = () => {
|
10221 | 10291 | console.info(`%c Model %c v${version6} %c ${build_time6} `, "color: white; font-weight: bold; background: #0080fe", "color: white; background: darkgreen", "color: white; background: #0080fe;");
|
10222 | 10292 | };
|
|
39446 | 39516 |
|
39447 | 39517 | @olton/model/dist/model.js:
|
39448 | 39518 | (*!
|
39449 |
| - * Model v0.5.0 |
39450 |
| - * Build: 01.03.2025, 23:19:15 |
| 39519 | + * Model v0.7.0 |
| 39520 | + * Build: 02.03.2025, 00:39:42 |
39451 | 39521 | * Copyright 2012-2025 by Serhii Pimenov
|
39452 | 39522 | * Licensed under MIT
|
39453 | 39523 | *)
|
|
0 commit comments