taon-ui 19.0.30 → 19.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser/fesm2022/taon-ui.mjs +180 -2
- package/browser/fesm2022/taon-ui.mjs.map +1 -1
- package/browser/lib/ui/index.d.ts +2 -1
- package/browser/lib/ui/taon-iframe-sync/taon-iframe-sync.component.d.ts +31 -0
- package/browser/package.json +1 -1
- package/lib/build-info._auto-generated_.d.ts +1 -1
- package/lib/build-info._auto-generated_.js +1 -1
- package/lib/env/env.angular-node-app.d.ts +1 -0
- package/lib/env/env.angular-node-app.js +3 -2
- package/lib/env/env.angular-node-app.js.map +1 -1
- package/lib/env/env.docs-webapp.d.ts +1 -0
- package/lib/env/env.docs-webapp.js +3 -2
- package/lib/env/env.docs-webapp.js.map +1 -1
- package/lib/env/env.electron-app.d.ts +1 -0
- package/lib/env/env.electron-app.js +3 -2
- package/lib/env/env.electron-app.js.map +1 -1
- package/lib/env/env.mobile-app.d.ts +1 -0
- package/lib/env/env.mobile-app.js +3 -2
- package/lib/env/env.mobile-app.js.map +1 -1
- package/lib/env/env.npm-lib-and-cli-tool.d.ts +1 -0
- package/lib/env/env.npm-lib-and-cli-tool.js +3 -2
- package/lib/env/env.npm-lib-and-cli-tool.js.map +1 -1
- package/lib/env/env.vscode-plugin.d.ts +1 -0
- package/lib/env/env.vscode-plugin.js +3 -2
- package/lib/env/env.vscode-plugin.js.map +1 -1
- package/lib/index.js +2 -2
- package/lib/layouts/taon-bootstrap-navbar/index.js +2 -2
- package/lib/ui/directives/index.js +2 -2
- package/lib/ui/index.d.ts +2 -1
- package/lib/ui/index.js +2 -2
- package/lib/ui/taon-github-fork-me-corner/index.js +2 -2
- package/lib/ui/taon-github-fork-me-ribbon/index.js +2 -2
- package/lib/ui/taon-iframe-sync/index.d.ts +1 -0
- package/lib/ui/taon-iframe-sync/index.js +5 -0
- package/lib/ui/taon-iframe-sync/index.js.map +1 -0
- package/lib/ui/taon-iframe-sync/taon-iframe-sync.component.d.ts +27 -0
- package/lib/ui/taon-iframe-sync/taon-iframe-sync.d.ts +24 -0
- package/lib/ui/taon-iframe-sync/taon-iframe-sync.js +118 -0
- package/lib/ui/taon-iframe-sync/taon-iframe-sync.js.map +1 -0
- package/lib/ui/taon-notifications/taon-notifications.models.js +2 -2
- package/lib/ui/taon-progress-bar/index.js +2 -2
- package/lib/ui/taon-session-passcode/index.js +2 -2
- package/lib/ui/taon-table/index.js +2 -2
- package/package.json +1 -1
- package/websql/fesm2022/taon-ui.mjs +180 -2
- package/websql/fesm2022/taon-ui.mjs.map +1 -1
- package/websql/lib/ui/index.d.ts +2 -1
- package/websql/lib/ui/taon-iframe-sync/taon-iframe-sync.component.d.ts +31 -0
- package/websql/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function
|
|
3
|
+
exports.dummy1765313656635 = dummy1765313656635;
|
|
4
|
+
function dummy1765313656635() { }
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function
|
|
3
|
+
exports.dummy1765313656686 = dummy1765313656686;
|
|
4
|
+
function dummy1765313656686() { }
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function
|
|
3
|
+
exports.dummy1765313656743 = dummy1765313656743;
|
|
4
|
+
function dummy1765313656743() { }
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import { EventEmitter, HostListener, HostBinding, Output, Input, Directive, Pipe
|
|
|
3
3
|
import { _, json5, Helpers } from 'tnp-core/websql';
|
|
4
4
|
import { Log, Level } from 'ng2-logger/websql';
|
|
5
5
|
import * as i1 from '@angular/platform-browser';
|
|
6
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
6
7
|
import { A11yModule } from '@angular/cdk/a11y';
|
|
7
8
|
import * as i5$1 from '@angular/cdk/drag-drop';
|
|
8
9
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
|
@@ -52,7 +53,7 @@ import { MatToolbarModule } from '@angular/material/toolbar';
|
|
|
52
53
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
53
54
|
import { MatTreeModule } from '@angular/material/tree';
|
|
54
55
|
import * as i2$1 from '@angular/common';
|
|
55
|
-
import { CommonModule } from '@angular/common';
|
|
56
|
+
import { CommonModule, NgIf } from '@angular/common';
|
|
56
57
|
import { Resource } from 'ng2-rest/websql';
|
|
57
58
|
import * as i1$1 from '@ngneat/hot-toast';
|
|
58
59
|
import { __decorate, __metadata } from 'tslib';
|
|
@@ -72,6 +73,8 @@ import { StaticColumnsModule } from 'static-columns/websql';
|
|
|
72
73
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
73
74
|
import * as i4 from 'ngx-scrollbar';
|
|
74
75
|
import { NgScrollbarModule } from 'ngx-scrollbar';
|
|
76
|
+
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
|
77
|
+
import { distinctUntilChanged as distinctUntilChanged$1, takeUntil as takeUntil$1, filter } from 'rxjs/operators';
|
|
75
78
|
import * as i2$3 from '@ng-bootstrap/ng-bootstrap';
|
|
76
79
|
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
|
|
77
80
|
import { ModalModule } from 'ngx-bootstrap/modal';
|
|
@@ -1225,6 +1228,181 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1225
1228
|
args: ['window:resize', ['$event']]
|
|
1226
1229
|
}] } });
|
|
1227
1230
|
|
|
1231
|
+
// iframe-sync.component.ts
|
|
1232
|
+
// taon-iframe-sync.component.ts
|
|
1233
|
+
class TaonIframeSyncComponent {
|
|
1234
|
+
constructor() {
|
|
1235
|
+
this.destroy$ = new Subject();
|
|
1236
|
+
this.iframeWin = null;
|
|
1237
|
+
// This is the key: iframe stays hidden until first correct page is confirmed loaded
|
|
1238
|
+
this.isReady = false;
|
|
1239
|
+
this.hasInitialSync = false;
|
|
1240
|
+
this.queryParamKey = 'internalIframePath';
|
|
1241
|
+
this.initialPath = null;
|
|
1242
|
+
this.router = inject(Router);
|
|
1243
|
+
this.route = inject(ActivatedRoute);
|
|
1244
|
+
this.sanitizer = inject(DomSanitizer);
|
|
1245
|
+
// This is called when iframe confirms: "Yes, I loaded the correct page!"
|
|
1246
|
+
this.handleIframeMessage = (event) => {
|
|
1247
|
+
const expected = this.targetOrigin ?? this.getSafeOrigin(this.iframeSrc);
|
|
1248
|
+
if (event.origin !== expected)
|
|
1249
|
+
return;
|
|
1250
|
+
// NEW: iframe tells us when it's truly ready
|
|
1251
|
+
if (event.data?.type === 'IFRAME_READY') {
|
|
1252
|
+
this.isReady = true; // NOW show the iframe!
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
if (event.data?.type === 'IFRAME_PATH_UPDATE') {
|
|
1256
|
+
const path = event.data.path || '/';
|
|
1257
|
+
this.router.navigate([], {
|
|
1258
|
+
queryParams: { [this.queryParamKey]: path === '/' ? null : path },
|
|
1259
|
+
queryParamsHandling: 'merge',
|
|
1260
|
+
replaceUrl: true,
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
// ... same inputs as before
|
|
1266
|
+
#src;
|
|
1267
|
+
set iframeSrc(v) {
|
|
1268
|
+
this.#src = v.trim();
|
|
1269
|
+
this.safeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.#src);
|
|
1270
|
+
}
|
|
1271
|
+
get iframeSrc() {
|
|
1272
|
+
return this.#src;
|
|
1273
|
+
}
|
|
1274
|
+
ngAfterViewInit() {
|
|
1275
|
+
this.setupSync();
|
|
1276
|
+
window.addEventListener('message', this.handleIframeMessage);
|
|
1277
|
+
}
|
|
1278
|
+
setupSync() {
|
|
1279
|
+
this.route.queryParamMap
|
|
1280
|
+
.pipe(distinctUntilChanged$1((a, b) => a.get(this.queryParamKey) === b.get(this.queryParamKey)), takeUntil$1(this.destroy$))
|
|
1281
|
+
.subscribe(() => this.sendNavigateIfReady());
|
|
1282
|
+
this.router.events
|
|
1283
|
+
.pipe(filter((e) => e instanceof NavigationEnd), takeUntil$1(this.destroy$))
|
|
1284
|
+
.subscribe(() => this.sendNavigateIfReady());
|
|
1285
|
+
}
|
|
1286
|
+
onIframeLoad() {
|
|
1287
|
+
this.iframeWin = this.iframeRef?.nativeElement?.contentWindow;
|
|
1288
|
+
// Send the correct path — iframe will load it
|
|
1289
|
+
this.sendNavigateIfReady();
|
|
1290
|
+
// The real magic: wait for iframe to confirm it loaded the right page
|
|
1291
|
+
// (we'll enhance the iframe script to send a "READY" message)
|
|
1292
|
+
}
|
|
1293
|
+
sendNavigateIfReady() {
|
|
1294
|
+
if (!this.iframeWin ||
|
|
1295
|
+
!this.isValidUrl(this.iframeSrc) ||
|
|
1296
|
+
this.hasInitialSync)
|
|
1297
|
+
return;
|
|
1298
|
+
const path = this.route.snapshot.queryParamMap.get(this.queryParamKey) ??
|
|
1299
|
+
this.initialPath ??
|
|
1300
|
+
'/';
|
|
1301
|
+
const origin = this.targetOrigin ?? this.getSafeOrigin(this.iframeSrc);
|
|
1302
|
+
this.iframeWin.postMessage({ type: 'NAVIGATE', path }, origin);
|
|
1303
|
+
this.hasInitialSync = true;
|
|
1304
|
+
}
|
|
1305
|
+
// ────── Safe URL helpers ──────
|
|
1306
|
+
isValidUrl(string) {
|
|
1307
|
+
if (!string)
|
|
1308
|
+
return false;
|
|
1309
|
+
try {
|
|
1310
|
+
new URL(string, window.location.origin);
|
|
1311
|
+
return true;
|
|
1312
|
+
}
|
|
1313
|
+
catch {
|
|
1314
|
+
return false;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
getSafeOrigin(src) {
|
|
1318
|
+
if (!src)
|
|
1319
|
+
return window.location.origin;
|
|
1320
|
+
try {
|
|
1321
|
+
// Full URL
|
|
1322
|
+
if (src.startsWith('http')) {
|
|
1323
|
+
return new URL(src).origin;
|
|
1324
|
+
}
|
|
1325
|
+
// Relative path
|
|
1326
|
+
if (src.startsWith('/')) {
|
|
1327
|
+
return window.location.origin;
|
|
1328
|
+
}
|
|
1329
|
+
// Protocol-relative
|
|
1330
|
+
if (src.startsWith('//')) {
|
|
1331
|
+
return new URL(src, window.location.origin).origin;
|
|
1332
|
+
}
|
|
1333
|
+
// Just return current origin for anything else
|
|
1334
|
+
return window.location.origin;
|
|
1335
|
+
}
|
|
1336
|
+
catch {
|
|
1337
|
+
return window.location.origin;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
// ... rest of helpers (isValidUrl, getSafeOrigin) same as before
|
|
1341
|
+
ngOnDestroy() {
|
|
1342
|
+
this.destroy$.next();
|
|
1343
|
+
this.destroy$.complete();
|
|
1344
|
+
window.removeEventListener('message', this.handleIframeMessage);
|
|
1345
|
+
}
|
|
1346
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TaonIframeSyncComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1347
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: TaonIframeSyncComponent, isStandalone: true, selector: "taon-iframe-sync", inputs: { iframeSrc: "iframeSrc", queryParamKey: "queryParamKey", initialPath: "initialPath", targetOrigin: "targetOrigin" }, viewQueries: [{ propertyName: "iframeRef", first: true, predicate: ["iframe"], descendants: true }], ngImport: i0, template: `
|
|
1348
|
+
<!-- Hidden by default, shown only when ready -->
|
|
1349
|
+
<iframe
|
|
1350
|
+
#iframe
|
|
1351
|
+
[src]="safeSrc"
|
|
1352
|
+
[style.display]="isReady ? 'block' : 'none'"
|
|
1353
|
+
[style.visibility]="isReady ? 'visible' : 'hidden'"
|
|
1354
|
+
[style.opacity]="isReady ? '1' : '0'"
|
|
1355
|
+
frameborder="0"
|
|
1356
|
+
style="width:100%; height:100%; border:none; transition: opacity 0.2s ease;"
|
|
1357
|
+
(load)="onIframeLoad()"
|
|
1358
|
+
allow="clipboard-write"></iframe>
|
|
1359
|
+
|
|
1360
|
+
<!-- Optional: nice loading placeholder -->
|
|
1361
|
+
<div
|
|
1362
|
+
*ngIf="!isReady"
|
|
1363
|
+
class="iframe-loading-placeholder">
|
|
1364
|
+
<div class="spinner"></div>
|
|
1365
|
+
<p>Loading documentation...</p>
|
|
1366
|
+
</div>
|
|
1367
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%;position:relative}.iframe-loading-placeholder{position:absolute;inset:0;background:var(--md-primary-fg-color--light);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;color:var(--text-color, #666);font-family:system-ui,sans-serif}.spinner{width:40px;height:40px;border:4px solid #f3f3f3;border-top:4px solid #3498db;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1368
|
+
}
|
|
1369
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TaonIframeSyncComponent, decorators: [{
|
|
1370
|
+
type: Component,
|
|
1371
|
+
args: [{ selector: 'taon-iframe-sync', template: `
|
|
1372
|
+
<!-- Hidden by default, shown only when ready -->
|
|
1373
|
+
<iframe
|
|
1374
|
+
#iframe
|
|
1375
|
+
[src]="safeSrc"
|
|
1376
|
+
[style.display]="isReady ? 'block' : 'none'"
|
|
1377
|
+
[style.visibility]="isReady ? 'visible' : 'hidden'"
|
|
1378
|
+
[style.opacity]="isReady ? '1' : '0'"
|
|
1379
|
+
frameborder="0"
|
|
1380
|
+
style="width:100%; height:100%; border:none; transition: opacity 0.2s ease;"
|
|
1381
|
+
(load)="onIframeLoad()"
|
|
1382
|
+
allow="clipboard-write"></iframe>
|
|
1383
|
+
|
|
1384
|
+
<!-- Optional: nice loading placeholder -->
|
|
1385
|
+
<div
|
|
1386
|
+
*ngIf="!isReady"
|
|
1387
|
+
class="iframe-loading-placeholder">
|
|
1388
|
+
<div class="spinner"></div>
|
|
1389
|
+
<p>Loading documentation...</p>
|
|
1390
|
+
</div>
|
|
1391
|
+
`, standalone: true, imports: [NgIf], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%;height:100%;position:relative}.iframe-loading-placeholder{position:absolute;inset:0;background:var(--md-primary-fg-color--light);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;color:var(--text-color, #666);font-family:system-ui,sans-serif}.spinner{width:40px;height:40px;border:4px solid #f3f3f3;border-top:4px solid #3498db;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
|
|
1392
|
+
}], propDecorators: { iframeRef: [{
|
|
1393
|
+
type: ViewChild,
|
|
1394
|
+
args: ['iframe']
|
|
1395
|
+
}], iframeSrc: [{
|
|
1396
|
+
type: Input,
|
|
1397
|
+
args: [{ required: true }]
|
|
1398
|
+
}], queryParamKey: [{
|
|
1399
|
+
type: Input
|
|
1400
|
+
}], initialPath: [{
|
|
1401
|
+
type: Input
|
|
1402
|
+
}], targetOrigin: [{
|
|
1403
|
+
type: Input
|
|
1404
|
+
}] } });
|
|
1405
|
+
|
|
1228
1406
|
//#region @browser
|
|
1229
1407
|
//#endregion
|
|
1230
1408
|
|
|
@@ -1256,5 +1434,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1256
1434
|
* Generated bundle index. Do not edit.
|
|
1257
1435
|
*/
|
|
1258
1436
|
|
|
1259
|
-
export { SafePipe, TaonAdminModeConfigurationComponent, TaonBootstrapNavbarComponent, TaonFullMaterialModule, TaonGithubForkMeCornerComponent, TaonGithubForkMeCornerModule, TaonGithubForkMeRibbonComponent, TaonGithubForkMeRibbonModule, TaonInjectHTMLDirective, TaonLongPress, TaonNotificationOptions, TaonNotificationsComponent, TaonNotificationsModule, TaonNotificationsService, TaonProgressBarComponent, TaonProgressBarModule, TaonSessionPasscodeComponent, TaonTableComponent, TaonTableModule };
|
|
1437
|
+
export { SafePipe, TaonAdminModeConfigurationComponent, TaonBootstrapNavbarComponent, TaonFullMaterialModule, TaonGithubForkMeCornerComponent, TaonGithubForkMeCornerModule, TaonGithubForkMeRibbonComponent, TaonGithubForkMeRibbonModule, TaonIframeSyncComponent, TaonInjectHTMLDirective, TaonLongPress, TaonNotificationOptions, TaonNotificationsComponent, TaonNotificationsModule, TaonNotificationsService, TaonProgressBarComponent, TaonProgressBarModule, TaonSessionPasscodeComponent, TaonTableComponent, TaonTableModule };
|
|
1260
1438
|
//# sourceMappingURL=taon-ui.mjs.map
|