frayerjj-frontend 0.2.27 → 0.2.29

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": "frayerjj-frontend",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "My base frontend for various projects",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -16,6 +16,7 @@
16
16
  "dependencies": {
17
17
  "@ckeditor/ckeditor5-build-classic": "^44.3.0",
18
18
  "@popperjs/core": "^2.11.8",
19
- "bootstrap": "^5.3.3"
19
+ "bootstrap": "^5.3.3",
20
+ "cropperjs": "^2.0.0"
20
21
  }
21
22
  }
@@ -0,0 +1,97 @@
1
+ import Cropper from 'cropperjs';
2
+ import { modal } from './modal';
3
+
4
+ export const avatarCropper = {
5
+
6
+ export: (selection, redirect) => {
7
+ selection.$toCanvas().then(canvas => {
8
+ canvas.toBlob(blob => {
9
+ let formData = new FormData();
10
+ formData.append('file', blob, 'avatar.png');
11
+ // Send the blob to the server
12
+ fetch(window.location.href, {
13
+ method: 'POST',
14
+ body: formData,
15
+ headers: {
16
+ 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
17
+ }
18
+ }).then(response => {
19
+ if (response.ok) {
20
+ // Show success message
21
+ modal.alert('Avatar updated successfully.');
22
+ // Redirect to the specified URL
23
+ window.location.href = redirect;
24
+ } else
25
+ // Show error message
26
+ modal.alert('Error updating avatar. Please try again.');
27
+ });
28
+ });
29
+ });
30
+ },
31
+
32
+ loadImage: (file, cropperImg, selection, exportBtn) => {
33
+ // If valid image
34
+ if (file && file.type.match(/image.*/)) {
35
+ // Load image
36
+ let reader = new FileReader();
37
+ reader.onload = () => {
38
+ // Set image on Cropper
39
+ cropperImg.onload = () => {
40
+ // Reset selector
41
+ selection.$reset();
42
+ selection.$center();
43
+ // Show export button
44
+ exportBtn.style.display = 'block';
45
+ }
46
+ cropperImg.src = e.target.result;
47
+ };
48
+ reader.readAsDataURL(file);
49
+ } else
50
+ // Show error message
51
+ modal.alert('Invalid file type. Please select an image file.');
52
+ },
53
+
54
+ init:() => {
55
+ let img = document.getElementById('avatar-cropper');
56
+ if (img) {
57
+
58
+ // Set the image to a transparent 1x1 pixel
59
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
60
+
61
+ // Initialize the cropper
62
+ new Cropper(img);
63
+ let canvas = document.querySelector('cropper-canvas');
64
+ canvas.classList.add('container-fixed');
65
+ window.dispatchEvent(new Event('resize'));
66
+ let selection = document.querySelector('cropper-selection');
67
+ selection.style.overflow = 'hidden';
68
+ selection.style.borderRadius = '50%';
69
+ selection.aspectRatio = 1;
70
+ let cropperImg = document.querySelector('cropper-image');
71
+
72
+ // Set export button
73
+ let exportBtn = document.querySelector(cropperImg.getAttribute('data-export-btn'));
74
+ let redirectUrl = img.getAttribute('data-redirect');
75
+ exportBtn.style.display = 'none';
76
+ exportBtn.addEventListener('click', () => {
77
+ avatarCropper.export(selection, redirectUrl);
78
+ });
79
+
80
+ // Create a file input element
81
+ let fileInput = document.createElement('input');
82
+ fileInput.setAttribute('type', 'file');
83
+ fileInput.setAttribute('accept', 'image/*');
84
+ fileInput.style.display = 'none';
85
+ img.insertAdjacentElement('afterend', fileInput);
86
+ fileInput.addEventListener('change', ev => {
87
+ avatarCropper.loadImage(ev.target.files[0], cropperImg, selection, exportBtn);
88
+ });
89
+
90
+ // Set upload button
91
+ let uploadBtn = document.querySelector(img.getAttribute('data-upload-btn'));
92
+ uploadBtn.addEventListener('click', () => {
93
+ fileInput.click();
94
+ });
95
+ }
96
+ }
97
+ };
package/src/init.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as bootstrap from 'bootstrap';
2
+ import { avatarCropper } from './avatar-cropper';
2
3
  import { createPopper } from '@popperjs/core';
