diff --git a/src/gui/src/UI/Components/QRCode.js b/src/gui/src/UI/Components/QRCode.js
deleted file mode 100644
index 68eb31a30..000000000
--- a/src/gui/src/UI/Components/QRCode.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Copyright (C) 2024-present Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-const Component = use('util.Component');
-import UIComponentWindow from '../UIComponentWindow.js';
-
-export default def(class QRCodeView extends Component {
- static ID = 'ui.component.QRCodeView';
-
- static PROPERTIES = {
- value: {
- description: 'The text to encode in the QR code',
- },
- size: {
- value: 150,
- },
- enlarge_option: {
- value: true,
- },
- };
-
- static CSS = /*css*/`
- .qr-code {
- width: 100%;
- display: flex;
- justify-content: center;
- flex-direction: column;
- align-items: center;
- }
- .qr-code img {
- margin-bottom: 20px;
- }
- .has-enlarge-option {
- cursor: -moz-zoom-in;
- cursor: -webkit-zoom-in;
- cursor: zoom-in
- }
- `;
-
- create_template ({ template }) {
- $(template).html(`
-
-
- `);
- }
-
- on_ready ({ listen }) {
- listen('value', value => {
- // $(this.dom_).find('.qr-code').empty();
- new QRCode($(this.dom_).find('.qr-code').get(0), {
- text: value,
- // TODO: dynamic size
- width: this.get('size'),
- height: this.get('size'),
- currectLevel: QRCode.CorrectLevel.H,
- });
-
- if ( this.get('enlarge_option') ) {
- $(this.dom_).find('.qr-code img').addClass('has-enlarge-option');
- $(this.dom_).find('.qr-code img').on('click', async () => {
- UIComponentWindow({
- component: new QRCodeView({
- value: value,
- size: 400,
- enlarge_option: false,
- }),
- title: i18n('enlarged_qr_code'),
- backdrop: true,
- dominant: true,
- width: 550,
- height: 'auto',
- body_css: {
- width: 'initial',
- height: '100%',
- 'background-color': 'rgb(245 247 249)',
- 'backdrop-filter': 'blur(3px)',
- padding: '20px',
- },
- });
- });
- }
- });
- }
-});
diff --git a/src/gui/src/UI/UIQRCode.js b/src/gui/src/UI/UIQRCode.js
new file mode 100644
index 000000000..003dec070
--- /dev/null
+++ b/src/gui/src/UI/UIQRCode.js
@@ -0,0 +1,130 @@
+/**
+ * Copyright (C) 2024-present Puter Technologies Inc.
+ *
+ * This file is part of Puter.
+ *
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import UIWindow from './UIWindow.js';
+import Placeholder from '../util/Placeholder.js';
+
+const QR_CODE_CSS = `
+ .qr-code {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ }
+ .qr-code img {
+ margin-bottom: 20px;
+ }
+ .qr-code .has-enlarge-option {
+ cursor: -moz-zoom-in;
+ cursor: -webkit-zoom-in;
+ cursor: zoom-in;
+ }
+`;
+
+let css_injected = false;
+const inject_css_once = () => {
+ if ( css_injected ) return;
+ css_injected = true;
+ $('').text(QR_CODE_CSS).appendTo('head');
+};
+
+function UIQRCode (options) {
+ options = options ?? {};
+ const value = options.value;
+ const size = options.size ?? 150;
+ const enlarge_option = options.enlarge_option ?? true;
+
+ inject_css_once();
+
+ window.global_element_id++;
+ const id = `qr-code-${window.global_element_id}`;
+
+ const $el = $(``);
+ const el = $el.get(0);
+
+ if ( value ) {
+ new QRCode(el, {
+ text: value,
+ width: size,
+ height: size,
+ currectLevel: QRCode.CorrectLevel.H,
+ });
+
+ if ( enlarge_option ) {
+ const $img = $el.find('img');
+ $img.addClass('has-enlarge-option');
+ $img.on('click', () => UIQRCode.open_enlarged(value));
+ }
+ }
+
+ if ( options.appendTo ) {
+ if ( options.appendTo && options.appendTo.$ === 'placeholder' ) {
+ options.appendTo.replaceWith(el);
+ } else {
+ $(options.appendTo).append(el);
+ }
+ }
+
+ // Compatibility shim: Component-based containers (e.g. Flexer) call
+ // `.attach(parent)` on their children. Returning a plain DOM element with
+ // an `attach` method lets this work without making UIQRCode a Component.
+ el.attach = function (destination) {
+ if ( destination instanceof HTMLElement || destination instanceof ShadowRoot ) {
+ destination.appendChild(el);
+ return;
+ }
+ if ( destination && destination.$ === 'placeholder' ) {
+ destination.replaceWith(el);
+ return;
+ }
+ throw new Error(`Unknown destination type: ${destination}`);
+ };
+
+ return el;
+}
+
+UIQRCode.open_enlarged = async (value) => {
+ const placeholder = Placeholder();
+
+ await UIWindow({
+ title: i18n('enlarged_qr_code'),
+ backdrop: true,
+ dominant: true,
+ width: 550,
+ height: 'auto',
+ body_content: placeholder.html,
+ body_css: {
+ width: 'initial',
+ height: '100%',
+ 'background-color': 'rgb(245 247 249)',
+ 'backdrop-filter': 'blur(3px)',
+ padding: '20px',
+ },
+ });
+
+ UIQRCode({
+ value,
+ size: 400,
+ enlarge_option: false,
+ appendTo: placeholder,
+ });
+};
+
+export default UIQRCode;
diff --git a/src/gui/src/UI/UIWindow2FASetup.js b/src/gui/src/UI/UIWindow2FASetup.js
index 01bd29db0..4460f8d2e 100644
--- a/src/gui/src/UI/UIWindow2FASetup.js
+++ b/src/gui/src/UI/UIWindow2FASetup.js
@@ -21,7 +21,7 @@
Components: OneAtATimeView < ... >
Screen 1: QR code and entry box for testing
- Components: Flexer < QRCodeView, CodeEntryView, ActionsView >
+ Components: Flexer < UIQRCode, CodeEntryView, ActionsView >
Logic:
- when CodeEntryView has a value, check it against the QR code value...
... then go to the next screen
@@ -43,7 +43,7 @@ import Button from './Components/Button.js';
import CodeEntryView from './Components/CodeEntryView.js';
import ConfirmationsView from './Components/ConfirmationsView.js';
import Flexer from './Components/Flexer.js';
-import QRCodeView from './Components/QRCode.js';
+import UIQRCode from './UIQRCode.js';
import RecoveryCodesView from './Components/RecoveryCodesView.js';
import StepHeading from './Components/StepHeading.js';
import StepView from './Components/StepView.js';
@@ -120,7 +120,7 @@ const UIWindow2FASetup = async function UIWindow2FASetup () {
symbol: '2',
text: i18n('setup2fa_2_step_heading'),
}),
- new QRCodeView({
+ UIQRCode({
value: data.url,
}),
new StepHeading({
@@ -129,7 +129,7 @@ const UIWindow2FASetup = async function UIWindow2FASetup () {
}),
new CodeEntryView({
_ref: me => code_entry = me,
- async ['property.value'] (value, { component }) {
+ async 'property.value' (value, { component }) {
if ( ! await check_code_(value) ) {
component.set('error', 'Invalid code');
component.set('is_checking_code', false);
@@ -141,7 +141,7 @@ const UIWindow2FASetup = async function UIWindow2FASetup () {
},
}),
],
- ['event.focus'] () {
+ 'event.focus' () {
code_entry.focus();
},
}),
diff --git a/src/gui/src/UI/UIWindowQR.js b/src/gui/src/UI/UIWindowQR.js
index 73b24a87c..46f824bc3 100644
--- a/src/gui/src/UI/UIWindowQR.js
+++ b/src/gui/src/UI/UIWindowQR.js
@@ -19,7 +19,7 @@
import Placeholder from '../util/Placeholder.js';
import Flexer from './Components/Flexer.js';
-import QRCodeView from './Components/QRCode.js';
+import UIQRCode from './UIQRCode.js';
import UIWindow from './UIWindow.js';
async function UIWindowQR (options) {
@@ -71,14 +71,14 @@ async function UIWindowQR (options) {
},
});
- const component_qr = new QRCodeView({
+ const el_qr = UIQRCode({
value: options.text,
size: 250,
});
const component_flexer = new Flexer({
children: [
- component_qr,
+ el_qr,
],
});