html2apk 0.4.0 → 0.7.0

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.
@@ -0,0 +1,805 @@
1
+ (function () {
2
+ if (typeof window === "undefined" || window.Html2ApkRuntimeConsole) {
3
+ return;
4
+ }
5
+
6
+ var MAX_ENTRIES = 300;
7
+ var MAX_DETAIL = 1800;
8
+ var entries = [];
9
+ var networkEntries = [];
10
+ var scanCount = 0;
11
+ var scanTimer = null;
12
+ var slowScanTimer = null;
13
+ var modal = null;
14
+ var panel = null;
15
+ var button = null;
16
+ var consoleList = null;
17
+ var networkList = null;
18
+ var badge = null;
19
+ var activeTab = "console";
20
+ var opened = false;
21
+ var dragMoved = false;
22
+ var originalConsole = {};
23
+
24
+ var functionNames = [
25
+ "notificar", "notify",
26
+ "agendarNotificacao", "scheduleNotification",
27
+ "agendarNotificacoes", "scheduleNotifications",
28
+ "agendarLoopNotificacoes", "scheduleNotificationLoop",
29
+ "cancelarNotificacao", "cancelNotification",
30
+ "lanterna", "flashlight",
31
+ "alternarLanterna", "toggleFlashlight",
32
+ "ouvirMic", "listenMic", "startMic",
33
+ "pararMic", "stopMic",
34
+ "solicitarPermissaoCamera", "requestCameraPermission",
35
+ "solicitarPermissaoMicrofone", "requestMicrophonePermission",
36
+ "solicitarPermissaoNotificacoes", "requestNotificationPermission",
37
+ "escolherArquivo", "pickFile",
38
+ "escolherImagem", "pickImage",
39
+ "abrirNoApp", "openInApp",
40
+ "abrirForaDoApp", "openOutsideApp",
41
+ "abrirUrl", "openUrl",
42
+ "vibrar", "vibrate",
43
+ "toast",
44
+ "statusPermissoes", "permissionStatus",
45
+ "infoDispositivo", "deviceInfo",
46
+ "infoDesempenho", "performanceInfo",
47
+ "appsAbertos", "openAppsMemory"
48
+ ];
49
+
50
+ function now() {
51
+ return new Date().toLocaleTimeString();
52
+ }
53
+
54
+ function stringify(value) {
55
+ if (value instanceof Error) {
56
+ return value.stack || value.message || String(value);
57
+ }
58
+ if (typeof value === "string") {
59
+ return value;
60
+ }
61
+ try {
62
+ return JSON.stringify(value);
63
+ } catch (error) {
64
+ return String(value);
65
+ }
66
+ }
67
+
68
+ function short(value, limit) {
69
+ var text = stringify(value);
70
+ var max = limit || 700;
71
+ return text.length > max ? text.slice(0, max) + "..." : text;
72
+ }
73
+
74
+ function scriptAssetUrl(fileName) {
75
+ var scripts = document.getElementsByTagName("script");
76
+ var index;
77
+ var src;
78
+
79
+ for (index = scripts.length - 1; index >= 0; index -= 1) {
80
+ src = scripts[index].getAttribute("src") || "";
81
+ if (src.indexOf("html2apk-runtime-console.js") !== -1) {
82
+ try {
83
+ return new URL(fileName, scripts[index].src).toString();
84
+ } catch (error) {
85
+ return fileName;
86
+ }
87
+ }
88
+ }
89
+
90
+ return fileName;
91
+ }
92
+
93
+ function keepEntry(list, entry) {
94
+ list.push(entry);
95
+ while (list.length > MAX_ENTRIES) {
96
+ list.shift();
97
+ }
98
+ }
99
+
100
+ function renderEntry(entry, target) {
101
+ var item;
102
+ var meta;
103
+ var body;
104
+
105
+ if (!target) {
106
+ return;
107
+ }
108
+
109
+ item = document.createElement("div");
110
+ item.className = "html2apk-console-entry " + entry.kind;
111
+
112
+ meta = document.createElement("div");
113
+ meta.className = "html2apk-console-meta";
114
+ meta.textContent = "[" + entry.time + "] " + entry.kind.toUpperCase();
115
+
116
+ body = document.createElement("pre");
117
+ body.textContent = entry.message;
118
+
119
+ item.appendChild(meta);
120
+ item.appendChild(body);
121
+ target.appendChild(item);
122
+
123
+ while (target.children.length > MAX_ENTRIES) {
124
+ target.removeChild(target.firstChild);
125
+ }
126
+
127
+ target.scrollTop = target.scrollHeight;
128
+ }
129
+
130
+ function renderNetworkEntry(entry) {
131
+ var status = entry.status || "ERR";
132
+ var method = entry.method || "GET";
133
+ var title = method + " " + entry.url + " -> " + status + " (" + entry.durationMs + "ms)";
134
+ var detail = {
135
+ type: entry.type,
136
+ ok: entry.ok,
137
+ status: entry.status,
138
+ statusText: entry.statusText,
139
+ durationMs: entry.durationMs,
140
+ requestBody: entry.requestBody,
141
+ responseBody: entry.responseBody,
142
+ error: entry.error
143
+ };
144
+
145
+ renderEntry({
146
+ kind: entry.ok ? "network" : "error",
147
+ time: entry.time,
148
+ message: title + "\n" + short(detail, MAX_DETAIL)
149
+ }, networkList);
150
+ }
151
+
152
+ function redrawLists() {
153
+ if (consoleList) {
154
+ consoleList.innerHTML = "";
155
+ entries.forEach(function (entry) {
156
+ renderEntry(entry, consoleList);
157
+ });
158
+ }
159
+ if (networkList) {
160
+ networkList.innerHTML = "";
161
+ networkEntries.forEach(renderNetworkEntry);
162
+ }
163
+ }
164
+
165
+ function updateBadge() {
166
+ var count;
167
+ if (!badge) {
168
+ return;
169
+ }
170
+ count = entries.filter(function (entry) {
171
+ return entry.kind === "error";
172
+ }).length + networkEntries.filter(function (entry) {
173
+ return !entry.ok;
174
+ }).length;
175
+ badge.textContent = count ? String(count) : "";
176
+ badge.style.display = count ? "inline-flex" : "none";
177
+ }
178
+
179
+ function add(kind, message, detail) {
180
+ var entry = {
181
+ kind: kind || "info",
182
+ time: now(),
183
+ message: detail ? message + "\n" + short(detail, MAX_DETAIL) : String(message || "")
184
+ };
185
+
186
+ keepEntry(entries, entry);
187
+ renderEntry(entry, consoleList);
188
+ updateBadge();
189
+ if (entry.kind === "error") {
190
+ openConsole("console");
191
+ }
192
+ }
193
+
194
+ function addNetwork(entry) {
195
+ var safeEntry = entry || {};
196
+ safeEntry.time = safeEntry.time || now();
197
+ safeEntry.durationMs = safeEntry.durationMs || 0;
198
+ safeEntry.ok = safeEntry.ok !== false && (!safeEntry.status || (safeEntry.status >= 200 && safeEntry.status < 400));
199
+ keepEntry(networkEntries, safeEntry);
200
+ renderNetworkEntry(safeEntry);
201
+ updateBadge();
202
+ if (!safeEntry.ok) {
203
+ openConsole("network");
204
+ }
205
+ }
206
+
207
+ function setActiveTab(tab) {
208
+ activeTab = tab === "network" ? "network" : "console";
209
+ if (!modal) {
210
+ return;
211
+ }
212
+ modal.querySelectorAll("[data-html2apk-console-tab]").forEach(function (item) {
213
+ item.classList.toggle("active", item.dataset.html2apkConsoleTab === activeTab);
214
+ });
215
+ if (consoleList) {
216
+ consoleList.classList.toggle("active", activeTab === "console");
217
+ }
218
+ if (networkList) {
219
+ networkList.classList.toggle("active", activeTab === "network");
220
+ }
221
+ }
222
+
223
+ function clearActiveTab() {
224
+ if (activeTab === "network") {
225
+ networkEntries = [];
226
+ if (networkList) {
227
+ networkList.innerHTML = "";
228
+ }
229
+ updateBadge();
230
+ return;
231
+ }
232
+
233
+ entries = [];
234
+ if (consoleList) {
235
+ consoleList.innerHTML = "";
236
+ }
237
+ updateBadge();
238
+ add("info", "Console limpo.");
239
+ }
240
+
241
+ function clamp(value, min, max) {
242
+ return Math.max(min, Math.min(max, value));
243
+ }
244
+
245
+ function makeButtonDraggable(target) {
246
+ var pointerId = null;
247
+ var startX = 0;
248
+ var startY = 0;
249
+ var startLeft = 0;
250
+ var startTop = 0;
251
+
252
+ target.addEventListener("pointerdown", function (event) {
253
+ var rect = target.getBoundingClientRect();
254
+ pointerId = event.pointerId;
255
+ startX = event.clientX;
256
+ startY = event.clientY;
257
+ startLeft = rect.left;
258
+ startTop = rect.top;
259
+ dragMoved = false;
260
+ target.setPointerCapture(pointerId);
261
+ });
262
+
263
+ target.addEventListener("pointermove", function (event) {
264
+ var nextLeft;
265
+ var nextTop;
266
+ if (pointerId !== event.pointerId) {
267
+ return;
268
+ }
269
+ if (Math.abs(event.clientX - startX) > 4 || Math.abs(event.clientY - startY) > 4) {
270
+ dragMoved = true;
271
+ }
272
+ nextLeft = clamp(startLeft + event.clientX - startX, 8, window.innerWidth - target.offsetWidth - 8);
273
+ nextTop = clamp(startTop + event.clientY - startY, 8, window.innerHeight - target.offsetHeight - 8);
274
+ target.style.left = nextLeft + "px";
275
+ target.style.top = nextTop + "px";
276
+ target.style.right = "auto";
277
+ target.style.bottom = "auto";
278
+ try {
279
+ localStorage.setItem("html2apk.consoleButton", JSON.stringify({ left: nextLeft, top: nextTop }));
280
+ } catch (error) {
281
+ }
282
+ });
283
+
284
+ target.addEventListener("pointerup", function (event) {
285
+ if (pointerId === event.pointerId) {
286
+ target.releasePointerCapture(pointerId);
287
+ pointerId = null;
288
+ }
289
+ });
290
+ }
291
+
292
+ function restoreButtonPosition(target) {
293
+ var saved;
294
+ try {
295
+ saved = JSON.parse(localStorage.getItem("html2apk.consoleButton") || "null");
296
+ } catch (error) {
297
+ saved = null;
298
+ }
299
+ if (!saved || typeof saved.left !== "number" || typeof saved.top !== "number") {
300
+ return;
301
+ }
302
+ target.style.left = clamp(saved.left, 8, window.innerWidth - 56) + "px";
303
+ target.style.top = clamp(saved.top, 8, window.innerHeight - 56) + "px";
304
+ target.style.right = "auto";
305
+ target.style.bottom = "auto";
306
+ }
307
+
308
+ function makePanelDraggable(header, target) {
309
+ var pointerId = null;
310
+ var startX = 0;
311
+ var startY = 0;
312
+ var startLeft = 0;
313
+ var startTop = 0;
314
+
315
+ header.addEventListener("pointerdown", function (event) {
316
+ var rect;
317
+ if (event.target.closest("button")) {
318
+ return;
319
+ }
320
+ rect = target.getBoundingClientRect();
321
+ pointerId = event.pointerId;
322
+ startX = event.clientX;
323
+ startY = event.clientY;
324
+ startLeft = rect.left;
325
+ startTop = rect.top;
326
+ header.setPointerCapture(pointerId);
327
+ });
328
+
329
+ header.addEventListener("pointermove", function (event) {
330
+ var nextLeft;
331
+ var nextTop;
332
+ if (pointerId !== event.pointerId) {
333
+ return;
334
+ }
335
+ nextLeft = clamp(startLeft + event.clientX - startX, 8, window.innerWidth - target.offsetWidth - 8);
336
+ nextTop = clamp(startTop + event.clientY - startY, 8, window.innerHeight - target.offsetHeight - 8);
337
+ target.style.position = "fixed";
338
+ target.style.left = nextLeft + "px";
339
+ target.style.top = nextTop + "px";
340
+ target.style.right = "auto";
341
+ target.style.bottom = "auto";
342
+ target.style.transform = "none";
343
+ });
344
+
345
+ header.addEventListener("pointerup", function (event) {
346
+ if (pointerId === event.pointerId) {
347
+ header.releasePointerCapture(pointerId);
348
+ pointerId = null;
349
+ }
350
+ });
351
+ }
352
+
353
+ function createUi() {
354
+ var style;
355
+ var icon;
356
+ var header;
357
+ var title;
358
+ var tabs;
359
+ var consoleTab;
360
+ var networkTab;
361
+ var actions;
362
+ var clearButton;
363
+ var closeButton;
364
+ var body;
365
+
366
+ if (modal || !document.body) {
367
+ return;
368
+ }
369
+
370
+ style = document.createElement("style");
371
+ style.textContent = [
372
+ ".html2apk-console-button{position:fixed;right:14px;bottom:14px;z-index:2147483640;width:54px;height:54px;border:0;border-radius:999px;background:#126fff;color:#fff;padding:0;box-shadow:0 10px 30px rgba(0,0,0,.3);touch-action:none}",
373
+ ".html2apk-console-button img{width:100%;height:100%;object-fit:cover;border-radius:999px;display:block}.html2apk-console-button.fallback:before{content:'Console';font:800 10px system-ui,Segoe UI,Arial}",
374
+ ".html2apk-console-badge{position:absolute;right:-3px;top:-3px;display:none;align-items:center;justify-content:center;min-width:20px;height:20px;border-radius:999px;background:#ff4d5d;color:#fff;font:800 11px system-ui,Segoe UI,Arial;border:2px solid #fff}",
375
+ ".html2apk-console-modal{position:fixed;inset:0;z-index:2147483641;display:none;background:rgba(8,13,22,.42);padding:16px}",
376
+ ".html2apk-console-modal.open{display:flex;align-items:flex-end;justify-content:center}",
377
+ ".html2apk-console-panel{width:min(980px,calc(100vw - 24px));max-height:min(74vh,700px);background:#10141b;color:#edf4ff;border:1px solid rgba(255,255,255,.14);border-radius:14px;box-shadow:0 28px 90px rgba(0,0,0,.42);overflow:hidden;font-family:system-ui,Segoe UI,Arial}",
378
+ ".html2apk-console-header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;padding:12px 14px;border-bottom:1px solid rgba(255,255,255,.12);background:#161d27;touch-action:none}",
379
+ ".html2apk-console-header strong{font-size:15px}.html2apk-console-tabs{display:flex;gap:8px}.html2apk-console-actions{display:flex;gap:8px}",
380
+ ".html2apk-console-header button{border:1px solid rgba(255,255,255,.18);background:#202b3a;color:#edf4ff;border-radius:8px;padding:7px 10px;font:700 12px system-ui,Segoe UI,Arial}",
381
+ ".html2apk-console-header button.active{background:#126fff;border-color:#126fff;color:#fff}",
382
+ ".html2apk-console-body{height:min(59vh,570px);background:#0d1118}.html2apk-console-list{display:none;height:100%;overflow:auto;padding:10px}.html2apk-console-list.active{display:block}",
383
+ ".html2apk-console-entry{border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:8px 10px;margin-bottom:8px;background:#141b25}",
384
+ ".html2apk-console-entry.error{border-color:rgba(255,110,123,.65)}.html2apk-console-entry.warn{border-color:rgba(231,173,76,.6)}.html2apk-console-entry.call,.html2apk-console-entry.network{border-color:rgba(98,160,255,.55)}.html2apk-console-entry.ok{border-color:rgba(67,201,133,.55)}",
385
+ ".html2apk-console-meta{color:#9baabd;font-size:11px;font-weight:800;margin-bottom:4px}.html2apk-console-entry pre{white-space:pre-wrap;word-break:break-word;margin:0;font:12px ui-monospace,SFMono-Regular,Consolas,monospace;line-height:1.45}"
386
+ ].join("");
387
+ document.head.appendChild(style);
388
+
389
+ button = document.createElement("button");
390
+ button.type = "button";
391
+ button.className = "html2apk-console-button";
392
+ button.setAttribute("aria-label", "Console");
393
+ icon = document.createElement("img");
394
+ icon.alt = "";
395
+ icon.src = scriptAssetUrl("html2apk-console.png");
396
+ icon.addEventListener("error", function () {
397
+ button.classList.add("fallback");
398
+ icon.remove();
399
+ });
400
+ badge = document.createElement("span");
401
+ badge.className = "html2apk-console-badge";
402
+ button.appendChild(icon);
403
+ button.appendChild(badge);
404
+ button.addEventListener("click", function () {
405
+ if (dragMoved) {
406
+ setTimeout(function () {
407
+ dragMoved = false;
408
+ }, 0);
409
+ return;
410
+ }
411
+ openConsole();
412
+ });
413
+ makeButtonDraggable(button);
414
+ restoreButtonPosition(button);
415
+
416
+ modal = document.createElement("section");
417
+ modal.className = "html2apk-console-modal";
418
+ modal.setAttribute("aria-label", "Console");
419
+
420
+ panel = document.createElement("div");
421
+ panel.className = "html2apk-console-panel";
422
+
423
+ header = document.createElement("div");
424
+ header.className = "html2apk-console-header";
425
+ title = document.createElement("strong");
426
+ title.textContent = "Console";
427
+
428
+ tabs = document.createElement("div");
429
+ tabs.className = "html2apk-console-tabs";
430
+ consoleTab = document.createElement("button");
431
+ consoleTab.type = "button";
432
+ consoleTab.textContent = "Console";
433
+ consoleTab.dataset.html2apkConsoleTab = "console";
434
+ consoleTab.addEventListener("click", function () {
435
+ setActiveTab("console");
436
+ });
437
+ networkTab = document.createElement("button");
438
+ networkTab.type = "button";
439
+ networkTab.textContent = "Rede";
440
+ networkTab.dataset.html2apkConsoleTab = "network";
441
+ networkTab.addEventListener("click", function () {
442
+ setActiveTab("network");
443
+ });
444
+ tabs.appendChild(consoleTab);
445
+ tabs.appendChild(networkTab);
446
+
447
+ actions = document.createElement("div");
448
+ actions.className = "html2apk-console-actions";
449
+ clearButton = document.createElement("button");
450
+ clearButton.type = "button";
451
+ clearButton.textContent = "Limpar";
452
+ clearButton.addEventListener("click", clearActiveTab);
453
+ closeButton = document.createElement("button");
454
+ closeButton.type = "button";
455
+ closeButton.textContent = "Fechar";
456
+ closeButton.addEventListener("click", closeConsole);
457
+ actions.appendChild(clearButton);
458
+ actions.appendChild(closeButton);
459
+
460
+ body = document.createElement("div");
461
+ body.className = "html2apk-console-body";
462
+ consoleList = document.createElement("div");
463
+ consoleList.className = "html2apk-console-list";
464
+ networkList = document.createElement("div");
465
+ networkList.className = "html2apk-console-list";
466
+ body.appendChild(consoleList);
467
+ body.appendChild(networkList);
468
+
469
+ header.appendChild(title);
470
+ header.appendChild(tabs);
471
+ header.appendChild(actions);
472
+ panel.appendChild(header);
473
+ panel.appendChild(body);
474
+ modal.appendChild(panel);
475
+ modal.addEventListener("click", function (event) {
476
+ if (event.target === modal) {
477
+ closeConsole();
478
+ }
479
+ });
480
+ makePanelDraggable(header, panel);
481
+
482
+ document.body.appendChild(button);
483
+ document.body.appendChild(modal);
484
+ redrawLists();
485
+ setActiveTab(activeTab);
486
+ updateBadge();
487
+ }
488
+
489
+ function openConsole(tab) {
490
+ opened = true;
491
+ createUi();
492
+ if (tab) {
493
+ setActiveTab(tab);
494
+ }
495
+ if (modal) {
496
+ modal.classList.add("open");
497
+ }
498
+ }
499
+
500
+ function closeConsole() {
501
+ opened = false;
502
+ if (modal) {
503
+ modal.classList.remove("open");
504
+ }
505
+ }
506
+
507
+ function wrapFunction(name, fn) {
508
+ var wrapped;
509
+ if (typeof fn !== "function" || fn.__html2apkConsoleWrapped) {
510
+ return fn;
511
+ }
512
+
513
+ wrapped = function () {
514
+ var args = Array.prototype.slice.call(arguments);
515
+ var result;
516
+ add("call", name + "(" + args.map(short).join(", ") + ")");
517
+ try {
518
+ result = fn.apply(this, arguments);
519
+ } catch (error) {
520
+ add("error", name + " falhou", error);
521
+ throw error;
522
+ }
523
+
524
+ if (result && typeof result.then === "function") {
525
+ return result.then(function (value) {
526
+ add("ok", name + " resolveu", value);
527
+ return value;
528
+ }, function (error) {
529
+ add("error", name + " rejeitou", error);
530
+ throw error;
531
+ });
532
+ }
533
+
534
+ add("ok", name + " retornou", result);
535
+ return result;
536
+ };
537
+
538
+ wrapped.__html2apkConsoleWrapped = true;
539
+ wrapped.__html2apkConsoleOriginal = fn;
540
+ return wrapped;
541
+ }
542
+
543
+ function wrapApi(api, prefix) {
544
+ if (!api || typeof api !== "object") {
545
+ return;
546
+ }
547
+ Object.keys(api).forEach(function (name) {
548
+ if (name.indexOf("__") === 0 || typeof api[name] !== "function") {
549
+ return;
550
+ }
551
+ api[name] = wrapFunction(prefix ? prefix + "." + name : name, api[name]);
552
+ });
553
+ }
554
+
555
+ function wrapKnownFunctions() {
556
+ wrapApi(window.Html2ApkEarlyBridge, "early");
557
+ wrapApi(window.Html2ApkNative, "native");
558
+
559
+ functionNames.forEach(function (name) {
560
+ if (typeof window[name] === "function") {
561
+ window[name] = wrapFunction(name, window[name]);
562
+ }
563
+ });
564
+ }
565
+
566
+ function installConsoleHooks() {
567
+ ["log", "info", "debug", "warn", "error"].forEach(function (name) {
568
+ if (typeof console[name] !== "function" || console[name].__html2apkConsoleWrapped) {
569
+ return;
570
+ }
571
+ originalConsole[name] = console[name];
572
+ console[name] = function () {
573
+ var args = Array.prototype.slice.call(arguments);
574
+ add(name === "error" ? "error" : (name === "warn" ? "warn" : "info"), "console." + name, args);
575
+ return originalConsole[name].apply(console, arguments);
576
+ };
577
+ console[name].__html2apkConsoleWrapped = true;
578
+ });
579
+
580
+ window.addEventListener("error", function (event) {
581
+ var target = event.target || {};
582
+ if (target !== window && (target.src || target.href)) {
583
+ addNetwork({
584
+ type: "resource",
585
+ method: "GET",
586
+ url: target.src || target.href,
587
+ ok: false,
588
+ status: "ERR",
589
+ statusText: "Resource failed",
590
+ durationMs: 0,
591
+ error: target.outerHTML ? short(target.outerHTML, 500) : "Resource failed"
592
+ });
593
+ return;
594
+ }
595
+
596
+ add("error", event.message || "Erro JavaScript", {
597
+ source: event.filename,
598
+ line: event.lineno,
599
+ column: event.colno,
600
+ error: event.error ? stringify(event.error) : ""
601
+ });
602
+ }, true);
603
+
604
+ window.addEventListener("unhandledrejection", function (event) {
605
+ add("error", "Promise rejeitada sem tratamento", event.reason);
606
+ });
607
+ }
608
+
609
+ function responseHeaders(headers) {
610
+ var output = {};
611
+ try {
612
+ headers.forEach(function (value, key) {
613
+ output[key] = value;
614
+ });
615
+ } catch (error) {
616
+ }
617
+ return output;
618
+ }
619
+
620
+ function requestUrl(input) {
621
+ if (typeof input === "string") {
622
+ return input;
623
+ }
624
+ if (input && input.url) {
625
+ return input.url;
626
+ }
627
+ return String(input || "");
628
+ }
629
+
630
+ function requestMethod(input, init) {
631
+ return String((init && init.method) || (input && input.method) || "GET").toUpperCase();
632
+ }
633
+
634
+ function installFetchHook() {
635
+ var originalFetch = window.fetch;
636
+ if (typeof originalFetch !== "function" || originalFetch.__html2apkNetworkWrapped) {
637
+ return;
638
+ }
639
+
640
+ window.fetch = function (input, init) {
641
+ var startedAt = Date.now();
642
+ var method = requestMethod(input, init || {});
643
+ var url = requestUrl(input);
644
+ var requestBody = init && typeof init.body === "string" ? short(init.body, MAX_DETAIL) : undefined;
645
+
646
+ return originalFetch.apply(this, arguments).then(function (response) {
647
+ var entry = {
648
+ type: "fetch",
649
+ method: method,
650
+ url: url,
651
+ status: response.status,
652
+ statusText: response.statusText,
653
+ ok: response.ok,
654
+ durationMs: Date.now() - startedAt,
655
+ requestBody: requestBody,
656
+ headers: responseHeaders(response.headers)
657
+ };
658
+
659
+ try {
660
+ response.clone().text().then(function (body) {
661
+ entry.responseBody = short(body, MAX_DETAIL);
662
+ addNetwork(entry);
663
+ }, function () {
664
+ addNetwork(entry);
665
+ });
666
+ } catch (error) {
667
+ addNetwork(entry);
668
+ }
669
+
670
+ return response;
671
+ }, function (error) {
672
+ addNetwork({
673
+ type: "fetch",
674
+ method: method,
675
+ url: url,
676
+ ok: false,
677
+ status: "ERR",
678
+ statusText: "Fetch failed",
679
+ durationMs: Date.now() - startedAt,
680
+ requestBody: requestBody,
681
+ error: stringify(error)
682
+ });
683
+ throw error;
684
+ });
685
+ };
686
+
687
+ window.fetch.__html2apkNetworkWrapped = true;
688
+ }
689
+
690
+ function installXhrHook() {
691
+ var proto = window.XMLHttpRequest && window.XMLHttpRequest.prototype;
692
+ var originalOpen;
693
+ var originalSend;
694
+ if (!proto || proto.__html2apkNetworkWrapped) {
695
+ return;
696
+ }
697
+
698
+ originalOpen = proto.open;
699
+ originalSend = proto.send;
700
+
701
+ proto.open = function (method, url) {
702
+ this.__html2apkNetwork = {
703
+ type: "xhr",
704
+ method: String(method || "GET").toUpperCase(),
705
+ url: String(url || "")
706
+ };
707
+ return originalOpen.apply(this, arguments);
708
+ };
709
+
710
+ proto.send = function (body) {
711
+ var xhr = this;
712
+ var meta = xhr.__html2apkNetwork || { type: "xhr", method: "GET", url: "" };
713
+ var startedAt = Date.now();
714
+ var requestBody = typeof body === "string" ? short(body, MAX_DETAIL) : undefined;
715
+ var finished = false;
716
+
717
+ function finish(kind) {
718
+ var responseBody;
719
+ if (finished) {
720
+ return;
721
+ }
722
+ finished = true;
723
+ try {
724
+ responseBody = typeof xhr.responseText === "string" ? short(xhr.responseText, MAX_DETAIL) : undefined;
725
+ } catch (error) {
726
+ responseBody = undefined;
727
+ }
728
+ addNetwork({
729
+ type: "xhr",
730
+ method: meta.method,
731
+ url: meta.url,
732
+ ok: kind === "loadend" && xhr.status >= 200 && xhr.status < 400,
733
+ status: kind === "loadend" ? xhr.status : "ERR",
734
+ statusText: xhr.statusText || kind,
735
+ durationMs: Date.now() - startedAt,
736
+ requestBody: requestBody,
737
+ responseBody: responseBody
738
+ });
739
+ }
740
+
741
+ xhr.addEventListener("loadend", function () {
742
+ finish("loadend");
743
+ }, { once: true });
744
+ xhr.addEventListener("error", function () {
745
+ finish("error");
746
+ }, { once: true });
747
+ xhr.addEventListener("timeout", function () {
748
+ finish("timeout");
749
+ }, { once: true });
750
+ xhr.addEventListener("abort", function () {
751
+ finish("abort");
752
+ }, { once: true });
753
+
754
+ return originalSend.apply(this, arguments);
755
+ };
756
+
757
+ proto.__html2apkNetworkWrapped = true;
758
+ }
759
+
760
+ function installNetworkHooks() {
761
+ installFetchHook();
762
+ installXhrHook();
763
+ }
764
+
765
+ window.Html2ApkRuntimeConsole = {
766
+ open: openConsole,
767
+ close: closeConsole,
768
+ clear: clearActiveTab,
769
+ log: add,
770
+ network: addNetwork,
771
+ entries: function () {
772
+ return entries.slice();
773
+ },
774
+ networkEntries: function () {
775
+ return networkEntries.slice();
776
+ },
777
+ wrap: wrapKnownFunctions
778
+ };
779
+
780
+ installConsoleHooks();
781
+ installNetworkHooks();
782
+
783
+ if (document.readyState === "loading") {
784
+ document.addEventListener("DOMContentLoaded", createUi);
785
+ } else {
786
+ createUi();
787
+ }
788
+
789
+ wrapKnownFunctions();
790
+ document.addEventListener("deviceready", wrapKnownFunctions, false);
791
+ window.addEventListener("html2apk:event", wrapKnownFunctions);
792
+
793
+ scanTimer = setInterval(function () {
794
+ scanCount += 1;
795
+ wrapKnownFunctions();
796
+ if (scanCount >= 80) {
797
+ clearInterval(scanTimer);
798
+ if (!slowScanTimer) {
799
+ slowScanTimer = setInterval(wrapKnownFunctions, 2000);
800
+ }
801
+ }
802
+ }, 250);
803
+
804
+ add("info", "Console runtime do html2apk ativo.");
805
+ })();