Replace QRCodeView with UIQRCode helper
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
Notify HeyPuter / notify (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test-backend (24.x) (push) Has been cancelled
test / API tests (node env, api-test) (24.x) (push) Has been cancelled
test / puterjs (node env, vitest) (24.x) (push) Has been cancelled

This commit is contained in:
Nariman Jelveh
2026-04-24 17:57:45 -07:00
parent 1aa51b7371
commit 231bfbd8a9
4 changed files with 138 additions and 108 deletions
-100
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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(`
<div class="qr-code opt-qr-code">
</div>
`);
}
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',
},
});
});
}
});
}
});
+130
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
$('<style/>').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 = $(`<div id="${id}" class="qr-code"></div>`);
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;
+5 -5
View File
@@ -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();
},
}),
+3 -3
View File
@@ -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,
],
});