Feat: Replace Google ReCAPTCHA with ALTCHA using API - non-tracking, GDPR compliant without cookies or fingerprinting.
This commit is contained in:
@@ -81,9 +81,15 @@ class Config:
|
|||||||
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
||||||
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
||||||
MAIL_CONTACT_PUBLIC = os.getenv('MAIL_CONTACT_PUBLIC')
|
MAIL_CONTACT_PUBLIC = os.getenv('MAIL_CONTACT_PUBLIC')
|
||||||
|
"""
|
||||||
# Recaptcha
|
# Recaptcha
|
||||||
RECAPTCHA_PUBLIC_KEY = os.getenv('RECAPTCHA_PUBLIC_KEY')
|
RECAPTCHA_PUBLIC_KEY = os.getenv('RECAPTCHA_PUBLIC_KEY')
|
||||||
RECAPTCHA_PRIVATE_KEY = os.getenv('RECAPTCHA_PRIVATE_KEY')
|
RECAPTCHA_PRIVATE_KEY = os.getenv('RECAPTCHA_PRIVATE_KEY')
|
||||||
|
"""
|
||||||
|
# ALTCHA
|
||||||
|
ALTCHA_API_KEY = os.getenv('ALTCHA_API_KEY')
|
||||||
|
ALTCHA_SECRET_KEY = os.getenv('ALTCHA_SECRET_KEY')
|
||||||
|
ALTCHA_REGION = 'eu'
|
||||||
|
|
||||||
class DevelopmentConfig(Config):
|
class DevelopmentConfig(Config):
|
||||||
is_development = True
|
is_development = True
|
||||||
|
|||||||
@@ -18,14 +18,17 @@ from models.model_view_contact import Model_View_Contact
|
|||||||
from models.model_view_home import Model_View_Home
|
from models.model_view_home import Model_View_Home
|
||||||
import lib.argument_validation as av
|
import lib.argument_validation as av
|
||||||
# external
|
# external
|
||||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app, flash
|
||||||
from flask_mail import Mail, Message
|
from flask_mail import Mail, Message
|
||||||
from extensions import db, oauth, mail
|
from extensions import db, oauth, mail
|
||||||
from urllib.parse import quote_plus, urlencode
|
from urllib.parse import quote_plus, urlencode
|
||||||
from authlib.integrations.flask_client import OAuth
|
from authlib.integrations.flask_client import OAuth
|
||||||
from authlib.integrations.base_client import OAuthError
|
from authlib.integrations.base_client import OAuthError
|
||||||
from urllib.parse import quote, urlparse, parse_qs
|
from urllib.parse import quote, urlparse, parse_qs
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
|
||||||
routes_core = Blueprint('routes_core', __name__)
|
routes_core = Blueprint('routes_core', __name__)
|
||||||
|
|
||||||
@@ -54,20 +57,82 @@ def contact_post():
|
|||||||
try:
|
try:
|
||||||
form = Form_Contact()
|
form = Form_Contact()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
# Handle form submission
|
altcha_payload = form.altcha.data
|
||||||
email = form.email.data
|
if not altcha_payload:
|
||||||
CC = form.CC.data # not in use
|
flash('Please complete the ALTCHA challenge', 'danger')
|
||||||
contact_name = form.contact_name.data
|
return "Invalid. ALTCHA challenge failed."
|
||||||
company_name = form.company_name.data
|
# Decode and verify the ALTCHA payload
|
||||||
message = form.message.data
|
try:
|
||||||
receive_marketing = form.receive_marketing.data
|
decoded_payload = json.loads(base64.b64decode(altcha_payload))
|
||||||
receive_marketing_text = "I would like to receive marketing emails." if receive_marketing else ""
|
|
||||||
# send email
|
# Verify the signature
|
||||||
mailItem = Message("PARTS Website Contact Us Message", recipients=[current_app.config['MAIL_CONTACT_PUBLIC']])
|
if verify_altcha_signature(decoded_payload):
|
||||||
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n{receive_marketing_text}\nKind regards,\n{contact_name}\n{company_name}\n{email}"
|
# Parse the verification data
|
||||||
mail.send(mailItem)
|
verification_data = urllib.parse.parse_qs(decoded_payload['verificationData'])
|
||||||
return "Submitted."
|
|
||||||
|
# Check if the verification was successful
|
||||||
|
if verification_data.get('verified', ['false'])[0] == 'true':
|
||||||
|
# If spam filter is enabled, check the classification
|
||||||
|
if 'classification' in verification_data:
|
||||||
|
classification = verification_data.get('classification', [''])[0]
|
||||||
|
score = float(verification_data.get('score', ['0'])[0])
|
||||||
|
|
||||||
|
# If the classification is BAD and score is high, reject the submission
|
||||||
|
if classification == 'BAD' and score > 5:
|
||||||
|
flash('Your submission was flagged as potential spam', 'error')
|
||||||
|
return render_template('contact.html', form=form)
|
||||||
|
|
||||||
|
# Process the form submission
|
||||||
|
email = form.email.data
|
||||||
|
CC = form.CC.data # not in use
|
||||||
|
contact_name = form.contact_name.data
|
||||||
|
company_name = form.company_name.data
|
||||||
|
message = form.message.data
|
||||||
|
receive_marketing = form.receive_marketing.data
|
||||||
|
receive_marketing_text = "I would like to receive marketing emails." if receive_marketing else ""
|
||||||
|
# send email
|
||||||
|
mailItem = Message("PARTS Website Contact Us Message", recipients=[current_app.config['MAIL_CONTACT_PUBLIC']])
|
||||||
|
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n{receive_marketing_text}\nKind regards,\n{contact_name}\n{company_name}\n{email}"
|
||||||
|
mail.send(mailItem)
|
||||||
|
flash('Thank you for your message. We will get back to you soon!', 'success')
|
||||||
|
return "Submitted."
|
||||||
|
else:
|
||||||
|
flash('CAPTCHA verification failed', 'error')
|
||||||
|
else:
|
||||||
|
flash('Invalid verification signature', 'error')
|
||||||
|
except Exception as e:
|
||||||
|
flash(f'Error verifying CAPTCHA: {str(e)}', 'error')
|
||||||
return "Invalid. Failed to submit."
|
return "Invalid. Failed to submit."
|
||||||
# html_body = render_template('pages/core/_contact.html', model = model)
|
# html_body = render_template('pages/core/_contact.html', model = model)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify(error=str(e)), 403
|
return jsonify(error=str(e)), 403
|
||||||
|
|
||||||
|
|
||||||
|
def verify_altcha_signature(payload):
|
||||||
|
"""Verify the ALTCHA signature"""
|
||||||
|
if 'algorithm' not in payload or 'signature' not in payload or 'verificationData' not in payload:
|
||||||
|
return False
|
||||||
|
|
||||||
|
algorithm = payload['algorithm']
|
||||||
|
signature = payload['signature']
|
||||||
|
verification_data = payload['verificationData']
|
||||||
|
|
||||||
|
# Calculate SHA hash of the verification data
|
||||||
|
if algorithm == 'SHA-256':
|
||||||
|
hash_func = hashlib.sha256
|
||||||
|
else:
|
||||||
|
# Fallback to SHA-256 if algorithm not specified
|
||||||
|
hash_func = hashlib.sha256
|
||||||
|
|
||||||
|
# Calculate the hash of verification_data
|
||||||
|
data_hash = hash_func(verification_data.encode('utf-8')).digest()
|
||||||
|
|
||||||
|
# Calculate the HMAC signature
|
||||||
|
calculated_signature = hmac.new(
|
||||||
|
current_app.config["ALTCHA_SECRET_KEY"].encode('utf-8'),
|
||||||
|
data_hash,
|
||||||
|
hash_func
|
||||||
|
).hexdigest()
|
||||||
|
|
||||||
|
# Compare the calculated signature with the provided signature
|
||||||
|
return hmac.compare_digest(calculated_signature, signature)
|
||||||
@@ -16,12 +16,63 @@ Defines Flask-WTF form for handling user input on Contact Us page.
|
|||||||
# from models.model_view_store import Model_View_Store # circular
|
# from models.model_view_store import Model_View_Store # circular
|
||||||
from forms.base import Form_Base
|
from forms.base import Form_Base
|
||||||
# external
|
# external
|
||||||
|
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
from wtforms import StringField, TextAreaField, SubmitField, HiddenField, BooleanField
|
||||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
from wtforms.validators import DataRequired, Email, ValidationError
|
||||||
from flask_wtf.recaptcha import RecaptchaField
|
from flask_wtf.recaptcha import RecaptchaField
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
"""
|
||||||
|
def validate_altcha(form, field):
|
||||||
|
if not field.data:
|
||||||
|
raise ValidationError('Please complete the ALTCHA challenge')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Decode the base64-encoded payload
|
||||||
|
payload_json = base64.b64decode(field.data).decode('utf-8')
|
||||||
|
payload = json.loads(payload_json)
|
||||||
|
|
||||||
|
# Verify ALTCHA response
|
||||||
|
if not payload.get('verified', False):
|
||||||
|
raise ValidationError('ALTCHA verification failed')
|
||||||
|
|
||||||
|
# Verify signature
|
||||||
|
verification_data = payload.get('verificationData', '')
|
||||||
|
received_signature = payload.get('signature', '')
|
||||||
|
algorithm = payload.get('algorithm', 'SHA-256')
|
||||||
|
|
||||||
|
# Calculate the hash of verification data
|
||||||
|
verification_hash = hashlib.sha256(verification_data.encode()).digest()
|
||||||
|
|
||||||
|
# Calculate HMAC signature
|
||||||
|
hmac_key = current_app.config['ALTCHA_SECRET_KEY'].encode()
|
||||||
|
calculated_signature = hmac.new(
|
||||||
|
hmac_key,
|
||||||
|
verification_hash,
|
||||||
|
getattr(hashlib, algorithm.lower().replace('-', ''))
|
||||||
|
).hexdigest()
|
||||||
|
|
||||||
|
if calculated_signature != received_signature:
|
||||||
|
raise ValidationError('Invalid ALTCHA signature')
|
||||||
|
|
||||||
|
# Optional: If using the spam filter, you could parse verification_data
|
||||||
|
# and reject submissions classified as spam
|
||||||
|
# Example:
|
||||||
|
parsed_data = dict(urllib.parse.parse_qsl(verification_data))
|
||||||
|
if parsed_data.get('classification') == 'BAD':
|
||||||
|
raise ValidationError('This submission was classified as spam')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error(f"ALTCHA validation error: {str(e)}")
|
||||||
|
raise ValidationError('ALTCHA validation failed')
|
||||||
|
"""
|
||||||
|
|
||||||
class Form_Contact(FlaskForm):
|
class Form_Contact(FlaskForm):
|
||||||
email = StringField('Email')
|
email = StringField('Email')
|
||||||
@@ -29,5 +80,6 @@ class Form_Contact(FlaskForm):
|
|||||||
company_name = StringField('Company')
|
company_name = StringField('Company')
|
||||||
message = TextAreaField('Message')
|
message = TextAreaField('Message')
|
||||||
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
||||||
recaptcha = RecaptchaField()
|
# recaptcha = RecaptchaField()
|
||||||
|
altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
|
||||||
submit = SubmitField('Send Message')
|
submit = SubmitField('Send Message')
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||||
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
||||||
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
||||||
FLAG_RECAPTCHA: ClassVar[str] = 'recaptcha'
|
FLAG_CAPTCHA: ClassVar[str] = 'recaptcha'
|
||||||
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||||
FLAG_ROW: ClassVar[str] = 'row'
|
FLAG_ROW: ClassVar[str] = 'row'
|
||||||
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class Model_View_Contact(Model_View_Base):
|
|||||||
FLAG_COMPANY_NAME: ClassVar[str] = 'company_name'
|
FLAG_COMPANY_NAME: ClassVar[str] = 'company_name'
|
||||||
FLAG_CONTACT_NAME: ClassVar[str] = 'contact_name'
|
FLAG_CONTACT_NAME: ClassVar[str] = 'contact_name'
|
||||||
FLAG_RECEIVE_MARKETING: ClassVar[str] = 'receive_marketing'
|
FLAG_RECEIVE_MARKETING: ClassVar[str] = 'receive_marketing'
|
||||||
|
ID_CONTACT_FORM: ClassVar[str] = 'contact-form'
|
||||||
"""
|
"""
|
||||||
ID_EMAIL: ClassVar[str] = 'email'
|
ID_EMAIL: ClassVar[str] = 'email'
|
||||||
ID_COMPANY_NAME: ClassVar[str] = 'company_name'
|
ID_COMPANY_NAME: ClassVar[str] = 'company_name'
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ python_dotenv
|
|||||||
authlib
|
authlib
|
||||||
pydantic
|
pydantic
|
||||||
# psycopg2
|
# psycopg2
|
||||||
requests
|
requests
|
||||||
|
cryptography
|
||||||
693
static/dist/js/main.bundle.js
vendored
693
static/dist/js/main.bundle.js
vendored
@@ -1,603 +1,7 @@
|
|||||||
/******/ (() => { // webpackBootstrap
|
/******/ (() => { // webpackBootstrap
|
||||||
/******/ var __webpack_modules__ = ({
|
/******/ "use strict";
|
||||||
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
/***/ 431:
|
|
||||||
/***/ (function(module) {
|
|
||||||
|
|
||||||
!function (e, t) {
|
|
||||||
true ? module.exports = t() : 0;
|
|
||||||
}(this, function () {
|
|
||||||
return function (e) {
|
|
||||||
function t(o) {
|
|
||||||
if (n[o]) return n[o].exports;
|
|
||||||
var i = n[o] = {
|
|
||||||
exports: {},
|
|
||||||
id: o,
|
|
||||||
loaded: !1
|
|
||||||
};
|
|
||||||
return e[o].call(i.exports, i, i.exports, t), i.loaded = !0, i.exports;
|
|
||||||
}
|
|
||||||
var n = {};
|
|
||||||
return t.m = e, t.c = n, t.p = "dist/", t(0);
|
|
||||||
}([function (e, t, n) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function o(e) {
|
|
||||||
return e && e.__esModule ? e : {
|
|
||||||
default: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var i = Object.assign || function (e) {
|
|
||||||
for (var t = 1; t < arguments.length; t++) {
|
|
||||||
var n = arguments[t];
|
|
||||||
for (var o in n) Object.prototype.hasOwnProperty.call(n, o) && (e[o] = n[o]);
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
},
|
|
||||||
r = n(1),
|
|
||||||
a = (o(r), n(6)),
|
|
||||||
u = o(a),
|
|
||||||
c = n(7),
|
|
||||||
s = o(c),
|
|
||||||
f = n(8),
|
|
||||||
d = o(f),
|
|
||||||
l = n(9),
|
|
||||||
p = o(l),
|
|
||||||
m = n(10),
|
|
||||||
b = o(m),
|
|
||||||
v = n(11),
|
|
||||||
y = o(v),
|
|
||||||
g = n(14),
|
|
||||||
h = o(g),
|
|
||||||
w = [],
|
|
||||||
k = !1,
|
|
||||||
x = {
|
|
||||||
offset: 120,
|
|
||||||
delay: 0,
|
|
||||||
easing: "ease",
|
|
||||||
duration: 400,
|
|
||||||
disable: !1,
|
|
||||||
once: !1,
|
|
||||||
startEvent: "DOMContentLoaded",
|
|
||||||
throttleDelay: 99,
|
|
||||||
debounceDelay: 50,
|
|
||||||
disableMutationObserver: !1
|
|
||||||
},
|
|
||||||
j = function () {
|
|
||||||
var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
|
|
||||||
if (e && (k = !0), k) return w = (0, y.default)(w, x), (0, b.default)(w, x.once), w;
|
|
||||||
},
|
|
||||||
O = function () {
|
|
||||||
w = (0, h.default)(), j();
|
|
||||||
},
|
|
||||||
M = function () {
|
|
||||||
w.forEach(function (e, t) {
|
|
||||||
e.node.removeAttribute("data-aos"), e.node.removeAttribute("data-aos-easing"), e.node.removeAttribute("data-aos-duration"), e.node.removeAttribute("data-aos-delay");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
S = function (e) {
|
|
||||||
return e === !0 || "mobile" === e && p.default.mobile() || "phone" === e && p.default.phone() || "tablet" === e && p.default.tablet() || "function" == typeof e && e() === !0;
|
|
||||||
},
|
|
||||||
_ = function (e) {
|
|
||||||
x = i(x, e), w = (0, h.default)();
|
|
||||||
var t = document.all && !window.atob;
|
|
||||||
return S(x.disable) || t ? M() : (x.disableMutationObserver || d.default.isSupported() || (console.info('\n aos: MutationObserver is not supported on this browser,\n code mutations observing has been disabled.\n You may have to call "refreshHard()" by yourself.\n '), x.disableMutationObserver = !0), document.querySelector("body").setAttribute("data-aos-easing", x.easing), document.querySelector("body").setAttribute("data-aos-duration", x.duration), document.querySelector("body").setAttribute("data-aos-delay", x.delay), "DOMContentLoaded" === x.startEvent && ["complete", "interactive"].indexOf(document.readyState) > -1 ? j(!0) : "load" === x.startEvent ? window.addEventListener(x.startEvent, function () {
|
|
||||||
j(!0);
|
|
||||||
}) : document.addEventListener(x.startEvent, function () {
|
|
||||||
j(!0);
|
|
||||||
}), window.addEventListener("resize", (0, s.default)(j, x.debounceDelay, !0)), window.addEventListener("orientationchange", (0, s.default)(j, x.debounceDelay, !0)), window.addEventListener("scroll", (0, u.default)(function () {
|
|
||||||
(0, b.default)(w, x.once);
|
|
||||||
}, x.throttleDelay)), x.disableMutationObserver || d.default.ready("[data-aos]", O), w);
|
|
||||||
};
|
|
||||||
e.exports = {
|
|
||||||
init: _,
|
|
||||||
refresh: j,
|
|
||||||
refreshHard: O
|
|
||||||
};
|
|
||||||
}, function (e, t) {},,,,, function (e, t) {
|
|
||||||
(function (t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function n(e, t, n) {
|
|
||||||
function o(t) {
|
|
||||||
var n = b,
|
|
||||||
o = v;
|
|
||||||
return b = v = void 0, k = t, g = e.apply(o, n);
|
|
||||||
}
|
|
||||||
function r(e) {
|
|
||||||
return k = e, h = setTimeout(f, t), M ? o(e) : g;
|
|
||||||
}
|
|
||||||
function a(e) {
|
|
||||||
var n = e - w,
|
|
||||||
o = e - k,
|
|
||||||
i = t - n;
|
|
||||||
return S ? j(i, y - o) : i;
|
|
||||||
}
|
|
||||||
function c(e) {
|
|
||||||
var n = e - w,
|
|
||||||
o = e - k;
|
|
||||||
return void 0 === w || n >= t || n < 0 || S && o >= y;
|
|
||||||
}
|
|
||||||
function f() {
|
|
||||||
var e = O();
|
|
||||||
return c(e) ? d(e) : void (h = setTimeout(f, a(e)));
|
|
||||||
}
|
|
||||||
function d(e) {
|
|
||||||
return h = void 0, _ && b ? o(e) : (b = v = void 0, g);
|
|
||||||
}
|
|
||||||
function l() {
|
|
||||||
void 0 !== h && clearTimeout(h), k = 0, b = w = v = h = void 0;
|
|
||||||
}
|
|
||||||
function p() {
|
|
||||||
return void 0 === h ? g : d(O());
|
|
||||||
}
|
|
||||||
function m() {
|
|
||||||
var e = O(),
|
|
||||||
n = c(e);
|
|
||||||
if (b = arguments, v = this, w = e, n) {
|
|
||||||
if (void 0 === h) return r(w);
|
|
||||||
if (S) return h = setTimeout(f, t), o(w);
|
|
||||||
}
|
|
||||||
return void 0 === h && (h = setTimeout(f, t)), g;
|
|
||||||
}
|
|
||||||
var b,
|
|
||||||
v,
|
|
||||||
y,
|
|
||||||
g,
|
|
||||||
h,
|
|
||||||
w,
|
|
||||||
k = 0,
|
|
||||||
M = !1,
|
|
||||||
S = !1,
|
|
||||||
_ = !0;
|
|
||||||
if ("function" != typeof e) throw new TypeError(s);
|
|
||||||
return t = u(t) || 0, i(n) && (M = !!n.leading, S = "maxWait" in n, y = S ? x(u(n.maxWait) || 0, t) : y, _ = "trailing" in n ? !!n.trailing : _), m.cancel = l, m.flush = p, m;
|
|
||||||
}
|
|
||||||
function o(e, t, o) {
|
|
||||||
var r = !0,
|
|
||||||
a = !0;
|
|
||||||
if ("function" != typeof e) throw new TypeError(s);
|
|
||||||
return i(o) && (r = "leading" in o ? !!o.leading : r, a = "trailing" in o ? !!o.trailing : a), n(e, t, {
|
|
||||||
leading: r,
|
|
||||||
maxWait: t,
|
|
||||||
trailing: a
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function i(e) {
|
|
||||||
var t = "undefined" == typeof e ? "undefined" : c(e);
|
|
||||||
return !!e && ("object" == t || "function" == t);
|
|
||||||
}
|
|
||||||
function r(e) {
|
|
||||||
return !!e && "object" == ("undefined" == typeof e ? "undefined" : c(e));
|
|
||||||
}
|
|
||||||
function a(e) {
|
|
||||||
return "symbol" == ("undefined" == typeof e ? "undefined" : c(e)) || r(e) && k.call(e) == d;
|
|
||||||
}
|
|
||||||
function u(e) {
|
|
||||||
if ("number" == typeof e) return e;
|
|
||||||
if (a(e)) return f;
|
|
||||||
if (i(e)) {
|
|
||||||
var t = "function" == typeof e.valueOf ? e.valueOf() : e;
|
|
||||||
e = i(t) ? t + "" : t;
|
|
||||||
}
|
|
||||||
if ("string" != typeof e) return 0 === e ? e : +e;
|
|
||||||
e = e.replace(l, "");
|
|
||||||
var n = m.test(e);
|
|
||||||
return n || b.test(e) ? v(e.slice(2), n ? 2 : 8) : p.test(e) ? f : +e;
|
|
||||||
}
|
|
||||||
var c = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) {
|
|
||||||
return typeof e;
|
|
||||||
} : function (e) {
|
|
||||||
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e;
|
|
||||||
},
|
|
||||||
s = "Expected a function",
|
|
||||||
f = NaN,
|
|
||||||
d = "[object Symbol]",
|
|
||||||
l = /^\s+|\s+$/g,
|
|
||||||
p = /^[-+]0x[0-9a-f]+$/i,
|
|
||||||
m = /^0b[01]+$/i,
|
|
||||||
b = /^0o[0-7]+$/i,
|
|
||||||
v = parseInt,
|
|
||||||
y = "object" == ("undefined" == typeof t ? "undefined" : c(t)) && t && t.Object === Object && t,
|
|
||||||
g = "object" == ("undefined" == typeof self ? "undefined" : c(self)) && self && self.Object === Object && self,
|
|
||||||
h = y || g || Function("return this")(),
|
|
||||||
w = Object.prototype,
|
|
||||||
k = w.toString,
|
|
||||||
x = Math.max,
|
|
||||||
j = Math.min,
|
|
||||||
O = function () {
|
|
||||||
return h.Date.now();
|
|
||||||
};
|
|
||||||
e.exports = o;
|
|
||||||
}).call(t, function () {
|
|
||||||
return this;
|
|
||||||
}());
|
|
||||||
}, function (e, t) {
|
|
||||||
(function (t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function n(e, t, n) {
|
|
||||||
function i(t) {
|
|
||||||
var n = b,
|
|
||||||
o = v;
|
|
||||||
return b = v = void 0, O = t, g = e.apply(o, n);
|
|
||||||
}
|
|
||||||
function r(e) {
|
|
||||||
return O = e, h = setTimeout(f, t), M ? i(e) : g;
|
|
||||||
}
|
|
||||||
function u(e) {
|
|
||||||
var n = e - w,
|
|
||||||
o = e - O,
|
|
||||||
i = t - n;
|
|
||||||
return S ? x(i, y - o) : i;
|
|
||||||
}
|
|
||||||
function s(e) {
|
|
||||||
var n = e - w,
|
|
||||||
o = e - O;
|
|
||||||
return void 0 === w || n >= t || n < 0 || S && o >= y;
|
|
||||||
}
|
|
||||||
function f() {
|
|
||||||
var e = j();
|
|
||||||
return s(e) ? d(e) : void (h = setTimeout(f, u(e)));
|
|
||||||
}
|
|
||||||
function d(e) {
|
|
||||||
return h = void 0, _ && b ? i(e) : (b = v = void 0, g);
|
|
||||||
}
|
|
||||||
function l() {
|
|
||||||
void 0 !== h && clearTimeout(h), O = 0, b = w = v = h = void 0;
|
|
||||||
}
|
|
||||||
function p() {
|
|
||||||
return void 0 === h ? g : d(j());
|
|
||||||
}
|
|
||||||
function m() {
|
|
||||||
var e = j(),
|
|
||||||
n = s(e);
|
|
||||||
if (b = arguments, v = this, w = e, n) {
|
|
||||||
if (void 0 === h) return r(w);
|
|
||||||
if (S) return h = setTimeout(f, t), i(w);
|
|
||||||
}
|
|
||||||
return void 0 === h && (h = setTimeout(f, t)), g;
|
|
||||||
}
|
|
||||||
var b,
|
|
||||||
v,
|
|
||||||
y,
|
|
||||||
g,
|
|
||||||
h,
|
|
||||||
w,
|
|
||||||
O = 0,
|
|
||||||
M = !1,
|
|
||||||
S = !1,
|
|
||||||
_ = !0;
|
|
||||||
if ("function" != typeof e) throw new TypeError(c);
|
|
||||||
return t = a(t) || 0, o(n) && (M = !!n.leading, S = "maxWait" in n, y = S ? k(a(n.maxWait) || 0, t) : y, _ = "trailing" in n ? !!n.trailing : _), m.cancel = l, m.flush = p, m;
|
|
||||||
}
|
|
||||||
function o(e) {
|
|
||||||
var t = "undefined" == typeof e ? "undefined" : u(e);
|
|
||||||
return !!e && ("object" == t || "function" == t);
|
|
||||||
}
|
|
||||||
function i(e) {
|
|
||||||
return !!e && "object" == ("undefined" == typeof e ? "undefined" : u(e));
|
|
||||||
}
|
|
||||||
function r(e) {
|
|
||||||
return "symbol" == ("undefined" == typeof e ? "undefined" : u(e)) || i(e) && w.call(e) == f;
|
|
||||||
}
|
|
||||||
function a(e) {
|
|
||||||
if ("number" == typeof e) return e;
|
|
||||||
if (r(e)) return s;
|
|
||||||
if (o(e)) {
|
|
||||||
var t = "function" == typeof e.valueOf ? e.valueOf() : e;
|
|
||||||
e = o(t) ? t + "" : t;
|
|
||||||
}
|
|
||||||
if ("string" != typeof e) return 0 === e ? e : +e;
|
|
||||||
e = e.replace(d, "");
|
|
||||||
var n = p.test(e);
|
|
||||||
return n || m.test(e) ? b(e.slice(2), n ? 2 : 8) : l.test(e) ? s : +e;
|
|
||||||
}
|
|
||||||
var u = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) {
|
|
||||||
return typeof e;
|
|
||||||
} : function (e) {
|
|
||||||
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e;
|
|
||||||
},
|
|
||||||
c = "Expected a function",
|
|
||||||
s = NaN,
|
|
||||||
f = "[object Symbol]",
|
|
||||||
d = /^\s+|\s+$/g,
|
|
||||||
l = /^[-+]0x[0-9a-f]+$/i,
|
|
||||||
p = /^0b[01]+$/i,
|
|
||||||
m = /^0o[0-7]+$/i,
|
|
||||||
b = parseInt,
|
|
||||||
v = "object" == ("undefined" == typeof t ? "undefined" : u(t)) && t && t.Object === Object && t,
|
|
||||||
y = "object" == ("undefined" == typeof self ? "undefined" : u(self)) && self && self.Object === Object && self,
|
|
||||||
g = v || y || Function("return this")(),
|
|
||||||
h = Object.prototype,
|
|
||||||
w = h.toString,
|
|
||||||
k = Math.max,
|
|
||||||
x = Math.min,
|
|
||||||
j = function () {
|
|
||||||
return g.Date.now();
|
|
||||||
};
|
|
||||||
e.exports = n;
|
|
||||||
}).call(t, function () {
|
|
||||||
return this;
|
|
||||||
}());
|
|
||||||
}, function (e, t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function n(e) {
|
|
||||||
var t = void 0,
|
|
||||||
o = void 0,
|
|
||||||
i = void 0;
|
|
||||||
for (t = 0; t < e.length; t += 1) {
|
|
||||||
if (o = e[t], o.dataset && o.dataset.aos) return !0;
|
|
||||||
if (i = o.children && n(o.children)) return !0;
|
|
||||||
}
|
|
||||||
return !1;
|
|
||||||
}
|
|
||||||
function o() {
|
|
||||||
return window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
|
|
||||||
}
|
|
||||||
function i() {
|
|
||||||
return !!o();
|
|
||||||
}
|
|
||||||
function r(e, t) {
|
|
||||||
var n = window.document,
|
|
||||||
i = o(),
|
|
||||||
r = new i(a);
|
|
||||||
u = t, r.observe(n.documentElement, {
|
|
||||||
childList: !0,
|
|
||||||
subtree: !0,
|
|
||||||
removedNodes: !0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function a(e) {
|
|
||||||
e && e.forEach(function (e) {
|
|
||||||
var t = Array.prototype.slice.call(e.addedNodes),
|
|
||||||
o = Array.prototype.slice.call(e.removedNodes),
|
|
||||||
i = t.concat(o);
|
|
||||||
if (n(i)) return u();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var u = function () {};
|
|
||||||
t.default = {
|
|
||||||
isSupported: i,
|
|
||||||
ready: r
|
|
||||||
};
|
|
||||||
}, function (e, t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function n(e, t) {
|
|
||||||
if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function");
|
|
||||||
}
|
|
||||||
function o() {
|
|
||||||
return navigator.userAgent || navigator.vendor || window.opera || "";
|
|
||||||
}
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var i = function () {
|
|
||||||
function e(e, t) {
|
|
||||||
for (var n = 0; n < t.length; n++) {
|
|
||||||
var o = t[n];
|
|
||||||
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, o.key, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return function (t, n, o) {
|
|
||||||
return n && e(t.prototype, n), o && e(t, o), t;
|
|
||||||
};
|
|
||||||
}(),
|
|
||||||
r = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i,
|
|
||||||
a = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
|
|
||||||
u = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i,
|
|
||||||
c = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
|
|
||||||
s = function () {
|
|
||||||
function e() {
|
|
||||||
n(this, e);
|
|
||||||
}
|
|
||||||
return i(e, [{
|
|
||||||
key: "phone",
|
|
||||||
value: function () {
|
|
||||||
var e = o();
|
|
||||||
return !(!r.test(e) && !a.test(e.substr(0, 4)));
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "mobile",
|
|
||||||
value: function () {
|
|
||||||
var e = o();
|
|
||||||
return !(!u.test(e) && !c.test(e.substr(0, 4)));
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "tablet",
|
|
||||||
value: function () {
|
|
||||||
return this.mobile() && !this.phone();
|
|
||||||
}
|
|
||||||
}]), e;
|
|
||||||
}();
|
|
||||||
t.default = new s();
|
|
||||||
}, function (e, t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var n = function (e, t, n) {
|
|
||||||
var o = e.node.getAttribute("data-aos-once");
|
|
||||||
t > e.position ? e.node.classList.add("aos-animate") : "undefined" != typeof o && ("false" === o || !n && "true" !== o) && e.node.classList.remove("aos-animate");
|
|
||||||
},
|
|
||||||
o = function (e, t) {
|
|
||||||
var o = window.pageYOffset,
|
|
||||||
i = window.innerHeight;
|
|
||||||
e.forEach(function (e, r) {
|
|
||||||
n(e, i + o, t);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
t.default = o;
|
|
||||||
}, function (e, t, n) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function o(e) {
|
|
||||||
return e && e.__esModule ? e : {
|
|
||||||
default: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var i = n(12),
|
|
||||||
r = o(i),
|
|
||||||
a = function (e, t) {
|
|
||||||
return e.forEach(function (e, n) {
|
|
||||||
e.node.classList.add("aos-init"), e.position = (0, r.default)(e.node, t.offset);
|
|
||||||
}), e;
|
|
||||||
};
|
|
||||||
t.default = a;
|
|
||||||
}, function (e, t, n) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function o(e) {
|
|
||||||
return e && e.__esModule ? e : {
|
|
||||||
default: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var i = n(13),
|
|
||||||
r = o(i),
|
|
||||||
a = function (e, t) {
|
|
||||||
var n = 0,
|
|
||||||
o = 0,
|
|
||||||
i = window.innerHeight,
|
|
||||||
a = {
|
|
||||||
offset: e.getAttribute("data-aos-offset"),
|
|
||||||
anchor: e.getAttribute("data-aos-anchor"),
|
|
||||||
anchorPlacement: e.getAttribute("data-aos-anchor-placement")
|
|
||||||
};
|
|
||||||
switch (a.offset && !isNaN(a.offset) && (o = parseInt(a.offset)), a.anchor && document.querySelectorAll(a.anchor) && (e = document.querySelectorAll(a.anchor)[0]), n = (0, r.default)(e).top, a.anchorPlacement) {
|
|
||||||
case "top-bottom":
|
|
||||||
break;
|
|
||||||
case "center-bottom":
|
|
||||||
n += e.offsetHeight / 2;
|
|
||||||
break;
|
|
||||||
case "bottom-bottom":
|
|
||||||
n += e.offsetHeight;
|
|
||||||
break;
|
|
||||||
case "top-center":
|
|
||||||
n += i / 2;
|
|
||||||
break;
|
|
||||||
case "bottom-center":
|
|
||||||
n += i / 2 + e.offsetHeight;
|
|
||||||
break;
|
|
||||||
case "center-center":
|
|
||||||
n += i / 2 + e.offsetHeight / 2;
|
|
||||||
break;
|
|
||||||
case "top-top":
|
|
||||||
n += i;
|
|
||||||
break;
|
|
||||||
case "bottom-top":
|
|
||||||
n += e.offsetHeight + i;
|
|
||||||
break;
|
|
||||||
case "center-top":
|
|
||||||
n += e.offsetHeight / 2 + i;
|
|
||||||
}
|
|
||||||
return a.anchorPlacement || a.offset || isNaN(t) || (o = t), n + o;
|
|
||||||
};
|
|
||||||
t.default = a;
|
|
||||||
}, function (e, t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var n = function (e) {
|
|
||||||
for (var t = 0, n = 0; e && !isNaN(e.offsetLeft) && !isNaN(e.offsetTop);) t += e.offsetLeft - ("BODY" != e.tagName ? e.scrollLeft : 0), n += e.offsetTop - ("BODY" != e.tagName ? e.scrollTop : 0), e = e.offsetParent;
|
|
||||||
return {
|
|
||||||
top: n,
|
|
||||||
left: t
|
|
||||||
};
|
|
||||||
};
|
|
||||||
t.default = n;
|
|
||||||
}, function (e, t) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
Object.defineProperty(t, "__esModule", {
|
|
||||||
value: !0
|
|
||||||
});
|
|
||||||
var n = function (e) {
|
|
||||||
return e = e || document.querySelectorAll("[data-aos]"), Array.prototype.map.call(e, function (e) {
|
|
||||||
return {
|
|
||||||
node: e
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
t.default = n;
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
/******/ });
|
|
||||||
/************************************************************************/
|
|
||||||
/******/ // The module cache
|
|
||||||
/******/ var __webpack_module_cache__ = {};
|
|
||||||
/******/
|
|
||||||
/******/ // The require function
|
|
||||||
/******/ function __webpack_require__(moduleId) {
|
|
||||||
/******/ // Check if module is in cache
|
|
||||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
||||||
/******/ if (cachedModule !== undefined) {
|
|
||||||
/******/ return cachedModule.exports;
|
|
||||||
/******/ }
|
|
||||||
/******/ // Create a new module (and put it into the cache)
|
|
||||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
||||||
/******/ // no module.id needed
|
|
||||||
/******/ // no module.loaded needed
|
|
||||||
/******/ exports: {}
|
|
||||||
/******/ };
|
|
||||||
/******/
|
|
||||||
/******/ // Execute the module function
|
|
||||||
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
||||||
/******/
|
|
||||||
/******/ // Return the exports of the module
|
|
||||||
/******/ return module.exports;
|
|
||||||
/******/ }
|
|
||||||
/******/
|
|
||||||
/************************************************************************/
|
|
||||||
/******/ /* webpack/runtime/compat get default export */
|
|
||||||
/******/ (() => {
|
|
||||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
||||||
/******/ __webpack_require__.n = (module) => {
|
|
||||||
/******/ var getter = module && module.__esModule ?
|
|
||||||
/******/ () => (module['default']) :
|
|
||||||
/******/ () => (module);
|
|
||||||
/******/ __webpack_require__.d(getter, { a: getter });
|
|
||||||
/******/ return getter;
|
|
||||||
/******/ };
|
|
||||||
/******/ })();
|
|
||||||
/******/
|
|
||||||
/******/ /* webpack/runtime/define property getters */
|
|
||||||
/******/ (() => {
|
|
||||||
/******/ // define getter functions for harmony exports
|
|
||||||
/******/ __webpack_require__.d = (exports, definition) => {
|
|
||||||
/******/ for(var key in definition) {
|
|
||||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
||||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
||||||
/******/ }
|
|
||||||
/******/ }
|
|
||||||
/******/ };
|
|
||||||
/******/ })();
|
|
||||||
/******/
|
|
||||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
||||||
/******/ (() => {
|
|
||||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
||||||
/******/ })();
|
|
||||||
/******/
|
|
||||||
/************************************************************************/
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// UNUSED EXPORTS: default
|
// UNUSED EXPORTS: default
|
||||||
|
|
||||||
@@ -1320,9 +724,6 @@ var BasePage = /*#__PURE__*/function () {
|
|||||||
}]);
|
}]);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
// EXTERNAL MODULE: ./node_modules/aos/dist/aos.js
|
|
||||||
var aos = __webpack_require__(431);
|
|
||||||
var aos_default = /*#__PURE__*/__webpack_require__.n(aos);
|
|
||||||
;// ./static/js/pages/core/home.js
|
;// ./static/js/pages/core/home.js
|
||||||
function home_typeof(o) { "@babel/helpers - typeof"; return home_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, home_typeof(o); }
|
function home_typeof(o) { "@babel/helpers - typeof"; return home_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, home_typeof(o); }
|
||||||
function home_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
|
function home_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
|
||||||
@@ -1344,7 +745,6 @@ function home_toPrimitive(t, r) { if ("object" != home_typeof(t) || !t) return t
|
|||||||
// internal
|
// internal
|
||||||
|
|
||||||
// external
|
// external
|
||||||
|
|
||||||
var PageHome = /*#__PURE__*/function (_BasePage) {
|
var PageHome = /*#__PURE__*/function (_BasePage) {
|
||||||
function PageHome(router) {
|
function PageHome(router) {
|
||||||
home_classCallCheck(this, PageHome);
|
home_classCallCheck(this, PageHome);
|
||||||
@@ -1356,45 +756,7 @@ var PageHome = /*#__PURE__*/function (_BasePage) {
|
|||||||
value: function initialize() {
|
value: function initialize() {
|
||||||
this.sharedInitialize();
|
this.sharedInitialize();
|
||||||
this.hookupButtonsNavContact();
|
this.hookupButtonsNavContact();
|
||||||
// this.initialiseAOS();
|
|
||||||
this.initialiseAnimations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AOS */
|
|
||||||
}, {
|
|
||||||
key: "initialiseAOS",
|
|
||||||
value: function initialiseAOS() {
|
|
||||||
aos_default().init({
|
|
||||||
duration: 1000,
|
|
||||||
once: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/* Manual animations *
|
|
||||||
initialiseAnimations() {
|
|
||||||
// Check if IntersectionObserver is supported
|
|
||||||
if ('IntersectionObserver' in window) {
|
|
||||||
const observer = new IntersectionObserver((entries) => {
|
|
||||||
entries.forEach(entry => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.classList.add('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, {
|
|
||||||
threshold: 0.1,
|
|
||||||
rootMargin: '50px'
|
|
||||||
});
|
|
||||||
// Observe all elements with 'reveal' class
|
|
||||||
document.querySelectorAll('.reveal').forEach((element) => {
|
|
||||||
observer.observe(element);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// If IntersectionObserver is not supported, make all elements visible
|
|
||||||
document.querySelectorAll('.reveal').forEach((element) => {
|
|
||||||
element.style.opacity = 1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}, {
|
}, {
|
||||||
key: "leave",
|
key: "leave",
|
||||||
value: function leave() {
|
value: function leave() {
|
||||||
@@ -1430,8 +792,32 @@ var PageContact = /*#__PURE__*/function (_BasePage) {
|
|||||||
key: "initialize",
|
key: "initialize",
|
||||||
value: function initialize() {
|
value: function initialize() {
|
||||||
this.sharedInitialize();
|
this.sharedInitialize();
|
||||||
|
this.hookupCaptcha();
|
||||||
this.hookupButtonSubmitFormContactUs();
|
this.hookupButtonSubmitFormContactUs();
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
key: "hookupCaptcha",
|
||||||
|
value: function hookupCaptcha() {
|
||||||
|
var form = document.querySelector(idContactForm);
|
||||||
|
var altchaWidget = form.querySelector('altcha-widget');
|
||||||
|
|
||||||
|
// Listen for verification events from the ALTCHA widget
|
||||||
|
if (altchaWidget) {
|
||||||
|
altchaWidget.addEventListener('serververification', function (event) {
|
||||||
|
// Create or update the hidden input for ALTCHA
|
||||||
|
var altchaInput = form.querySelector('input[name="altcha"]');
|
||||||
|
if (!altchaInput) {
|
||||||
|
altchaInput = document.createElement('input');
|
||||||
|
altchaInput.type = 'hidden';
|
||||||
|
altchaInput.name = 'altcha';
|
||||||
|
form.appendChild(altchaInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the verification payload
|
||||||
|
altchaInput.value = event.detail.payload;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "hookupButtonSubmitFormContactUs",
|
key: "hookupButtonSubmitFormContactUs",
|
||||||
value: function hookupButtonSubmitFormContactUs() {
|
value: function hookupButtonSubmitFormContactUs() {
|
||||||
@@ -2301,65 +1687,56 @@ window.app = app;
|
|||||||
/* harmony default export */ const js_app = ((/* unused pure expression or super */ null && (app)));
|
/* harmony default export */ const js_app = ((/* unused pure expression or super */ null && (app)));
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
|
||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
|
||||||
// extracted by mini-css-extract-plugin
|
// extracted by mini-css-extract-plugin
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -10,9 +10,32 @@ export default class PageContact extends BasePage {
|
|||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.sharedInitialize();
|
this.sharedInitialize();
|
||||||
|
this.hookupCaptcha();
|
||||||
this.hookupButtonSubmitFormContactUs();
|
this.hookupButtonSubmitFormContactUs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hookupCaptcha() {
|
||||||
|
const form = document.querySelector(idContactForm);
|
||||||
|
const altchaWidget = form.querySelector('altcha-widget');
|
||||||
|
|
||||||
|
// Listen for verification events from the ALTCHA widget
|
||||||
|
if (altchaWidget) {
|
||||||
|
altchaWidget.addEventListener('serververification', function(event) {
|
||||||
|
// Create or update the hidden input for ALTCHA
|
||||||
|
let altchaInput = form.querySelector('input[name="altcha"]');
|
||||||
|
if (!altchaInput) {
|
||||||
|
altchaInput = document.createElement('input');
|
||||||
|
altchaInput.type = 'hidden';
|
||||||
|
altchaInput.name = 'altcha';
|
||||||
|
form.appendChild(altchaInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the verification payload
|
||||||
|
altchaInput.value = event.detail.payload;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hookupButtonSubmitFormContactUs() {
|
hookupButtonSubmitFormContactUs() {
|
||||||
const button = document.querySelector('form input[type="submit"]');
|
const button = document.querySelector('form input[type="submit"]');
|
||||||
button.classList.add(flagButton);
|
button.classList.add(flagButton);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// internal
|
// internal
|
||||||
import BasePage from "../base.js";
|
import BasePage from "../base.js";
|
||||||
// external
|
// external
|
||||||
import AOS from 'aos';
|
|
||||||
|
|
||||||
|
|
||||||
export default class PageHome extends BasePage {
|
export default class PageHome extends BasePage {
|
||||||
@@ -15,46 +14,10 @@ export default class PageHome extends BasePage {
|
|||||||
initialize() {
|
initialize() {
|
||||||
this.sharedInitialize();
|
this.sharedInitialize();
|
||||||
this.hookupButtonsNavContact();
|
this.hookupButtonsNavContact();
|
||||||
// this.initialiseAOS();
|
|
||||||
this.initialiseAnimations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AOS */
|
|
||||||
initialiseAOS() {
|
|
||||||
AOS.init({
|
|
||||||
duration: 1000,
|
|
||||||
once: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/* Manual animations *
|
|
||||||
initialiseAnimations() {
|
|
||||||
// Check if IntersectionObserver is supported
|
|
||||||
if ('IntersectionObserver' in window) {
|
|
||||||
const observer = new IntersectionObserver((entries) => {
|
|
||||||
entries.forEach(entry => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.classList.add('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, {
|
|
||||||
threshold: 0.1,
|
|
||||||
rootMargin: '50px'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Observe all elements with 'reveal' class
|
|
||||||
document.querySelectorAll('.reveal').forEach((element) => {
|
|
||||||
observer.observe(element);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// If IntersectionObserver is not supported, make all elements visible
|
|
||||||
document.querySelectorAll('.reveal').forEach((element) => {
|
|
||||||
element.style.opacity = 1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
leave() {
|
leave() {
|
||||||
super.leave();
|
super.leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2636
static/js/vendor/altcha.js
vendored
Normal file
2636
static/js/vendor/altcha.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -117,7 +117,7 @@
|
|||||||
var flagPageBody = "{{ model.FLAG_PAGE_BODY }}";
|
var flagPageBody = "{{ model.FLAG_PAGE_BODY }}";
|
||||||
var flagPhoneNumber = "{{ model.FLAG_PHONE_NUMBER }}";
|
var flagPhoneNumber = "{{ model.FLAG_PHONE_NUMBER }}";
|
||||||
var flagPostcode = "{{ model.FLAG_POSTCODE }}";
|
var flagPostcode = "{{ model.FLAG_POSTCODE }}";
|
||||||
var flagRecaptcha = "{{ model.FLAG_RECAPTCHA }}";
|
var flagCaptcha = "{{ model.FLAG_CAPTCHA }}";
|
||||||
var flagRightHandSide = "{{ model.FLAG_RIGHT_HAND_SIDE }}";
|
var flagRightHandSide = "{{ model.FLAG_RIGHT_HAND_SIDE }}";
|
||||||
var flagRow = "{{ model.FLAG_ROW }}";
|
var flagRow = "{{ model.FLAG_ROW }}";
|
||||||
var flagRowNew = "{{ model.FLAG_ROW_NEW }}";
|
var flagRowNew = "{{ model.FLAG_ROW_NEW }}";
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
{% block page_head %}
|
{% block page_head %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
|
||||||
|
{#
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@altcha/browser@latest/dist/index.js" defer></script>
|
||||||
|
#}
|
||||||
|
<script type="module" src="{{ url_for('static', filename='js/vendor/altcha.js')}}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_nav_links %}
|
{% block page_nav_links %}
|
||||||
@@ -12,6 +16,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_body %}
|
{% block page_body %}
|
||||||
|
{#
|
||||||
<script>
|
<script>
|
||||||
function loadRecaptcha() {
|
function loadRecaptcha() {
|
||||||
var script = document.createElement('script');
|
var script = document.createElement('script');
|
||||||
@@ -22,15 +27,15 @@
|
|||||||
|
|
||||||
window.addEventListener('load', loadRecaptcha);
|
window.addEventListener('load', loadRecaptcha);
|
||||||
</script>
|
</script>
|
||||||
|
#}
|
||||||
<!-- Divs -->
|
|
||||||
{% set form = model.form_contact %}
|
{% set form = model.form_contact %}
|
||||||
<section class="contact-section">
|
<section class="contact-section">
|
||||||
<div class="contact-form">
|
<div class="contact-form">
|
||||||
<h1>Contact Us</h1>
|
<h1>Contact Us</h1>
|
||||||
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
|
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
|
||||||
|
|
||||||
<form id="contact-form" method="POST" action="{{ url_for('routes_core.contact') }}">
|
<form id="{{ model.ID_CONTACT_FORM }}" method="POST" action="{{ url_for('routes_core.contact') }}">
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
@@ -59,8 +64,12 @@
|
|||||||
{{ model.form_contact.receive_marketing() }}
|
{{ model.form_contact.receive_marketing() }}
|
||||||
{{ model.form_contact.receive_marketing.label }}
|
{{ model.form_contact.receive_marketing.label }}
|
||||||
</div>
|
</div>
|
||||||
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_RECAPTCHA }}">
|
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_CAPTCHA }}">
|
||||||
{{ model.form_contact.recaptcha() }}
|
{# {{ model.form_contact.recaptcha() }} #}
|
||||||
|
<altcha-widget
|
||||||
|
challengeurl="https://eu.altcha.org/api/v1/challenge?apiKey={{ model.app.app_config.ALTCHA_API_KEY }}"
|
||||||
|
spamfilter
|
||||||
|
></altcha-widget>
|
||||||
</div>
|
</div>
|
||||||
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
|
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
|
||||||
{{ model.form_contact.submit() }}
|
{{ model.form_contact.submit() }}
|
||||||
@@ -101,6 +110,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var idContactForm = "#{{ model.ID_CONTACT_FORM }}";
|
||||||
var idEmail = "#{{ model.ID_EMAIL }}";
|
var idEmail = "#{{ model.ID_EMAIL }}";
|
||||||
var idMessage = "#{{ model.ID_MESSAGE }}";
|
var idMessage = "#{{ model.ID_MESSAGE }}";
|
||||||
var idContactName = "#{{ model.ID_CONTACT_NAME }}";
|
var idContactName = "#{{ model.ID_CONTACT_NAME }}";
|
||||||
|
|||||||
Reference in New Issue
Block a user