diff --git a/assets/controllers/pages/barcode_scan_controller.js b/assets/controllers/pages/barcode_scan_controller.js new file mode 100644 index 00000000..daf0abd4 --- /dev/null +++ b/assets/controllers/pages/barcode_scan_controller.js @@ -0,0 +1,86 @@ +import {Controller} from "@hotwired/stimulus"; +import * as ZXing from "@zxing/library"; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + + static targets = [ "source" ] + + codeReader = null; + + connect() { + console.log('Init Scanner'); + this.codeReader = new ZXing.BrowserMultiFormatReader(); + this.initScanner(); + } + + codeScannedHandler(result, err) { + if (result) { + //@ts-ignore + document.getElementById('scan_dialog_input').value = result.text; + //Submit form + //@ts-ignore + document.getElementById('scan_dialog_form').submit(); + } + if (err && !(err instanceof ZXing.NotFoundException)) { + console.error(err); + //document.getElementById('result').textContent = err + } + } + + initScanner() { + let selectedDeviceId; + + this.codeReader.listVideoInputDevices() + .then((videoInputDevices) => { + if (videoInputDevices.length >= 1) { + const sourceSelect = document.getElementById('sourceSelect'); + + + videoInputDevices.forEach((element) => { + const sourceOption = document.createElement('option'); + sourceOption.text = element.label; + sourceOption.value = element.deviceId; + sourceSelect.appendChild(sourceOption); + }); + + //Try to retrieve last selected webcam... + let last_cam_id = localStorage.getItem('scanner_last_cam_id'); + if (!!last_cam_id) { + //selectedDeviceId = localStorage.getItem('scanner_last_cam_id'); + sourceSelect.value = last_cam_id; + } else { + selectedDeviceId = videoInputDevices[0].deviceId; + } + + sourceSelect.onchange = () => { + //@ts-ignore + selectedDeviceId = sourceSelect.value; + localStorage.setItem('scanner_last_cam_id', selectedDeviceId); + changeHandler(); + }; + + document.getElementById('sourceSelectPanel').classList.remove('d-none'); + document.getElementById('video').classList.remove('d-none'); + document.getElementById('scanner-warning').classList.add('d-none'); + } + + + let changeHandler = () => { + this.codeReader.reset(); + this.codeReader.decodeFromVideoDevice(selectedDeviceId, 'video', (result, err) => this.codeScannedHandler(result, err)); + console.log(`Started continous decode from camera with id ${selectedDeviceId}`) + }; + + //Register Change Src Button + //document.getElementById('changeSrcBtn').addEventListener('click', changeHandler); + + //Try to start logging automatically. + changeHandler(); + + }) + .catch((err) => { + console.error(err) + }) + } +} \ No newline at end of file diff --git a/assets/js/register_events.js b/assets/js/register_events.js index 8521622e..9039f682 100644 --- a/assets/js/register_events.js +++ b/assets/js/register_events.js @@ -14,12 +14,13 @@ const RegisterEventHelper = class { constructor() { this.registerToasts(); this.registerTooltips(); - this.registerFileInput(); this.registerJumpToTopBtn(); this.registerTriStateCheckboxes(); + this.registerFileInput(); this.registerSpecialCharInput(); + this.registerHoverPics(); } diff --git a/assets/ts_src/event_listeners.ts b/assets/ts_src/event_listeners.ts index b56980ea..c61ce444 100644 --- a/assets/ts_src/event_listeners.ts +++ b/assets/ts_src/event_listeners.ts @@ -31,101 +31,6 @@ import * as ZXing from "@zxing/library"; * ***********************************/ - -//Register greek input in search fields. -$(document).on("ajaxUI:start ajaxUI:reload", function() { - //@ts-ignore - $("input[type=text], textarea, input[type=search]").unbind("keydown").keydown(function (event : KeyboardEvent) { - let greek = event.altKey; - - let greek_char : string = ""; - if (greek){ - switch(event.key) { - case "w": //Omega - greek_char = '\u2126'; - break; - case "u": - case "m": //Micro - greek_char = "\u00B5"; - break; - case "p": //Phi - greek_char = "\u03C6"; - break; - case "a": //Alpha - greek_char = "\u03B1"; - break; - case "b": //Beta - greek_char = "\u03B2"; - break; - case "c": //Gamma - greek_char = "\u03B3"; - break; - case "d": //Delta - greek_char = "\u03B4"; - break; - case "l": //Pound - greek_char = "\u00A3"; - break; - case "y": //Yen - greek_char = "\u00A5"; - break; - case "o": //Yen - greek_char = "\u00A4"; - break; - case "1": //Sum symbol - greek_char = "\u2211"; - break; - case "2": //Integral - greek_char = "\u222B"; - break; - case "3": //Less-than or equal - greek_char = "\u2264"; - break; - case "4": //Greater than or equal - greek_char = "\u2265"; - break; - case "5": //PI - greek_char = "\u03c0"; - break; - case "q": //Copyright - greek_char = "\u00A9"; - break; - case "e": //Euro - greek_char = "\u20AC"; - break; - } - - if(greek_char=="") return; - - let $txt = $(this); - //@ts-ignore - let caretPos = $txt[0].selectionStart; - let textAreaTxt = $txt.val().toString(); - $txt.val(textAreaTxt.substring(0, caretPos) + greek_char + textAreaTxt.substring(caretPos) ); - - } - }); - //@ts-ignore - this.greek_once = true; -}); - -//Register bootstrap select picker -$(document).on("ajaxUI:reload ajaxUI:start", function () { - //@ts-ignore - $(".selectpicker").selectpicker({ - dropdownAlignRight: 'auto', - container: '#content', - }); -}); - -//Use bootstrap tooltips for the most tooltips -$(document).on("ajaxUI:start ajaxUI:reload ajaxUI:dt_loaded", function () { - $(".tooltip").remove(); - $('a[title], button[title], span[title], h6[title], h3[title], i.fas[title]') - //@ts-ignore - .tooltip("hide").tooltip({container: "body", placement: "auto", boundary: 'window'}); -}); - // Add bootstrap treeview on divs with data-tree-data attribute $(document).on("ajaxUI:start ajaxUI:reload", function() { $("[data-tree-data]").each(function(index, element) { @@ -263,60 +168,6 @@ $(document).on("ajaxUI:reload", function () { $(".file").fileinput(); }); -$(document).on("ajaxUI:start ajaxUI:reload", function () { - $('input.tagsinput').each(function() { - - //Use typeahead if an autocomplete url was specified. - if($(this).data('autocomplete')) { - - //@ts-ignore - var engine = new Bloodhound({ - //@ts-ignore - datumTokenizer: Bloodhound.tokenizers.obj.whitespace(''), - //@ts-ignore - queryTokenizer: Bloodhound.tokenizers.obj.whitespace(''), - remote: { - url: $(this).data('autocomplete'), - wildcard: 'QUERY' - } - }); - - //@ts-ignore - $(this).tagsinput({ - typeaheadjs: { - name: 'tags', - source: engine.ttAdapter() - } - }); - - - } else { //Init tagsinput without typeahead - //@ts-ignore - $(this).tagsinput(); - } - }) -}); - -/** - * Register the button, to jump to the top of the page. - */ -$(document).on("ajaxUI:start", function registerJumpToTop() { - $(window).scroll(function () { - if ($(this).scrollTop() > 50) { - $('#back-to-top').fadeIn(); - } else { - $('#back-to-top').fadeOut(); - } - }); - // scroll body to 0px on click - $('#back-to-top').click(function () { - $('#back-to-top').tooltip('hide'); - $('body,html').animate({ - scrollTop: 0 - }, 800); - return false; - }).tooltip(); -}); /** * This listener keeps track of which tab is currently selected (using hash and localstorage) and will try to open @@ -374,48 +225,6 @@ $(document).on("ajaxUI:reload ajaxUI:start ajaxUI:dt_loaded", function () { }); }); -/* - * Register the button which is used to - */ -$(document).on("ajaxUI:start", function() { - let $sidebar = $("#fixed-sidebar"); - let $container = $("#main"); - let $toggler = $('#sidebar-toggle-button'); - - function sidebarHide() { - $sidebar.hide(); - $container.removeClass('col-md-9 col-lg-10 offset-md-3 offset-lg-2'); - $container.addClass('col-12'); - $toggler.html(''); - $toggler.data('hidden', true); - localStorage.setItem('sidebarHidden', 'true'); - } - function sidebarShow() { - let $sidebar = $("#fixed-sidebar"); - $sidebar.show(); - let $container = $("#main"); - $container.removeClass('col-12'); - $container.addClass('col-md-9 col-lg-10 offset-md-3 offset-lg-2'); - $toggler.html(''); - $toggler.data('hidden', false); - localStorage.setItem('sidebarHidden', 'false'); - } - - //Make the state persistent over reloads - if(localStorage.getItem('sidebarHidden') === 'true') { - sidebarHide(); - } - - //Register handler - $toggler.click(function() { - if($(this).data('hidden')) { - sidebarShow(); - } else { - sidebarHide(); - } - }); - -}); //Register typeaheads $(document).on("ajaxUI:reload ajaxUI:start attachment:create", function () { @@ -459,51 +268,6 @@ $(document).on("ajaxUI:reload ajaxUI:start attachment:create", function () { }) }); -$(document).on("ajaxUI:start", function () { - function decodeHTML(html) { - var txt = document.createElement('textarea'); - txt.innerHTML = html; - return txt.value; - } - - function parseMarkdown() { - $('.markdown').each(function() { - let unescaped = marked(decodeHTML( $(this).data('markdown'))); - //@ts-ignore - let escaped = DOMPurify.sanitize(unescaped); - $(this).html(escaped); - //Remove markdown from DOM - $(this).removeAttr('data-markdown'); - - //Make all links external - $('a', this).addClass('link-external').attr('target', '_blank').attr('rel', 'noopener'); - //Bootstrapify objects - $('table', this).addClass('table table-hover table-striped table-bordered'); - }); - - //Latex rendering have to be done after markdown parsing - $('.latex').each(function(index, element) { - //@ts-ignore - window.renderMathInElement(element, { - delimiters: [ - {left: "$$", right: "$$", display: true}, - {left: "$", right: "$", display: false}, - {left: "\\(", right: "\\)", display: false}, - {left: "\\[", right: "\\]", display: true} - ] - }); - }); - } - - //Configure markdown - marked.setOptions({ - gfm: true, - }); - - parseMarkdown(); - $(document).on("ajaxUI:reload", parseMarkdown); - $(document).on("ajaxUI:dt_loaded", parseMarkdown); -}); $(document).on("ajaxUI:start ajaxUI:reload attachment:create", function() { let updater = function() { @@ -571,92 +335,6 @@ $(document).on("ajaxUI:reload", function() { }) }); -//Reuse codereader between multiple requests -const codeReader = new ZXing.BrowserMultiFormatReader(); - -//Init barcode scanner -$(document).on("ajaxUI:start ajaxUI:reload", function() { - - //Skip if we are not on scanner page... - if (!document.getElementById('scan_dialog_form')) { - - codeReader.reset(); - - return; - } - - - let selectedDeviceId; - - - //Save it for later, so we can reset it - console.log('ZXing code reader initialized'); - codeReader.listVideoInputDevices() - .then((videoInputDevices) => { - if (videoInputDevices.length >= 1) { - const sourceSelect = document.getElementById('sourceSelect'); - - - videoInputDevices.forEach((element) => { - const sourceOption = document.createElement('option'); - sourceOption.text = element.label; - sourceOption.value = element.deviceId; - sourceSelect.appendChild(sourceOption); - }); - - //Try to retrieve last selected webcam... - let last_cam_id = localStorage.getItem('scanner_last_cam_id'); - if (!!last_cam_id) { - //selectedDeviceId = localStorage.getItem('scanner_last_cam_id'); - $(sourceSelect).val(last_cam_id); - } else { - selectedDeviceId = videoInputDevices[0].deviceId; - } - - sourceSelect.onchange = () => { - //@ts-ignore - selectedDeviceId = sourceSelect.value; - localStorage.setItem('scanner_last_cam_id', selectedDeviceId); - changeHandler(); - }; - - document.getElementById('sourceSelectPanel').classList.remove('d-none'); - document.getElementById('video').classList.remove('d-none'); - document.getElementById('scanner-warning').classList.add('d-none'); - } - - - let changeHandler = () => { - codeReader.reset(); - codeReader.decodeFromVideoDevice(selectedDeviceId, 'video', (result, err) => { - if (result) { - //@ts-ignore - document.getElementById('scan_dialog_input').value = result.text; - //Submit form - //@ts-ignore - document.getElementById('scan_dialog_form').submit(); - } - if (err && !(err instanceof ZXing.NotFoundException)) { - console.error(err); - //document.getElementById('result').textContent = err - } - }); - console.log(`Started continous decode from camera with id ${selectedDeviceId}`) - }; - - //Register Change Src Button - //document.getElementById('changeSrcBtn').addEventListener('click', changeHandler); - - //Try to start logging automatically. - changeHandler(); - - }) - .catch((err) => { - console.error(err) - }) -}); - - //Need for proper body padding, with every navbar height $(window).resize(function () { let height : number = $('#navbar').height() + 10; diff --git a/templates/LabelSystem/Scanner/dialog.html.twig b/templates/LabelSystem/Scanner/dialog.html.twig index 9e5e0503..56bd6ab7 100644 --- a/templates/LabelSystem/Scanner/dialog.html.twig +++ b/templates/LabelSystem/Scanner/dialog.html.twig @@ -14,7 +14,7 @@