perfectionist-plugins 2.4.0 → 2.4.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perfectionist-plugins",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Small plugins that fix the annoying parts of League of Legends champ select. Built for Pengu Loader.",
5
5
  "type": "module",
6
6
  "main": "perfectionist-utils.js",
@@ -1,6 +1,5 @@
1
1
  const READY_EVENT = "perfectionist:utils-ready";
2
2
  const STATE_KEY = "perfectionist-plugins:state";
3
- const CACHE_KEY = "perfectionist-plugins:cache";
4
3
  const NAV_ID = "perfectionist-plugins-nav";
5
4
  const PANEL_ID = "perfectionist-plugins-panel";
6
5
  const STYLE_ID = "perfectionist-plugins-style";
@@ -10,13 +9,11 @@ export const version = "2.4.0";
10
9
 
11
10
  const PKG = "perfectionist-plugins";
12
11
  const CDN = "https://cdn.jsdelivr.net/npm";
13
- const REGISTRY_URL = `https://registry.npmjs.org/${PKG}/latest`;
14
- const CORE_FILE = "perfectionist-utils.js";
15
12
 
16
13
  const BUNDLED_MODULES = [
17
14
  {
18
15
  id: "perfectionist-utils",
19
- file: CORE_FILE,
16
+ file: "perfectionist-utils.js",
20
17
  name: "Perfectionism Core",
21
18
  version,
22
19
  description: "Shared core for the Perfectionism plugins.",
@@ -127,10 +124,6 @@ const STYLE_CSS = `
127
124
  #${PANEL_ID} .perf-chip:hover { color: #f0e6d2; border-color: #c89b3c; }
128
125
  #${PANEL_ID} .perf-chip--on { color: #010a13; background: #c89b3c; border-color: #c89b3c; }
129
126
  #${PANEL_ID} .perf-chip--on:hover { background: #f0e6d2; }
130
- #${PANEL_ID} .perf-info { margin-top: 11px; padding-top: 8px; border-top: 1px solid rgba(120, 90, 40, 0.35); }
131
- #${PANEL_ID} .perf-info-line { font-size: 10px; line-height: 16px; letter-spacing: 0.2px; color: #a09b8c;
132
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
133
-
134
127
  #${PANEL_ID} .perf-tools { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; margin-bottom: 14px; }
135
128
  #${PANEL_ID} .perf-search { flex: 1 1 auto; min-width: 0; box-sizing: border-box;
136
129
  font-family: "LoL Body", Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 12px; letter-spacing: 0.3px;
@@ -145,18 +138,6 @@ const STYLE_CSS = `
145
138
  #${PANEL_ID} .perf-chip:disabled { opacity: 0.45; cursor: default; }
146
139
  #${PANEL_ID} .perf-chip:disabled:hover { color: #a09b8c; border-color: #785a28; background: #0a1428; }
147
140
  #${PANEL_ID} .perf-chip--on:disabled:hover { color: #010a13; border-color: #c89b3c; background: #c89b3c; }
148
-
149
- .perf-update { position: fixed; inset: 0; z-index: 100000; display: flex; align-items: center;
150
- justify-content: center; background: rgba(1, 10, 19, 0.72); }
151
- .perf-update-box { width: 430px; box-sizing: border-box; padding: 22px 26px;
152
- background: #010a13; border: 1px solid #785a28; box-shadow: 0 0 32px rgba(0, 0, 0, 0.8); }
153
- .perf-update-title { font-family: "LoL Display", "Times New Roman", Times, Baskerville, Georgia, serif;
154
- font-size: 15px; font-weight: 700; letter-spacing: 1.05px; text-transform: uppercase; color: #f0e6d2; }
155
- .perf-update-status { font-family: "LoL Body", Arial, sans-serif; font-size: 12px; letter-spacing: 0.3px;
156
- color: #a09b8c; margin-top: 12px; line-height: 1.5; }
157
- .perf-update-track { height: 6px; margin-top: 16px; background: #0a1428; border: 1px solid #785a28; }
158
- .perf-update-fill { height: 100%; width: 0; background: #c89b3c; transition: width 0.25s; }
159
- .perf-update-close { margin-top: 18px; }
160
141
  `;
161
142
 
162
143
  const registry = new Map();
@@ -170,8 +151,10 @@ let coords = null;
170
151
  const resolved = new Map();
171
152
  let availableModules = BUNDLED_MODULES;
172
153
  let pendingReload = false;
154
+ let modulesLoaded = false;
173
155
  let searchQuery = "";
174
156
  let runningVersion = version;
157
+ let coreStarted = false;
175
158
 
176
159
  let state = { installed: {}, enabled: {}, options: {}, masterLocked: false };
177
160
 
@@ -322,20 +305,6 @@ function isInstalled(mod) {
322
305
  return installed === undefined ? registry.has(mod.id) : Boolean(installed);
323
306
  }
324
307
 
325
- function newerVersion(a, b) {
326
- const pa = String(a ?? "0")
327
- .split(".")
328
- .map(Number);
329
- const pb = String(b ?? "0")
330
- .split(".")
331
- .map(Number);
332
- for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
333
- const diff = (pa[i] || 0) - (pb[i] || 0);
334
- if (diff !== 0) return diff > 0;
335
- }
336
- return false;
337
- }
338
-
339
308
  function moduleUrl(file) {
340
309
  return `${CDN}/${PKG}@${runningVersion}/${file}`;
341
310
  }
@@ -344,14 +313,6 @@ function importModule(url) {
344
313
  return coords?.importModule ? coords.importModule(url) : import(url);
345
314
  }
346
315
 
347
- // Lets a feature module (BetterClient → Pages Remake) pull its code only when enabled.
348
- // A local override keeps the dev harness on freshly edited files instead of the CDN copy.
349
- function loadPluginFile(file) {
350
- const local = typeof window !== "undefined" ? window.PerfectionistLocalBase : null;
351
- const url = local ? new URL(file, local).href : moduleUrl(file);
352
- return importModule(url);
353
- }
354
-
355
316
  async function installModule(mod) {
356
317
  state.installed[mod.id] = true;
357
318
  delete state.enabled[mod.id];
@@ -368,105 +329,14 @@ async function uninstallModule(mod) {
368
329
  refreshPanel();
369
330
  }
370
331
 
371
- const SAFE_PHASES = new Set(["None", "Lobby", "EndOfGame"]);
372
-
373
332
  function reloadClientNow() {
374
333
  if (typeof window.reloadClient === "function") window.reloadClient();
375
334
  else window.location.reload();
376
335
  }
377
336
 
378
- async function reloadWhenSafe() {
379
- for (;;) {
380
- let phase = null;
381
- try {
382
- phase = await apiGet("/lol-gameflow/v1/gameflow-phase");
383
- } catch {
384
- phase = null;
385
- }
386
- if (phase == null || SAFE_PHASES.has(phase)) break;
387
- await new Promise((resolve) => setTimeout(resolve, 5000));
388
- }
389
- reloadClientNow();
390
- }
391
-
392
- function apiGet(path) {
393
- return fetch(path, { headers: { Accept: "application/json" } }).then((response) => {
394
- if (!response.ok) throw new Error(`${path} responded ${response.status}`);
395
- return response.status === 204 ? null : response.json();
396
- });
397
- }
398
-
399
- function buildUpdateWindow() {
400
- const root = el("div", "perf-update");
401
- const box = el("div", "perf-update-box");
402
- box.append(el("div", "perf-update-title", "Installing Update"));
403
- const status = el("div", "perf-update-status", "Downloading...");
404
- const track = el("div", "perf-update-track");
405
- const fill = el("div", "perf-update-fill");
406
- track.append(fill);
407
- box.append(status, track);
408
- root.append(box);
409
- return {
410
- root,
411
- setStatus: (text) => {
412
- status.textContent = text;
413
- },
414
- setProgress: (fraction) => {
415
- fill.style.width = `${Math.round(Math.max(0, Math.min(1, fraction)) * 100)}%`;
416
- },
417
- fail: (text) => {
418
- status.textContent = text;
419
- const close = el("button", "perf-btn perf-update-close", "Close");
420
- close.addEventListener("click", () => root.remove());
421
- box.append(close);
422
- },
423
- };
424
- }
425
-
426
- async function runUpdate(target) {
427
- const win = buildUpdateWindow();
428
- (document.body ?? document.documentElement).append(win.root);
429
- const files = [{ name: "Perfectionism Core", file: CORE_FILE }, ...BUNDLED_MODULES.filter((m) => !m.core)];
430
- const sources = {};
431
- for (let i = 0; i < files.length; i++) {
432
- win.setStatus(`Downloading ${files[i].name}...`);
433
- win.setProgress(i / files.length);
434
- try {
435
- const response = await fetch(`${CDN}/${PKG}@${target}/${files[i].file}`);
436
- if (response.status === 404 && files[i].id) continue;
437
- if (!response.ok) throw new Error(`download failed (${response.status})`);
438
- const text = await response.text();
439
- if (!text || !/export/.test(text)) throw new Error("the downloaded file looks invalid");
440
- if (files[i].id) sources[files[i].id] = text;
441
- } catch (error) {
442
- logError(`could not update to ${target}.`, error);
443
- win.fail(`Could not update to ${target}. It will be retried on the next client start.`);
444
- return;
445
- }
446
- }
447
- try {
448
- localStorage.setItem(CACHE_KEY, JSON.stringify({ version: target, files: sources }));
449
- } catch {}
450
- win.setProgress(1);
451
- runningVersion = target;
452
- saveState();
453
- win.setStatus("Update installed. Restarting the client...");
454
- reloadWhenSafe();
455
- }
456
-
457
- async function checkForUpdates() {
458
- if (!/^\d+\.\d+\.\d+$/.test(runningVersion)) return;
459
- let target = null;
460
- try {
461
- const response = await fetch(REGISTRY_URL, { headers: { Accept: "application/json" }, cache: "no-store" });
462
- if (response.ok) target = (await response.json())?.version ?? null;
463
- } catch {
464
- return;
465
- }
466
- if (target && newerVersion(target, runningVersion)) runUpdate(target);
467
- }
468
-
469
337
  async function loadModules() {
338
+ if (modulesLoaded) return;
339
+ modulesLoaded = true;
470
340
  for (const mod of BUNDLED_MODULES) {
471
341
  if (mod.core || resolved.has(mod.id) || registry.has(mod.id) || !isInstalled(mod)) continue;
472
342
  try {
@@ -647,17 +517,6 @@ function buildOptionRow(mod, option, disabled, onChange) {
647
517
  return row;
648
518
  }
649
519
 
650
- function buildInfo(option) {
651
- const block = el("div", "perf-info");
652
- if (option.label) block.append(el("div", "perf-chips-label", option.label));
653
- let lines = [];
654
- try {
655
- lines = option.lines?.() ?? [];
656
- } catch {}
657
- for (const line of lines) block.append(el("div", "perf-info-line", String(line)));
658
- return block;
659
- }
660
-
661
520
  function buildChips(mod, option, locked) {
662
521
  const block = el("div", "perf-chip-block");
663
522
  block.title = option.description ?? "";
@@ -680,28 +539,6 @@ function buildChips(mod, option, locked) {
680
539
  return block;
681
540
  }
682
541
 
683
- function buildAction(option, locked) {
684
- const button = el("button", "perf-btn", option.label);
685
- button.type = "button";
686
- button.title = option.description ?? "";
687
- button.disabled = Boolean(locked);
688
- button.addEventListener("click", async () => {
689
- const original = button.textContent;
690
- button.disabled = true;
691
- try {
692
- await option.onClick?.();
693
- button.textContent = "Copied";
694
- } catch {
695
- button.textContent = "Copy failed";
696
- }
697
- setTimeout(() => {
698
- button.textContent = original;
699
- button.disabled = Boolean(locked);
700
- }, 1600);
701
- });
702
- return button;
703
- }
704
-
705
542
  function buildOptions(mod, locked) {
706
543
  const options = registry.get(mod.id)?.options ?? [];
707
544
  if (options.length === 0) return null;
@@ -711,14 +548,6 @@ function buildOptions(mod, locked) {
711
548
  wrap.append(buildChips(mod, option, locked));
712
549
  continue;
713
550
  }
714
- if (option.type === "info") {
715
- wrap.append(buildInfo(option));
716
- continue;
717
- }
718
- if (option.type === "action") {
719
- wrap.append(buildAction(option, locked));
720
- continue;
721
- }
722
551
  if (!option.children?.length) {
723
552
  wrap.append(buildOptionRow(mod, option, Boolean(locked)));
724
553
  continue;
@@ -1072,8 +901,6 @@ const utils = {
1072
901
  getAvailableModules,
1073
902
  installModule,
1074
903
  uninstallModule,
1075
- loadPluginFile,
1076
- checkForUpdates,
1077
904
  watch,
1078
905
  waitFor,
1079
906
  addStyle,
@@ -1083,7 +910,8 @@ const utils = {
1083
910
  };
1084
911
 
1085
912
  export async function init(context, coordsProvided) {
1086
- if (window.PerfectionistUtils) return;
913
+ if (coreStarted || window.PerfectionistUtils) return;
914
+ coreStarted = true;
1087
915
  coords = coordsProvided ?? null;
1088
916
  runningVersion = coords?.version || version;
1089
917
 
@@ -1097,7 +925,6 @@ export async function init(context, coordsProvided) {
1097
925
 
1098
926
  try {
1099
927
  await loadModules();
1100
- checkForUpdates();
1101
928
  } catch (error) {
1102
929
  logError("startup failed.", error);
1103
930
  }