3
4
  import { message } from './message';
4
5
  import { modal } from './modal';
5
6
  import { validate } from './validate';
6
7
  import { loading } from './loading';
7
- import { ajax } from './ajax';
8
8
  import { session } from './session';
9
9
  import { ckeupload } from './ckeupload';
10
10
  import { ClassicEditor } from '@ckeditor/ckeditor5-build-classic';
@@ -15,7 +15,6 @@ export const init = () => {
15
15
  window.createPopper = createPopper;
16
16
  window.message = message;
17
17
  window.modal = modal;
18
- window.ajax = ajax;
19
18
  window.session = session;
20
19
  window.validate = validate;
21
20
  window.loading = loading;
@@ -28,7 +27,27 @@ export const init = () => {
28
27
  validate.init();
29
28
  modal.ajax.init();
30
29
  ckeupload.init();
31
-
30
+ avatarCropper.init();
31
+
32
+ //Dynamic height for container-fixed
33
+ let container = document.querySelectorAll('.container-fixed');
34
+ if (container.length) {
35
+ let setHeigth = () => {
36
+ let sub = document.querySelectorAll('.navbar,header,footer')
37
+ if (container) {
38
+ let height = window.innerHeight;
39
+ sub.forEach((el) => {
40
+ height -= el.offsetHeight;
41
+ });
42
+ container.forEach((el) => {
43
+ el.style.height = height + 'px';
44
+ });
45
+ }
46
+ }
47
+ setHeigth();
48
+ window.addEventListener('resize', setHeigth);
49
+ }
50
+
32
51
  // Updates the id in the form action inside a modal. Used for delete confirm and edit modals.
33
52
  document.querySelectorAll('.modal-uuid-update').forEach(el => {
34
53
  message.verbose('Enabling Modal UUID Update');
package/src/modal.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Modal } from 'bootstrap';
2
- import { ajax } from './ajax.js';
3
2
  import { message } from './message.js';
4
3
 
5
4
  export const modal = {
@@ -40,56 +39,46 @@ export const modal = {
40
39
  bsAjaxModal.show();
41
40
  loading.start(0, ajaxModalBody);
42
41
  message.verbose('Loading AJAX Modal');
43
- window.ajax({
44
- method: 'GET',
45
- uri: el.getAttribute('modal-load-uri'),
46
- json: false,
47
- success: html => {
48
- ajaxModalBody.insertAdjacentHTML('afterbegin', html);
49
- let images = ajaxModalBody.querySelectorAll('img')
50
- if (images.length) {
51
- let counter = images.length;
52
- images.forEach(image => {
53
- if (image.complete && --counter == 0) loading.stop();
54
- else image.addEventListener('load', () => {
55
- if (--counter == 0) loading.stop();
56
- });
42
+ fetch(el.getAttribute('modal-load-uri'), { method: 'GET' }).then(response => {
43
+ ajaxModalBody.insertAdjacentHTML('afterbegin', response);
44
+ let images = ajaxModalBody.querySelectorAll('img')
45
+ if (images.length) {
46
+ let counter = images.length;
47
+ images.forEach(image => {
48
+ if (image.complete && --counter == 0) loading.stop();
49
+ else image.addEventListener('load', () => {
50
+ if (--counter == 0) loading.stop();
57
51
  });
58
- } else loading.stop();
59
- message.verbose('AJAX Modal Loaded');
60
- if (!el.getAttribute('modal-info')) {
61
- message.verbose('Adding submit handler to AJAX Modal');
62
- let saveButton = ajaxModal.querySelector('.btn-save');
63
- saveButton.removeAttribute('data-bs-dismiss').addEventListener('click', () => {
64
- message.verbose('Submitting AJAX Modal');
65
- loading.start(0, ajaxModalBody);
66
- let form = ajaxModal.querySelector('form');
67
- ajax({
68
- method: 'POST',
69
- uri: form.getAttribute('action'),
70
- vars: serialize(form),
71
- success: () => {
72
- message.verbose('AJAX Modal Saved');
73
- loading.stop();
74
- bsAjaxModal.hide();
75
- ajaxModal.remove();
76
- },
77
- failure: () => {
78
- message.warn('AJAX Modal Save Failed');
79
- loading.stop();
80
- modal.alert(modal.ajax.error.save.msg, modal.ajax.error.save.title);
81
- }
82
- });
52
+ });
53
+ } else loading.stop();
54
+ message.verbose('AJAX Modal Loaded');
55
+ if (!el.getAttribute('modal-info')) {
56
+ message.verbose('Adding submit handler to AJAX Modal');
57
+ ajaxModal.querySelector('.btn-save').addEventListener('click', () => {
58
+ message.verbose('Submitting AJAX Modal');
59
+ loading.start(0, ajaxModalBody);
60
+ let form = ajaxModal.querySelector('form');
61
+ fetch(form.getAttribute('action'), {
62
+ method: 'POST',
63
+ body: new FormData(form)
64
+ }).then(response => {
65
+ message.verbose('AJAX Modal Saved');
66
+ loading.stop();
67
+ bsAjaxModal.hide();
68
+ ajaxModal.remove();
69
+ }).catch(() => {
70
+ message.warn('AJAX Modal Save Failed');
71
+ loading.stop();
72
+ modal.alert(modal.ajax.error.save.msg, modal.ajax.error.save.title);
83
73
  });
84
- }
85
- },
86
- failure: () => {
87
- message.warn('AJAX Modal Load Failed');
88
- loading.stop();
89
- bsAjaxModal.hide();
90
- ajaxModal.remove();
91
- modal.alert(modal.ajax.error.load.msg, modal.ajax.error.load.title);
74
+ });
92
75
  }
76
+ }).catch(() => {
77
+ message.warn('AJAX Modal Load Failed');
78
+ loading.stop();
79
+ bsAjaxModal.hide();
80
+ ajaxModal.remove();
81
+ modal.alert(modal.ajax.error.load.msg, modal.ajax.error.load.title);
93
82
  });
94
83
  });
95
84
  });
package/src/ajax.js DELETED
@@ -1,44 +0,0 @@
1
- import { message } from './message';
2
-
3
- export const ajax = (args) => {
4
- return new Promise((resolve, reject) => {
5
-
6
- let encodeVars = vars => {
7
- let s = '';
8
- for (var v in vars) s += v + '=' + vars[v] + "&";
9
- return s ? s.substring(0, s.length - 1) : s;
10
- }
11
-
12
- if (args.method == 'GET' && args.vars) args.uri += '?' + encodeVars(args.vars);
13
- message.verbose('Making Request: ' + args.method + ' ' + args.uri);
14
-
15
- let xhr = new XMLHttpRequest();
16
- xhr.open(args.method, args.uri, true);
17
-
18
- if (args.method == 'POST' && args.vars) xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
19
-
20
- // Timeout support
21
- if (args.timeout) {
22
- xhr.timeout = args.timeout;
23
- xhr.ontimeout = () => reject(new Error('Request timed out'));
24
- }
25
-
26
- xhr.onreadystatechange = () => {
27
- if (xhr.readyState === XMLHttpRequest.DONE) {
28
- const status = xhr.status;
29
- if (status === 0 || (status >= 200 && status < 400)) {
30
- message.verbose('AJAX Request Successful');
31
- const response = args.json !== false ? JSON.parse(xhr.responseText) : xhr.responseText;
32
- if (typeof args.success == 'function') args.success.call(xhr, response);
33
- resolve(response);
34
- } else {
35
- message.warn('AJAX Request Failed (HTTP ' + xhr.status + ': ' + xhr.statusText + ')');
36
- if (typeof args.failure == 'function') args.failure.call(xhr);
37
- reject(new Error('AJAX Request Failed: ' + xhr.statusText));
38
- }
39
- }
40
- };
41
-
42
- xhr.send(args.method == 'POST' && args.vars ? encodeVars(args.vars) : null);
43
- });
44
- };