/** Datei: plugins/cards/assets/js/arunox/hooks/templates/login.js **/ /** * cards/arunox/hooks/templates/login.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'template.login->config.OLD', function( config ) { config.content ??= {}; config.content.message ??= []; if( ARUNOX.Tools?.NFC.exists() ) { config.content.message.push('scan access card'); } return config; }); ARUNOX.Hooks.register( 'template.login->afterRender.OLD', function() { ARUNOX.Hooks.once( 'wrapper.dynamic->afterRender.OLD', function() { const section = this.instance; const parent = this.instance.parent; if( ARUNOX.Tools?.NFC.exists() ) { const NFCConfig = Object.assignRecursive( {}, section.element.ARX.storage.config, { color : 'danger', header : { after : false, before : 'Permission', }, aside : { side : 'left', }, footer : { after : { content : [ ARUNOX.Theme.htmlTag.config( 'button', { id : 'NFC_grant_authorization', icon : 'bi-check-lg', label : 'Berechtigung erteilen', onClick : () => ARUNOX.Tools.NFC.read(), style : { width : '100%', maxWidth : '100%', }, }), ], }, }, }); NFCConfig.content = [ ARUNOX.Theme.htmlTag.config( 'div', { classes : 'error__wrapper', content : [ ARUNOX.Theme.htmlTag.config( 'div', { classes : 'error', content : [ ARUNOX.Theme.htmlTag.config( 'div', { classes : 'error__icon', innerHTML : ``, }), ARUNOX.Theme.htmlTag.config( 'div', { classes : 'error__text', content : [ ARUNOX.Theme.htmlTag.config( 'h1', { classes : 'error__caption', textNode : 'NFC Gerät', }), ARUNOX.Theme.htmlTag.config( 'div', { classes : 'error__message', textNode : 'Fehlende Berechtigung', }), ], }), ], }), ], }) ]; const NFCQuery = parent.render( 'layout/section', NFCConfig ); const NFCHide = () => { NFCQuery.element.remove(); parent.append( section ); }; const NFCShow = ( denied ) => { section.element.remove(); parent.append( NFCQuery ) if( denied ) NFCQuery.elements.footer.elements.after.remove(); }; ARUNOX.Tools.NFC.onDenied = () => NFCShow( true ); if( typeof ARUNOX.Tools.NFCReadLogin === 'function' ) { ARUNOX.Tools.NFC.onRead = ARUNOX.Tools.NFCReadLogin; } ARUNOX.Tools.NFC.onGranted = NFCHide; ARUNOX.Tools.NFC.onPrompt = () => NFCShow( false ); ARUNOX.Tools.NFC.init(); } if( ARUNOX.Tools?.Keyboard ) { const loginForm = section.element.querySelector('form'); const Keyboard = parent.render( 'layout/section', { name : 'keyboard', color : 'primary', style : { order : 2, flexBasis : '200%', }, header : { after : '#', }, aside : { side : 'right', }, footer : { before : 'Keyboard', } }); const KBCopen = section.element.ARX.elements.header.addRight( true ); const KBCclose = Keyboard.element.ARX.elements.footer.addRight( true ); const KBCnumber = Keyboard.element.ARX.elements.header.addAfter( true ); const KBCback = Keyboard.element.ARX.elements.header.addBefore( true ); const KBCclear = Keyboard.element.ARX.elements.header.addRight( true ); const KBBopen = KBCopen.replace( 'button', { htmlTag : 'a', icon : 'bi bi-keyboard', title : 'Keyboard', color : { color: 'default', target: 'button' }, }); const KBBclose = KBCclose.replace( 'button', { htmlTag : 'a', icon : 'bi bi-caret-down-fill', title : 'Schließen', }); const KBBclear = KBCclear.replace( 'button', { htmlTag : 'a', color : 'danger', icon : 'bi bi-trash', title : 'Zurücksetzen', }); const KBBback = KBCback.replace( 'button', { htmlTag : 'a', color : 'secondary', icon : 'bi bi-backspace', title : 'Löschen', }); const KBEnumber = KBCnumber.element.querySelector('.frame__title'); KBCopen.reset(); ARUNOX.Tools.Keyboard.init({ visible : false, type : 'base36', closeBtn : KBBclose, openBtn : KBBopen, backBtn : KBBback, clearBtn : KBBclear, number : KBEnumber.ARX, content : Keyboard.elements.content, onHide : () => { loginForm.style.display = ''; KBCopen.replace( KBBopen ); Keyboard.element.remove(); }, onShow : () => { loginForm.style.display = 'none'; KBCopen.reset(); parent.append( Keyboard ) }, onBackHide : () => { KBCback.reset(); }, onBackShow : () => { KBCback.replace( KBBback ); }, onClearHide : () => { KBCclear.reset(); }, onClearShow : () => { KBCclear.replace( KBBclear ); }, onRefresh : ( value ) => ARUNOX.Tools.NFCManuelLogin( value ), }); } }); }); /** Datei: plugins/cards/assets/js/arunox/hooks/templates/_general.js **/ /** * cards/arunox/hooks/templates/v.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'template->beforeRender.OLD', function() { if( ARUNOX.Tools?.NFC.exists() ) { ARUNOX.Tools.NFC.onRead = null; ARUNOX.Tools.NFC.onError = null; ARUNOX.Tools.NFC.onError = null; ARUNOX.Tools.NFC.onPrompt = null; ARUNOX.Tools.NFC.onDenied = null; ARUNOX.Tools.NFC.onGranted = null; ARUNOX.Tools.NFC.onWritten = null; ARUNOX.Tools.NFC.init(); } }, 0 ); ARUNOX.Hooks.register( 'wrapper->beforeRender.OLD', function() { if( this.instance.storage.config.title == 'PWAs' ) { // console.log( 'wrapper->beforeRender', this.instance.element, this.instance.storage.config ); } }, 0 ); /** Datei: plugins/cards/assets/js/arunox/nfc.js **/ window.ARUNOX ??= {}; ARUNOX.Tools ??= {}; ARUNOX.Tools.NFC = { ndef : null, abort : null, onRead : null, onAbort : null, onError : null, onPrompt : null, onDenied : null, onGranted : null, onWritten : null, log : function() { // console.log( 'NFC Reader', ...arguments ); }, stop : function() { this.log( 'Stop' ); this.abort.abort(); }, exists : function() { return typeof NDEFReader !== 'undefined'; }, write : async function( records, onSuccess, onAbort ) { this.ndef = new NDEFReader(); this.abort = new AbortController(); this.abort.signal.onabort = event => { this.log( 'OnAbortWrite', event ); this._call( onAbort || this.onAbort, event ); }; try { await this.ndef.write({ records: records }, { signal: this.abort.signal }) .then( () => { let data = []; for( let record of records ) { data.push({ serial : null, type : record.recordType || null, media : record.mediaType || null, data : record.data || null, lang : record.lang || null, encoding: record.encoding || null, }); } this.log( 'Start Write', data ); return this._call( onSuccess || this.onWritten );; }); } catch( error ) { this.log( 'onErrorWrite', error ); this._call( onError || this.onError, error ); } }, read : async function( onSuccess, onAbort, onError ) { this.ndef = new NDEFReader(); this.abort = new AbortController(); this.abort.signal.onabort = event => { this.log( 'OnAbortRead', event ); this._call( onAbort || this.onAbort, event ); }; this.log( 'Read' ); try { const decoder = new TextDecoder(); await this.ndef.scan({ signal: this.abort.signal }); this.log( 'Waiting' ); this.ndef.addEventListener( 'readingerror', event => { this.log( 'onReadingError', 'Argh! Cannot read data from the NFC tag. Try another one?', event ); this._call( onError || this.onError, event ); }); this.ndef.addEventListener( 'reading', ({ message, serialNumber }) => { this.log( 'Reading' ); let records = []; for( let [ index, record ] of Object.entries( message.records ) ) { if( record.data ) { let data = decoder.decode( record.data ); records.push({ serial : serialNumber, type : record.recordType, media : record.mediaType, data : data, lang : record.lang, encoding: record.encoding, }); } else { records.push({ serial : serialNumber, type : record.recordType, media : record.mediaType, lang : record.lang, encoding: record.encoding, }); } } return this._call( onSuccess || this.onRead, records, serialNumber );; }); } catch( error ) { this.log( 'onErrorRead', error ); this._call( onError || this.onError, error ); } }, init : function( onGranted, onPrompt, onDenied ) { navigator.permissions.query({ name: 'nfc' }).then( permissionStatus => { if( permissionStatus.state === 'prompt' ) this._call( onPrompt || this.onPrompt ); else if( permissionStatus.state === 'denied' ) this._call( onDenied || this.onDenied ); else if( permissionStatus.state === 'granted' ) { this._call( onGranted || this.onGranted ); if( this._init ) return; this._init = true; this.read(); } permissionStatus.onchange = _ => { if( permissionStatus.state == 'granted' ) this._call( onGranted || this.onGranted ); else if( permissionStatus.state === 'denied' ) this._call( onDenied || this.onDenied ); }; }); }, _init : false, _call : function( callback, ...args ) { if( typeof callback === 'function' ) { return callback.apply( this, args ); } return false; }, };