From 41f71056ad0486735d945e350c70ddd80cec764d Mon Sep 17 00:00:00 2001 From: yaschalew Date: Sat, 11 Jul 2026 11:34:41 +0300 Subject: [PATCH 01/23] fix --- .../backoffice/src/shared/services/organizationsService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/edr-freight-web/backoffice/src/shared/services/organizationsService.ts b/apps/edr-freight-web/backoffice/src/shared/services/organizationsService.ts index 84a88b71c..3a560a08d 100644 --- a/apps/edr-freight-web/backoffice/src/shared/services/organizationsService.ts +++ b/apps/edr-freight-web/backoffice/src/shared/services/organizationsService.ts @@ -46,7 +46,8 @@ export const getOrganizations = async ( }; export const getMyAdminOrganizations = async (): Promise => { - return axiosInstance.get("/organizations/my-admin-organizations", { + //my-admin-organizations + return axiosInstance.get("/organizations/with-admin-flag", { headers: withHeaders(), }); }; From 33a9129e8be0b4c7d10e604313aaef66d7c0c1be Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Sat, 11 Jul 2026 12:13:05 +0300 Subject: [PATCH 02/23] Fix look up by phone number --- .../src/modules/bookings/bookings.service.ts | 179 +++++++++++--- .../portal/src/app/contact/page.tsx | 220 +----------------- .../portal/src/components/Footer.tsx | 6 +- 3 files changed, 151 insertions(+), 254 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index d9c393ee7..74ba9f509 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -53,15 +53,17 @@ function normalizePhoneVariants(raw: string): string[] { const variants = new Set([stripped]); if (stripped.startsWith('+251') && digits.length === 12) { - // +251 9XXXXXXXX → 09XXXXXXXX - variants.add('0' + digits.slice(3)); + // +251 9XXXXXXXX → 251 9XXXXXXXX (no +) → 09XXXXXXXX + variants.add(digits); // 251XXXXXXXXX + variants.add('0' + digits.slice(3)); // 09XXXXXXXXX } else if (stripped.startsWith('251') && digits.length === 12) { // 251 9XXXXXXXX → +251 9XXXXXXXX → 09XXXXXXXX - variants.add('+' + stripped); - variants.add('0' + digits.slice(3)); + variants.add('+' + stripped); // +251XXXXXXXXX + variants.add('0' + digits.slice(3)); // 09XXXXXXXXX } else if (stripped.startsWith('0') && digits.length === 10) { - // 09XXXXXXXX → +251 9XXXXXXXX - variants.add('+251' + digits.slice(1)); + // 09XXXXXXXX → +251 9XXXXXXXX → 251 9XXXXXXXX (no +) + variants.add('+251' + digits.slice(1)); // +251XXXXXXXXX + variants.add('251' + digits.slice(1)); // 251XXXXXXXXX } else if (!stripped.startsWith('+') && digits.length >= 9) { // bare international digits without + variants.add('+' + digits); @@ -183,15 +185,81 @@ export class BookingsService { const { status, page = 1, pageSize = 20 } = filters; const skip = (page - 1) * pageSize; + // Authenticated-user bookings don't store contactPhone — their phone lives in + // iam.users.phone_number linked via passenger.iamUserId. Mirror the same lookup + // that findAll uses for the search field. + const iamRows = await this.dataSource + .query<{ id: string }[]>( + `SELECT u.id FROM iam.users u WHERE u.phone_number = ANY($1::text[])`, + [variants], + ) + .catch((err: unknown) => { + this.logger.warn(`IAM phone lookup failed: ${err instanceof Error ? err.message : String(err)}`); + return [] as { id: string }[]; + }); + + const iamPassengerIds = iamRows.length > 0 + ? (await this.prisma.passenger.findMany({ + where: { iamUserId: { in: iamRows.map(r => r.id) } }, + select: { id: true }, + })).map(p => p.id) + : []; + + // Guest bookings store phone in TravelerProfile.notes JSON (created for every guest booking). + // This catches cases where contactPhone was null but the phone was still recorded in the profile. + const travelerRows = await this.dataSource + .query<{ passengerId: string }[]>( + `SELECT DISTINCT passenger_id AS "passengerId" + FROM passenger.traveler_profiles + WHERE notes IS NOT NULL + AND (notes::jsonb->>'phone') = ANY($1::text[])`, + [variants], + ) + .catch((err: unknown) => { + this.logger.warn(`TravelerProfile phone lookup failed: ${err instanceof Error ? err.message : String(err)}`); + return [] as { passengerId: string }[]; + }); + const travelerPassengerIds = travelerRows.map(r => r.passengerId); + + // Guests who saved their profile (savePassengerDetails:true) have a SavedPassengerProfile + // row with phone + deviceId. Guest bookings store the deviceId in Booking.userAgent. + const savedProfileRows = await this.dataSource + .query<{ deviceId: string }[]>( + `SELECT DISTINCT device_id AS "deviceId" + FROM passenger.saved_passenger_profiles + WHERE phone = ANY($1::text[]) AND device_id IS NOT NULL`, + [variants], + ) + .catch((err: unknown) => { + this.logger.warn(`SavedPassengerProfile phone lookup failed: ${err instanceof Error ? err.message : String(err)}`); + return [] as { deviceId: string }[]; + }); + const guestDeviceIds = savedProfileRows.map(r => r.deviceId); + + // Merge all passenger IDs from every source + const allPassengerIds = [...new Set([...iamPassengerIds, ...travelerPassengerIds])]; + const where: any = { OR: [ { contactPhone: { in: variants } }, { passenger: { user: { phone: { in: variants } } } }, + ...(allPassengerIds.length > 0 ? [{ passengerId: { in: allPassengerIds } }] : []), + ...(guestDeviceIds.length > 0 ? [{ userAgent: { in: guestDeviceIds } }] : []), ], }; if (status) where.status = status; - const [items, total] = await Promise.all([ + // PackageBooking is a separate table with its own contactPhone field — + // must be queried independently or guest package bookings are invisible. + const pkgWhere: any = { + OR: [ + { contactPhone: { in: variants } }, + ...(allPassengerIds.length > 0 ? [{ passengerId: { in: allPassengerIds } }] : []), + ], + }; + if (status) pkgWhere.status = status; + + const [items, total, pkgItems, pkgTotal] = await Promise.all([ this.prisma.booking.findMany({ where, skip, @@ -205,37 +273,84 @@ export class BookingsService { }, }), this.prisma.booking.count({ where }), + this.prisma.packageBooking.findMany({ + where: pkgWhere, + skip, + take: pageSize, + orderBy: { createdAt: 'desc' }, + include: { + package: { + include: { + outboundSchedule: { include: { originStation: true, destinationStation: true } }, + }, + }, + paymentIntent: { select: { method: true, status: true, amountMinor: true, currency: true } }, + }, + }), + this.prisma.packageBooking.count({ where: pkgWhere }), ]); + const mappedBookings = items.map(booking => ({ + id: booking.id, + bookingRef: booking.bookingRef, + status: booking.status, + totalMinor: resolvePackageRoundTripTotal(booking, (booking as any).priceTier?.priceMinor, booking.adultCount, booking.childCount), + currency: 'ETB', + displayCurrency: booking.displayCurrency, + displayTotalMinor: booking.displayTotalMinor, + adultCount: booking.adultCount, + childCount: booking.childCount, + bookingType: booking.bookingType, + returnLegStatus: (booking as any).returnLegStatus ?? null, + createdAt: booking.createdAt, + schedule: { + train: booking.schedule.train, + originStation: booking.schedule.originStation, + destinationStation: booking.schedule.destinationStation, + departureAt: booking.schedule.departureAt, + arrivalAt: booking.schedule.arrivalAt, + }, + payment: booking.paymentIntent ?? undefined, + seatCount: booking.seats.length, + })); + + const mappedPkg = pkgItems.map((b: any) => ({ + id: b.id, + bookingRef: b.bookingRef, + status: b.status, + totalMinor: b.totalMinor, + currency: b.currency || 'ETB', + displayCurrency: b.displayCurrency ?? null, + displayTotalMinor: b.displayTotalMinor ?? null, + adultCount: b.adultCount, + childCount: b.childCount, + bookingType: 'PACKAGE', + returnLegStatus: null, + createdAt: b.createdAt, + schedule: b.package?.outboundSchedule + ? { + train: null, + originStation: b.package.outboundSchedule.originStation, + destinationStation: b.package.outboundSchedule.destinationStation, + departureAt: b.package.outboundSchedule.departureAt, + arrivalAt: b.package.outboundSchedule.arrivalAt, + } + : null, + payment: b.paymentIntent ?? undefined, + seatCount: b.passengerCount, + })); + + const allItems = [...mappedBookings, ...mappedPkg] + .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) + .slice(0, pageSize); + return { - items: items.map(booking => ({ - id: booking.id, - bookingRef: booking.bookingRef, - status: booking.status, - totalMinor: resolvePackageRoundTripTotal(booking, (booking as any).priceTier?.priceMinor, booking.adultCount, booking.childCount), - currency: 'ETB', - displayCurrency: booking.displayCurrency, - displayTotalMinor: booking.displayTotalMinor, - adultCount: booking.adultCount, - childCount: booking.childCount, - bookingType: booking.bookingType, - returnLegStatus: (booking as any).returnLegStatus ?? null, - createdAt: booking.createdAt, - schedule: { - train: booking.schedule.train, - originStation: booking.schedule.originStation, - destinationStation: booking.schedule.destinationStation, - departureAt: booking.schedule.departureAt, - arrivalAt: booking.schedule.arrivalAt, - }, - payment: booking.paymentIntent ?? undefined, - seatCount: booking.seats.length, - })), + items: allItems, meta: { page, pageSize, - total, - totalPages: Math.ceil(total / pageSize), + total: total + pkgTotal, + totalPages: Math.ceil((total + pkgTotal) / pageSize), }, }; } diff --git a/apps/edr-passenger-web/portal/src/app/contact/page.tsx b/apps/edr-passenger-web/portal/src/app/contact/page.tsx index 9f0d2d474..90aa54bd0 100644 --- a/apps/edr-passenger-web/portal/src/app/contact/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/contact/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { getTranslation, Language, useLanguage } from '@/lib/i18n'; -import { Phone, Mail, MapPin, Send, Loader } from 'lucide-react'; +import { Phone, Mail, MapPin } from 'lucide-react'; import { Footer } from '@/components/Footer'; const styles = ` @@ -110,145 +110,10 @@ const styles = ` .contact-card a:hover { color: rgb(20, 113, 76); } - - .form-section { - padding: 60px 20px; - background-color: #f9fafb; - } - - .dark .form-section { - background-color: #0f1117; - } - - .form-container { - max-width: 42rem; - margin: 0 auto; - background: white; - border-radius: 18px; - padding: 32px; - border: 1px solid #e5e7eb; - } - - .dark .form-container { - background: #1f2937; - border-color: #374151; - } - - .form-container h2 { - font-size: 1.5rem; - font-weight: 700; - margin-bottom: 24px; - color: #111827; - } - - .dark .form-container h2 { - color: #f3f4f6; - } - - .form-group { - margin-bottom: 20px; - } - - .form-group label { - display: block; - font-size: 0.875rem; - font-weight: 500; - color: #374151; - margin-bottom: 8px; - } - - .dark .form-group label { - color: #d1d5db; - } - - .form-group input, - .form-group textarea { - width: 100%; - padding: 12px 16px; - border: 2px solid #e5e7eb; - border-radius: 12px; - font-size: 1rem; - font-family: inherit; - transition: all 0.2s; - box-sizing: border-box; - background: white; - color: #111827; - } - - .dark .form-group input, - .dark .form-group textarea { - background: #111827; - color: #f3f4f6; - border-color: #374151; - } - - .form-group input:focus, - .form-group textarea:focus { - outline: none; - border-color: rgb(20, 113, 76); - box-shadow: 0 0 0 3px rgba(20, 113, 76, 0.1); - } - - .form-submit { - width: 100%; - padding: 14px 20px; - background-color: rgb(20, 113, 76); - color: white; - border: none; - border-radius: 12px; - font-weight: 700; - cursor: pointer; - transition: all 0.2s; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - margin-top: 8px; - } - - .form-submit:hover { - background-color: rgb(16, 89, 60); - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); - } - - .form-submit:disabled { - opacity: 0.6; - cursor: not-allowed; - } - - .alert { - padding: 12px 16px; - border-radius: 8px; - margin-bottom: 16px; - font-size: 0.875rem; - } - - .alert-success { - background-color: #dbeafe; - color: #1e40af; - } - - .dark .alert-success { - background-color: rgba(20, 113, 76, 0.1); - color: #a7f3d0; - } - - .alert-error { - background-color: #fee2e2; - color: #991b1b; - } - - .dark .alert-error { - background-color: rgba(239, 68, 68, 0.1); - color: #fca5a5; - } `; export default function Contact() { const [lang, setLang] = useState('en'); - const [formData, setFormData] = useState({ name: '', email: '', subject: '', message: '' }); - const [loading, setLoading] = useState(false); - const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); const { getLang } = useLanguage(); const t = (key: string) => getTranslation(lang, key); @@ -259,21 +124,6 @@ export default function Contact() { return () => window.removeEventListener('languageChange', handleLanguageChange); }, [getLang]); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - - try { - await new Promise(resolve => setTimeout(resolve, 1500)); - setMessage({ type: 'success', text: t('contact.success') }); - setFormData({ name: '', email: '', subject: '', message: '' }); - } catch (error) { - setMessage({ type: 'error', text: t('contact.error') }); - } finally { - setLoading(false); - } - }; - const contactInfo = [ { icon: Phone, title: t('contact.phone'), value: '9546', link: 'tel:9546' }, { icon: Mail, title: t('contact.email'), value: 'edr_@edrsc.com', link: 'mailto:edr_@edrsc.com' }, @@ -303,74 +153,6 @@ export default function Contact() { ); })} - -
-
-

{t('contact.form')}

- - {message && ( -
- {message.text} -
- )} - -
-
- - setFormData({ ...formData, name: e.target.value })} - /> -
- -
- - setFormData({ ...formData, email: e.target.value })} - /> -
- -
- - setFormData({ ...formData, subject: e.target.value })} - /> -
- -
- - ",E.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue,t.innerHTML="",E.option=!!t.lastChild})();var We={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};We.tbody=We.tfoot=We.colgroup=We.caption=We.thead,We.th=We.td,E.option||(We.optgroup=We.option=[1,""]);function Ie(e,t){var i;return typeof e.getElementsByTagName<"u"?i=e.getElementsByTagName(t||"*"):typeof e.querySelectorAll<"u"?i=e.querySelectorAll(t||"*"):i=[],t===void 0||t&&ae(e,t)?u.merge([e],i):i}function Kt(e,t){for(var i=0,l=e.length;i-1){f&&f.push(h);continue}if(w=pt(h),x=Ie(I.appendChild(h),"script"),w&&Kt(x),i)for(R=0;h=x[R++];)br.test(h.type||"")&&i.push(h)}return I}var Dr=/^([^.]*)(?:\.(.+)|)/;function xt(){return!0}function gt(){return!1}function Qt(e,t,i,l,f,h){var x,b;if(typeof t=="object"){typeof i!="string"&&(l=l||i,i=void 0);for(b in t)Qt(e,b,i,l,t[b],h);return e}if(l==null&&f==null?(f=i,l=i=void 0):f==null&&(typeof i=="string"?(f=l,l=void 0):(f=l,l=i,i=void 0)),f===!1)f=gt;else if(!f)return e;return h===1&&(x=f,f=function(v){return u().off(v),x.apply(this,arguments)},f.guid=x.guid||(x.guid=u.guid++)),e.each(function(){u.event.add(this,t,f,l,i)})}u.event={global:{},add:function(e,t,i,l,f){var h,x,b,v,w,R,I,C,F,ne,de,oe=V.get(e);if(Be(e))for(i.handler&&(h=i,i=h.handler,f=h.selector),f&&u.find.matchesSelector(ut,f),i.guid||(i.guid=u.guid++),(v=oe.events)||(v=oe.events=Object.create(null)),(x=oe.handle)||(x=oe.handle=function(Se){return typeof u<"u"&&u.event.triggered!==Se.type?u.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(Ne)||[""],w=t.length;w--;)b=Dr.exec(t[w])||[],F=de=b[1],ne=(b[2]||"").split(".").sort(),F&&(I=u.event.special[F]||{},F=(f?I.delegateType:I.bindType)||F,I=u.event.special[F]||{},R=u.extend({type:F,origType:de,data:l,handler:i,guid:i.guid,selector:f,needsContext:f&&u.expr.match.needsContext.test(f),namespace:ne.join(".")},h),(C=v[F])||(C=v[F]=[],C.delegateCount=0,(!I.setup||I.setup.call(e,l,ne,x)===!1)&&e.addEventListener&&e.addEventListener(F,x)),I.add&&(I.add.call(e,R),R.handler.guid||(R.handler.guid=i.guid)),f?C.splice(C.delegateCount++,0,R):C.push(R),u.event.global[F]=!0)},remove:function(e,t,i,l,f){var h,x,b,v,w,R,I,C,F,ne,de,oe=V.hasData(e)&&V.get(e);if(!(!oe||!(v=oe.events))){for(t=(t||"").match(Ne)||[""],w=t.length;w--;){if(b=Dr.exec(t[w])||[],F=de=b[1],ne=(b[2]||"").split(".").sort(),!F){for(F in v)u.event.remove(e,F+t[w],i,l,!0);continue}for(I=u.event.special[F]||{},F=(l?I.delegateType:I.bindType)||F,C=v[F]||[],b=b[2]&&new RegExp("(^|\\.)"+ne.join("\\.(?:.*\\.|)")+"(\\.|$)"),x=h=C.length;h--;)R=C[h],(f||de===R.origType)&&(!i||i.guid===R.guid)&&(!b||b.test(R.namespace))&&(!l||l===R.selector||l==="**"&&R.selector)&&(C.splice(h,1),R.selector&&C.delegateCount--,I.remove&&I.remove.call(e,R));x&&!C.length&&((!I.teardown||I.teardown.call(e,ne,oe.handle)===!1)&&u.removeEvent(e,F,oe.handle),delete v[F])}u.isEmptyObject(v)&&V.remove(e,"handle events")}},dispatch:function(e){var t,i,l,f,h,x,b=new Array(arguments.length),v=u.event.fix(e),w=(V.get(this,"events")||Object.create(null))[v.type]||[],R=u.event.special[v.type]||{};for(b[0]=v,t=1;t=1)){for(;w!==this;w=w.parentNode||this)if(w.nodeType===1&&!(e.type==="click"&&w.disabled===!0)){for(h=[],x={},i=0;i-1:u.find(f,this,null,[w]).length),x[f]&&h.push(l);h.length&&b.push({elem:w,handlers:h})}}return w=this,v\s*$/g;function kr(e,t){return ae(e,"table")&&ae(t.nodeType!==11?t:t.firstChild,"tr")&&u(e).children("tbody")[0]||e}function nn(e){return e.type=(e.getAttribute("type")!==null)+"/"+e.type,e}function an(e){return(e.type||"").slice(0,5)==="true/"?e.type=e.type.slice(5):e.removeAttribute("type"),e}function wr(e,t){var i,l,f,h,x,b,v;if(t.nodeType===1){if(V.hasData(e)&&(h=V.get(e),v=h.events,v)){V.remove(t,"handle events");for(f in v)for(i=0,l=v[f].length;i1&&typeof F=="string"&&!E.checkClone&&tn.test(F))return e.each(function(de){var oe=e.eq(de);ne&&(t[0]=F.call(this,de,oe.html())),yt(oe,t,i,l)});if(I&&(f=jr(t,e[0].ownerDocument,!1,e,l),h=f.firstChild,f.childNodes.length===1&&(f=h),h||l)){for(x=u?.map(Ie(f,"script"),nn),b=x.length;R0&&Kt(x,!v&&Ie(e,"script")),b},cleanData:function(e){for(var t,i,l,f=u.event.special,h=0;(i=e[h])!==void 0;h++)if(Be(i)){if(t=i[V.expando]){if(t.events)for(l in t.events)f[l]?u.event.remove(i,l):u.removeEvent(i,l,t.handle);i[V.expando]=void 0}i[_e.expando]&&(i[_e.expando]=void 0)}}}),u.fn.extend({detach:function(e){return Er(this,e,!0)},remove:function(e){return Er(this,e)},text:function(e){return xe(this,function(t){return t===void 0?u.text(this):this.empty().each(function(){(this.nodeType===1||this.nodeType===11||this.nodeType===9)&&(this.textContent=t)})},null,e,arguments.length)},append:function(){return yt(this,arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var t=kr(this,e);t.appendChild(e)}})},prepend:function(){return yt(this,arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var t=kr(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return yt(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return yt(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;(e=this[t])!=null;t++)e.nodeType===1&&(u.cleanData(Ie(e,!1)),e.textContent="");return this},clone:function(e,t){return e=e??!1,t=t??e,this?.map(function(){return u.clone(this,e,t)})},html:function(e){return xe(this,function(t){var i=this[0]||{},l=0,f=this.length;if(t===void 0&&i.nodeType===1)return i.innerHTML;if(typeof t=="string"&&!en.test(t)&&!We[(vr.exec(t)||["",""])[1].toLowerCase()]){t=u.htmlPrefilter(t);try{for(;l=0&&(v+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-h-v-b-.5))||0),v+w}function Or(e,t,i){var l=Ht(e),f=!E.boxSizingReliable()||i,h=f&&u.css(e,"boxSizing",!1,l)==="border-box",x=h,b=St(e,t,l),v="offset"+t[0].toUpperCase()+t.slice(1);if(Gt.test(b)){if(!i)return b;b="auto"}return(!E.boxSizingReliable()&&h||!E.reliableTrDimensions()&&ae(e,"tr")||b==="auto"||!parseFloat(b)&&u.css(e,"display",!1,l)==="inline")&&e.getClientRects().length&&(h=u.css(e,"boxSizing",!1,l)==="border-box",x=v in e,x&&(b=e[v])),b=parseFloat(b)||0,b+Zt(e,t,i||(h?"border":"content"),x,l,b)+"px"}u.extend({cssHooks:{opacity:{get:function(e,t){if(t){var i=St(e,"opacity");return i===""?"1":i}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,i,l){if(!(!e||e.nodeType===3||e.nodeType===8||!e.style)){var f,h,x,b=je(t),v=Xt.test(t),w=e.style;if(v||(t=$t(b)),x=u.cssHooks[t]||u.cssHooks[b],i!==void 0){if(h=typeof i,h==="string"&&(f=Nt.exec(i))&&f[1]&&(i=gr(e,t,f),h="number"),i==null||i!==i)return;h==="number"&&!v&&(i+=f&&f[3]||(u.cssNumber[b]?"":"px")),!E.clearCloneStyle&&i===""&&t.indexOf("background")===0&&(w[t]="inherit"),(!x||!("set"in x)||(i=x.set(e,i,l))!==void 0)&&(v?w.setProperty(t,i):w[t]=i)}else return x&&"get"in x&&(f=x.get(e,!1,l))!==void 0?f:w[t]}},css:function(e,t,i,l){var f,h,x,b=je(t),v=Xt.test(t);return v||(t=$t(b)),x=u.cssHooks[t]||u.cssHooks[b],x&&"get"in x&&(f=x.get(e,!0,i)),f===void 0&&(f=St(e,t,l)),f==="normal"&&t in Mr&&(f=Mr[t]),i===""||i?(h=parseFloat(f),i===!0||isFinite(h)?h||0:f):f}}),u.each(["height","width"],function(e,t){u.cssHooks[t]={get:function(i,l,f){if(l)return un.test(u.css(i,"display"))&&(!i.getClientRects().length||!i.getBoundingClientRect().width)?Nr(i,dn,function(){return Or(i,t,f)}):Or(i,t,f)},set:function(i,l,f){var h,x=Ht(i),b=!E.scrollboxSize()&&x.position==="absolute",v=b||f,w=v&&u.css(i,"boxSizing",!1,x)==="border-box",R=f?Zt(i,t,f,w,x):0;return w&&b&&(R-=Math.ceil(i["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(x[t])-Zt(i,t,"border",!1,x)-.5)),R&&(h=Nt.exec(l))&&(h[3]||"px")!=="px"&&(i.style[t]=l,l=u.css(i,t)),Tr(i,l,R)}}}),u.cssHooks.marginLeft=Cr(E.reliableMarginLeft,function(e,t){if(t)return(parseFloat(St(e,"marginLeft"))||e.getBoundingClientRect().left-Nr(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),u.each({margin:"",padding:"",border:"Width"},function(e,t){u.cssHooks[e+t]={expand:function(i){for(var l=0,f={},h=typeof i=="string"?i.split(" "):[i];l<4;l++)f[e+Ze[l]+t]=h[l]||h[l-2]||h[0];return f}},e!=="margin"&&(u.cssHooks[e+t].set=Tr)}),u.fn.extend({css:function(e,t){return xe(this,function(i,l,f){var h,x,b={},v=0;if(Array.isArray(l)){for(h=Ht(i),x=l.length;v1)}});function Ae(e,t,i,l,f){return new Ae.prototype.init(e,t,i,l,f)}u.Tween=Ae,Ae.prototype={constructor:Ae,init:function(e,t,i,l,f,h){this.elem=e,this.prop=i,this.easing=f||u.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=l,this.unit=h||(u.cssNumber[i]?"":"px")},cur:function(){var e=Ae.propHooks[this.prop];return e&&e.get?e.get(this):Ae.propHooks._default.get(this)},run:function(e){var t,i=Ae.propHooks[this.prop];return this.options.duration?this.pos=t=u.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),i&&i.set?i.set(this):Ae.propHooks._default.set(this),this}},Ae.prototype.init.prototype=Ae.prototype,Ae.propHooks={_default:{get:function(e){var t;return e.elem.nodeType!==1||e.elem[e.prop]!=null&&e.elem.style[e.prop]==null?e.elem[e.prop]:(t=u.css(e.elem,e.prop,""),!t||t==="auto"?0:t)},set:function(e){u.fx.step[e.prop]?u.fx.step[e.prop](e):e.elem.nodeType===1&&(u.cssHooks[e.prop]||e.elem.style[$t(e.prop)]!=null)?u.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ae.propHooks.scrollTop=Ae.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},u.easing={linear:function(e){return e},swing:function(e){return .5-Math.cos(e*Math.PI)/2},_default:"swing"},u.fx=Ae.prototype.init,u.fx.step={};var vt,Yt,fn=/^(?:toggle|show|hide)$/,hn=/queueHooks$/;function er(){Yt&&(A.hidden===!1&&o.requestAnimationFrame?o.requestAnimationFrame(er):o.setTimeout(er,u.fx.interval),u.fx.tick())}function Lr(){return o.setTimeout(function(){vt=void 0}),vt=Date.now()}function Bt(e,t){var i,l=0,f={height:e};for(t=t?1:0;l<4;l+=2-t)i=Ze[l],f["margin"+i]=f["padding"+i]=e;return t&&(f.opacity=f.width=e),f}function Ir(e,t,i){for(var l,f=(qe.tweeners[t]||[]).concat(qe.tweeners["*"]),h=0,x=f.length;h1)},removeAttr:function(e){return this.each(function(){u.removeAttr(this,e)})}}),u.extend({attr:function(e,t,i){var l,f,h=e.nodeType;if(!(h===3||h===8||h===2)){if(typeof e.getAttribute>"u")return u.prop(e,t,i);if((h!==1||!u.isXMLDoc(e))&&(f=u.attrHooks[t.toLowerCase()]||(u.expr.match.bool.test(t)?Ar:void 0)),i!==void 0){if(i===null){u.removeAttr(e,t);return}return f&&"set"in f&&(l=f.set(e,i,t))!==void 0?l:(e.setAttribute(t,i+""),i)}return f&&"get"in f&&(l=f.get(e,t))!==null?l:(l=u.find.attr(e,t),l??void 0)}},attrHooks:{type:{set:function(e,t){if(!E.radioValue&&t==="radio"&&ae(e,"input")){var i=e.value;return e.setAttribute("type",t),i&&(e.value=i),t}}}},removeAttr:function(e,t){var i,l=0,f=t&&t.match(Ne);if(f&&e.nodeType===1)for(;i=f[l++];)e.removeAttribute(i)}}),Ar={set:function(e,t,i){return t===!1?u.removeAttr(e,i):e.setAttribute(i,i),i}},u.each(u.expr.match.bool.source.match(/\w+/g),function(e,t){var i=_t[t]||u.find.attr;_t[t]=function(l,f,h){var x,b,v=f.toLowerCase();return h||(b=_t[v],_t[v]=x,x=i(l,f,h)!=null?v:null,_t[v]=b),x}});var xn=/^(?:input|select|textarea|button)$/i,gn=/^(?:a|area)$/i;u.fn.extend({prop:function(e,t){return xe(this,u.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[u.propFix[e]||e]})}}),u.extend({prop:function(e,t,i){var l,f,h=e.nodeType;if(!(h===3||h===8||h===2))return(h!==1||!u.isXMLDoc(e))&&(t=u.propFix[t]||t,f=u.propHooks[t]),i!==void 0?f&&"set"in f&&(l=f.set(e,i,t))!==void 0?l:e[t]=i:f&&"get"in f&&(l=f.get(e,t))!==null?l:e[t]},propHooks:{tabIndex:{get:function(e){var t=u.find.attr(e,"tabindex");return t?parseInt(t,10):xn.test(e.nodeName)||gn.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),E.optSelected||(u.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),u.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){u.propFix[this.toLowerCase()]=this});function ct(e){var t=e.match(Ne)||[];return t.join(" ")}function dt(e){return e.getAttribute&&e.getAttribute("class")||""}function tr(e){return Array.isArray(e)?e:typeof e=="string"?e.match(Ne)||[]:[]}u.fn.extend({addClass:function(e){var t,i,l,f,h,x;return M(e)?this.each(function(b){u(this).addClass(e.call(this,b,dt(this)))}):(t=tr(e),t.length?this.each(function(){if(l=dt(this),i=this.nodeType===1&&" "+ct(l)+" ",i){for(h=0;h-1;)i=i.replace(" "+f+" "," ");x=ct(i),l!==x&&this.setAttribute("class",x)}}):this):this.attr("class","")},toggleClass:function(e,t){var i,l,f,h,x=typeof e,b=x==="string"||Array.isArray(e);return M(e)?this.each(function(v){u(this).toggleClass(e.call(this,v,dt(this),t),t)}):typeof t=="boolean"&&b?t?this.addClass(e):this.removeClass(e):(i=tr(e),this.each(function(){if(b)for(h=u(this),f=0;f-1)return!0;return!1}});var yn=/\r/g;u.fn.extend({val:function(e){var t,i,l,f=this[0];return arguments.length?(l=M(e),this.each(function(h){var x;this.nodeType===1&&(l?x=e.call(this,h,u(this).val()):x=e,x==null?x="":typeof x=="number"?x+="":Array.isArray(x)&&(x=u?.map(x,function(b){return b==null?"":b+""})),t=u.valHooks[this.type]||u.valHooks[this.nodeName.toLowerCase()],(!t||!("set"in t)||t.set(this,x,"value")===void 0)&&(this.value=x))})):f?(t=u.valHooks[f.type]||u.valHooks[f.nodeName.toLowerCase()],t&&"get"in t&&(i=t.get(f,"value"))!==void 0?i:(i=f.value,typeof i=="string"?i.replace(yn,""):i??"")):void 0}}),u.extend({valHooks:{option:{get:function(e){var t=u.find.attr(e,"value");return t??ct(u.text(e))}},select:{get:function(e){var t,i,l,f=e.options,h=e.selectedIndex,x=e.type==="select-one",b=x?null:[],v=x?h+1:f.length;for(h<0?l=v:l=x?h:0;l-1)&&(i=!0);return i||(e.selectedIndex=-1),h}}}}),u.each(["radio","checkbox"],function(){u.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=u.inArray(u(e).val(),t)>-1}},E.checkOn||(u.valHooks[this].get=function(e){return e.getAttribute("value")===null?"on":e.value})});var Rt=o.location,Pr={guid:Date.now()},rr=/\?/;u.parseXML=function(e){var t,i;if(!e||typeof e!="string")return null;try{t=new o.DOMParser().parseFromString(e,"text/xml")}catch{}return i=t&&t.getElementsByTagName("parsererror")[0],(!t||i)&&u.error("Invalid XML: "+(i?u?.map(i.childNodes,function(l){return l.textContent}).join(` -`):e)),t};var Fr=/^(?:focusinfocus|focusoutblur)$/,Wr=function(e){e.stopPropagation()};u.extend(u.event,{trigger:function(e,t,i,l){var f,h,x,b,v,w,R,I,C=[i||A],F=k.call(e,"type")?e.type:e,ne=k.call(e,"namespace")?e.namespace.split("."):[];if(h=I=x=i=i||A,!(i.nodeType===3||i.nodeType===8)&&!Fr.test(F+u.event.triggered)&&(F.indexOf(".")>-1&&(ne=F.split("."),F=ne.shift(),ne.sort()),v=F.indexOf(":")<0&&"on"+F,e=e[u.expando]?e:new u.Event(F,typeof e=="object"&&e),e.isTrigger=l?2:3,e.namespace=ne.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+ne.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=i),t=t==null?[e]:u.makeArray(t,[e]),R=u.event.special[F]||{},!(!l&&R.trigger&&R.trigger.apply(i,t)===!1))){if(!l&&!R.noBubble&&!P(i)){for(b=R.delegateType||F,Fr.test(b+F)||(h=h.parentNode);h;h=h.parentNode)C.push(h),x=h;x===(i.ownerDocument||A)&&C.push(x.defaultView||x.parentWindow||o)}for(f=0;(h=C[f++])&&!e.isPropagationStopped();)I=h,e.type=f>1?b:R.bindType||F,w=(V.get(h,"events")||Object.create(null))[e.type]&&V.get(h,"handle"),w&&w.apply(h,t),w=v&&h[v],w&&w.apply&&Be(h)&&(e.result=w.apply(h,t),e.result===!1&&e.preventDefault());return e.type=F,!l&&!e.isDefaultPrevented()&&(!R._default||R._default.apply(C.pop(),t)===!1)&&Be(i)&&v&&M(i[F])&&!P(i)&&(x=i[v],x&&(i[v]=null),u.event.triggered=F,e.isPropagationStopped()&&I.addEventListener(F,Wr),i[F](),e.isPropagationStopped()&&I.removeEventListener(F,Wr),u.event.triggered=void 0,x&&(i[v]=x)),e.result}},simulate:function(e,t,i){var l=u.extend(new u.Event,i,{type:e,isSimulated:!0});u.event.trigger(l,null,t)}}),u.fn.extend({trigger:function(e,t){return this.each(function(){u.event.trigger(e,t,this)})},triggerHandler:function(e,t){var i=this[0];if(i)return u.event.trigger(e,t,i,!0)}});var vn=/\[\]$/,Hr=/\r?\n/g,bn=/^(?:submit|button|image|reset|file)$/i,jn=/^(?:input|select|textarea|keygen)/i;function nr(e,t,i,l){var f;if(Array.isArray(t))u.each(t,function(h,x){i||vn.test(e)?l(e,x):nr(e+"["+(typeof x=="object"&&x!=null?h:"")+"]",x,i,l)});else if(!i&&se(t)==="object")for(f in t)nr(e+"["+f+"]",t[f],i,l);else l(e,t)}u.param=function(e,t){var i,l=[],f=function(h,x){var b=M(x)?x():x;l[l.length]=encodeURIComponent(h)+"="+encodeURIComponent(b??"")};if(e==null)return"";if(Array.isArray(e)||e.jquery&&!u.isPlainObject(e))u.each(e,function(){f(this.name,this.value)});else for(i in e)nr(i,e[i],t,f);return l.join("&")},u.fn.extend({serialize:function(){return u.param(this.serializeArray())},serializeArray:function(){return this?.map(function(){var e=u.prop(this,"elements");return e?u.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!u(this).is(":disabled")&&jn.test(this.nodeName)&&!bn.test(e)&&(this.checked||!Ct.test(e))})?.map(function(e,t){var i=u(this).val();return i==null?null:Array.isArray(i)?u?.map(i,function(l){return{name:t.name,value:l.replace(Hr,`\r -`)}}):{name:t.name,value:i.replace(Hr,`\r -`)}}).get()}});var Dn=/%20/g,kn=/#.*$/,wn=/([?&])_=[^&]*/,En=/^(.*?):[ \t]*([^\r\n]*)$/mg,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,Sn=/^\/\//,Yr={},ar={},Br="*/".concat("*"),ir=A.createElement("a");ir.href=Rt.href;function qr(e){return function(t,i){typeof t!="string"&&(i=t,t="*");var l,f=0,h=t.toLowerCase().match(Ne)||[];if(M(i))for(;l=h[f++];)l[0]==="+"?(l=l.slice(1)||"*",(e[l]=e[l]||[]).unshift(i)):(e[l]=e[l]||[]).push(i)}}function Jr(e,t,i,l){var f={},h=e===ar;function x(b){var v;return f[b]=!0,u.each(e[b]||[],function(w,R){var I=R(t,i,l);if(typeof I=="string"&&!h&&!f[I])return t.dataTypes.unshift(I),x(I),!1;if(h)return!(v=I)}),v}return x(t.dataTypes[0])||!f["*"]&&x("*")}function sr(e,t){var i,l,f=u.ajaxSettings.flatOptions||{};for(i in t)t[i]!==void 0&&((f[i]?e:l||(l={}))[i]=t[i]);return l&&u.extend(!0,e,l),e}function _n(e,t,i){for(var l,f,h,x,b=e.contents,v=e.dataTypes;v[0]==="*";)v.shift(),l===void 0&&(l=e.mimeType||t.getResponseHeader("Content-Type"));if(l){for(f in b)if(b[f]&&b[f].test(l)){v.unshift(f);break}}if(v[0]in i)h=v[0];else{for(f in i){if(!v[0]||e.converters[f+" "+v[0]]){h=f;break}x||(x=f)}h=h||x}if(h)return h!==v[0]&&v.unshift(h),i[h]}function Rn(e,t,i,l){var f,h,x,b,v,w={},R=e.dataTypes.slice();if(R[1])for(x in e.converters)w[x.toLowerCase()]=e.converters[x];for(h=R.shift();h;)if(e.responseFields[h]&&(i[e.responseFields[h]]=t),!v&&l&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),v=h,h=R.shift(),h){if(h==="*")h=v;else if(v!=="*"&&v!==h){if(x=w[v+" "+h]||w["* "+h],!x){for(f in w)if(b=f.split(" "),b[1]===h&&(x=w[v+" "+b[0]]||w["* "+b[0]],x)){x===!0?x=w[f]:w[f]!==!0&&(h=b[0],R.unshift(b[1]));break}}if(x!==!0)if(x&&e.throws)t=x(t);else try{t=x(t)}catch(I){return{state:"parsererror",error:x?I:"No conversion from "+v+" to "+h}}}}return{state:"success",data:t}}u.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rt.href,type:"GET",isLocal:Nn.test(Rt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Br,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":u.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?sr(sr(e,u.ajaxSettings),t):sr(u.ajaxSettings,e)},ajaxPrefilter:qr(Yr),ajaxTransport:qr(ar),ajax:function(e,t){typeof e=="object"&&(t=e,e=void 0),t=t||{};var i,l,f,h,x,b,v,w,R,I,C=u.ajaxSetup({},t),F=C.context||C,ne=C.context&&(F.nodeType||F.jquery)?u(F):u.event,de=u.Deferred(),oe=u.Callbacks("once memory"),Se=C.statusCode||{},Ce={},Ke={},Qe="canceled",ce={readyState:0,getResponseHeader:function(he){var we;if(v){if(!h)for(h={};we=En.exec(f);)h[we[1].toLowerCase()+" "]=(h[we[1].toLowerCase()+" "]||[]).concat(we[2]);we=h[he.toLowerCase()+" "]}return we==null?null:we.join(", ")},getAllResponseHeaders:function(){return v?f:null},setRequestHeader:function(he,we){return v==null&&(he=Ke[he.toLowerCase()]=Ke[he.toLowerCase()]||he,Ce[he]=we),this},overrideMimeType:function(he){return v==null&&(C.mimeType=he),this},statusCode:function(he){var we;if(he)if(v)ce.always(he[ce.status]);else for(we in he)Se[we]=[Se[we],he[we]];return this},abort:function(he){var we=he||Qe;return i&&i.abort(we),ft(0,we),this}};if(de.promise(ce),C.url=((e||C.url||Rt.href)+"").replace(Sn,Rt.protocol+"//"),C.type=t.method||t.type||C.method||C.type,C.dataTypes=(C.dataType||"*").toLowerCase().match(Ne)||[""],C.crossDomain==null){b=A.createElement("a");try{b.href=C.url,b.href=b.href,C.crossDomain=ir.protocol+"//"+ir.host!=b.protocol+"//"+b.host}catch{C.crossDomain=!0}}if(C.data&&C.processData&&typeof C.data!="string"&&(C.data=u.param(C.data,C.traditional)),Jr(Yr,C,t,ce),v)return ce;w=u.event&&C.global,w&&u.active++===0&&u.event.trigger("ajaxStart"),C.type=C.type.toUpperCase(),C.hasContent=!Cn.test(C.type),l=C.url.replace(kn,""),C.hasContent?C.data&&C.processData&&(C.contentType||"").indexOf("application/x-www-form-urlencoded")===0&&(C.data=C.data.replace(Dn,"+")):(I=C.url.slice(l.length),C.data&&(C.processData||typeof C.data=="string")&&(l+=(rr.test(l)?"&":"?")+C.data,delete C.data),C.cache===!1&&(l=l.replace(wn,"$1"),I=(rr.test(l)?"&":"?")+"_="+Pr.guid+++I),C.url=l+I),C.ifModified&&(u.lastModified[l]&&ce.setRequestHeader("If-Modified-Since",u.lastModified[l]),u.etag[l]&&ce.setRequestHeader("If-None-Match",u.etag[l])),(C.data&&C.hasContent&&C.contentType!==!1||t.contentType)&&ce.setRequestHeader("Content-Type",C.contentType),ce.setRequestHeader("Accept",C.dataTypes[0]&&C.accepts[C.dataTypes[0]]?C.accepts[C.dataTypes[0]]+(C.dataTypes[0]!=="*"?", "+Br+"; q=0.01":""):C.accepts["*"]);for(R in C.headers)ce.setRequestHeader(R,C.headers[R]);if(C.beforeSend&&(C.beforeSend.call(F,ce,C)===!1||v))return ce.abort();if(Qe="abort",oe.add(C.complete),ce.done(C.success),ce.fail(C.error),i=Jr(ar,C,t,ce),!i)ft(-1,"No Transport");else{if(ce.readyState=1,w&&ne.trigger("ajaxSend",[ce,C]),v)return ce;C.async&&C.timeout>0&&(x=o.setTimeout(function(){ce.abort("timeout")},C.timeout));try{v=!1,i.send(Ce,ft)}catch(he){if(v)throw he;ft(-1,he)}}function ft(he,we,Tt,lr){var Ge,Ot,Xe,it,st,He=we;v||(v=!0,x&&o.clearTimeout(x),i=void 0,f=lr||"",ce.readyState=he>0?4:0,Ge=he>=200&&he<300||he===304,Tt&&(it=_n(C,ce,Tt)),!Ge&&u.inArray("script",C.dataTypes)>-1&&u.inArray("json",C.dataTypes)<0&&(C.converters["text script"]=function(){}),it=Rn(C,it,ce,Ge),Ge?(C.ifModified&&(st=ce.getResponseHeader("Last-Modified"),st&&(u.lastModified[l]=st),st=ce.getResponseHeader("etag"),st&&(u.etag[l]=st)),he===204||C.type==="HEAD"?He="nocontent":he===304?He="notmodified":(He=it.state,Ot=it.data,Xe=it.error,Ge=!Xe)):(Xe=He,(he||!He)&&(He="error",he<0&&(he=0))),ce.status=he,ce.statusText=(we||He)+"",Ge?de.resolveWith(F,[Ot,He,ce]):de.rejectWith(F,[ce,He,Xe]),ce.statusCode(Se),Se=void 0,w&&ne.trigger(Ge?"ajaxSuccess":"ajaxError",[ce,C,Ge?Ot:Xe]),oe.fireWith(F,[ce,He]),w&&(ne.trigger("ajaxComplete",[ce,C]),--u.active||u.event.trigger("ajaxStop")))}return ce},getJSON:function(e,t,i){return u.get(e,t,i,"json")},getScript:function(e,t){return u.get(e,void 0,t,"script")}}),u.each(["get","post"],function(e,t){u[t]=function(i,l,f,h){return M(l)&&(h=h||f,f=l,l=void 0),u.ajax(u.extend({url:i,type:t,dataType:h,data:l,success:f},u.isPlainObject(i)&&i))}}),u.ajaxPrefilter(function(e){var t;for(t in e.headers)t.toLowerCase()==="content-type"&&(e.contentType=e.headers[t]||"")}),u._evalUrl=function(e,t,i){return u.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(l){u.globalEval(l,t,i)}})},u.fn.extend({wrapAll:function(e){var t;return this[0]&&(M(e)&&(e=e.call(this[0])),t=u(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t?.map(function(){for(var i=this;i.firstElementChild;)i=i.firstElementChild;return i}).append(this)),this},wrapInner:function(e){return M(e)?this.each(function(t){u(this).wrapInner(e.call(this,t))}):this.each(function(){var t=u(this),i=t.contents();i.length?i.wrapAll(e):t.append(e)})},wrap:function(e){var t=M(e);return this.each(function(i){u(this).wrapAll(t?e.call(this,i):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){u(this).replaceWith(this.childNodes)}),this}}),u.expr.pseudos.hidden=function(e){return!u.expr.pseudos.visible(e)},u.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},u.ajaxSettings.xhr=function(){try{return new o.XMLHttpRequest}catch{}};var Mn={0:200,1223:204},Mt=u.ajaxSettings.xhr();E.cors=!!Mt&&"withCredentials"in Mt,E.ajax=Mt=!!Mt,u.ajaxTransport(function(e){var t,i;if(E.cors||Mt&&!e.crossDomain)return{send:function(l,f){var h,x=e.xhr();if(x.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(h in e.xhrFields)x[h]=e.xhrFields[h];e.mimeType&&x.overrideMimeType&&x.overrideMimeType(e.mimeType),!e.crossDomain&&!l["X-Requested-With"]&&(l["X-Requested-With"]="XMLHttpRequest");for(h in l)x.setRequestHeader(h,l[h]);t=function(b){return function(){t&&(t=i=x.onload=x.onerror=x.onabort=x.ontimeout=x.onreadystatechange=null,b==="abort"?x.abort():b==="error"?typeof x.status!="number"?f(0,"error"):f(x.status,x.statusText):f(Mn[x.status]||x.status,x.statusText,(x.responseType||"text")!=="text"||typeof x.responseText!="string"?{binary:x.response}:{text:x.responseText},x.getAllResponseHeaders()))}},x.onload=t(),i=x.onerror=x.ontimeout=t("error"),x.onabort!==void 0?x.onabort=i:x.onreadystatechange=function(){x.readyState===4&&o.setTimeout(function(){t&&i()})},t=t("abort");try{x.send(e.hasContent&&e.data||null)}catch(b){if(t)throw b}},abort:function(){t&&t()}}}),u.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),u.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return u.globalEval(e),e}}}),u.ajaxPrefilter("script",function(e){e.cache===void 0&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),u.ajaxTransport("script",function(e){if(e.crossDomain||e.scriptAttrs){var t,i;return{send:function(l,f){t=u(" - - - -
- - diff --git a/apps/edr-freight-web/backoffice/public/_um/tinymce/CHANGELOG.md b/apps/edr-freight-web/backoffice/public/_um/tinymce/CHANGELOG.md deleted file mode 100644 index dfa4751f4..000000000 --- a/apps/edr-freight-web/backoffice/public/_um/tinymce/CHANGELOG.md +++ /dev/null @@ -1,3802 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), -and is generated by [Changie](https://github.com/miniscruff/changie). - -## 7.9.3 - 2026-05-19 - -### Security -- Fixed media plugin `data-mce-object` injection leading to stored XSS. #TINY-14357 -- Fixed stored XSS vulnerability through `mce:protected` comments. #TINY-14353 -- Fixed stored XSS vulnerability through `data-mce-` prefixed `src`, `href`, `style` attributes. #TINY-14333 - -## 7.9.2 - 2026-02-11 - -### Deprecated -- The default value of `allow_html_in_comments` will change from `true` to `false` in TinyMCE 8.x. #TINY-11900 - -### Security -- Updated dependencies and parsing logic for enhanced content sanitization. HTML-like content in comments and certain legacy patterns are now sanitized more strictly when `xss_sanitization` is enabled (default). The Introduced `allow_html_in_comments` option provides control over comment node sanitization behavior. - #TINY-11900 -- Introduced `allow_html_in_comments` option (boolean, default: `true`) to control handling of HTML-like syntax in comment nodes. This option will default to `false` in TinyMCE 8.x. #TINY-11900 - -## 7.9.1 - 2025-05-29 - -### Improved -- Update `Notices` file and minified notices. #TINY-12091 - -## 7.9.0 - 2025-05-15 - -### Added -- Added new `disc` style option for unordered lists. #TINY-12015 - -### Improved -- The resize cursor now points in the correct direction for each resize mode. Patch contributed by daniloff200. ##GH-10189 -- If `style_formats` is empty, the button is now disabled. #TINY-12005 -- Inline dialog dropdowns reposition when the dialog is dragged or the window is scrolled. #TINY-11368 -- Bullet list icons were have been updated to better represent the default styles. #TINY-12014 - -### Changed -- The ContextFormSizeInput lock button is now centered instead of aligned to the end. #TINY-11916 -- Changed the default value of `advlist_bullet_styles` option to `default,disc,circle,square`. #TINY-12083 - -### Fixed -- Autolink no longer overrides already existing links when autolinking. #TINY-11836 -- Removed the deprecated CSS media selector `-ms-high-contrast`. #TINY-11876 -- The `mceInsertContent` command no longer deletes the parent block element when an anchor is selected. #TINY-11953 -- Table resizers are now visible when inline editor has a z-index property. #TINY-11981 -- Tabbing inside a `figcaption` element no longer displays two text insertion carets. #TINY-11997 -- Pressing Enter before a floating image no longer duplicates the image. #TINY-11676 -- Editor did not scroll into viewport on receiving focus on Chrome and Safari. #TINY-12017 -- Select UI elements was not properly styled on Chrome version 136. #TINY-12131 - -## 7.8.0 - 2025-04-09 - -### Added -- New subtoolbar support for context toolbars. #TINY-11748 -- New `extended_mathml_attributes` and `extended_mathml_elements` options. #TINY-11756 -- New `onboarding` option. #TINY-11931 - -### Improved -- Focus outline was misaligned with comment card border on saving an edit. #TINY-11329 -- The `editor.selection.scrollIntoView()` method now pads the target scroll area with a small margin, ensuring content doesn't sit at the very edge of the viewport. #TINY-11786 - -### Changed -- Changed promotional text and link. #TINY-11905 - -### Fixed -- Setting editor height to a `pt` or `em` value was ignoring min/max height settings. #TINY-11108 - -## 7.7.2 - 2025-03-19 - -### Fixed -- Error was thrown when pressing tab in the last cell of a non-editable table. #TINY-11797 -- Error was thrown when trying to use the context form API after a component was detached. #TINY-11781 -- Deleting an empty block within an
  • element would move cursor to the end of the
  • . #TINY-11763 -- Deleting an empty block that was between two lists would throw an Error when all three elements were nested inside a list. #TINY-11763 - -## 7.7.1 - 2025-03-05 - -### Fixed -- Skin UI content CSS was truncated when bundling, causing CSS styles to be missing. #TINY-11875 -- Context forms used to disappear if their input was disabled in the `onSetup` API. #TINY-11890 - -## 7.7.0 - 2025-02-20 - -### Added -- `link_attributes_postprocess` option that allows overriding attributes of a link that would be inserted through the link dialog. #TINY-11707 - -### Improved -- Improved visual indication of keyboard focus in annotations that contain an image. #TINY-11596 -- The type now defaults to `info` when `editor.notificationManager.open()` is used without a specified type or with an invalid one. #TINY-11661 - -### Changed -- Updated the `link` plugin behavior to move the cursor outside of the link when inserted or edited via the UI. Patch contributed by Philipp91. #GH-9998 - -### Fixed -- Keyboard navigation for size inputs in context forms. #TINY-11394 -- Keyboard navigation for context form sliders. #TINY-11482 -- The `insertContent` API was not replacing selected non-editable elements correctly. #TINY-11714 -- Context toolbar inputs had incorrect margins. #TINY-11624 -- Iframe aria text no longer suggests opening the help dialog when the help plugin is not enabled. #TINY-11672 -- Preview dialog no longer opens anchor links in a new tab. #TINY-11740 -- The `float` property was not properly removed on the image when converting a image into a captioned image. #TINY-11670 -- Expanding selection to word didn't work inside inline editing host elements. #TINY-11304 -- The `semantics` element in MathML was not properly retained when `annotation` elements were allowed. #TINY-11755 -- It was possible to tab to a toolbar group that had all children disabled. #TINY-11665 -- Keyboard navigation would get stuck on the 'more' toolbar button. #TINY-11762 -- Toolbar groups had both a `title` attribute and a custom tooltip, causing overlapping tooltips #TINY-11768 -- Toolbar text field did not render focus correctly. #TINY-11658 - -## 7.6.1 - 2025-01-22 - -### Fixed -- Text input was prevented in form elements in the contents of the editor. #TINY-11446 -- Opening a notification when the toolbar is positioned at the bottom of the editor threw an error. #TINY-11498 -- Table resize bars were not properly aligned for inline editors inside scrollable containers. #TINY-11215 - -## 7.6.0 - 2024-12-11 - -### Added -- It is now possible to create labeled groups in context toolbars. #TINY-11095 -- New `contextsliderform` and `contextsizeinput` context form types. #TINY-11342 -- New `back` function in `ContextFormApi` to go back to the previous toolbar. #TINY-11344 -- New `QuickbarInsertImage` command that is executed by the `quickimage` button. #TINY-11399 -- New `onSetup` function to the context form API. #TINY-11494 -- New `placeholder` to the context form input field API. #TINY-11459 -- New `disabled` option to restore the previous `readonly` mode behavior, allowing the editor to be displayed in a disabled state. #TINY-11488 - -### Improved -- Base64 data was not properly decoded due to unhandled URL-encoded characters. #TINY-9548 -- The `latin` list style type is now recognized as an alias for the `alpha` list style type. #TINY-11515 - -### Fixed -- Image selection was removed when calling `editor.nodeChanged()` while having focus inside the editor UI. #TINY-11437 -- Tooltip would not show for group toolbar button. #TINY-11391 -- Changing the table row type when a `contenteditable=false` cell was selected would not work as expected. #TINY-11383 -- The `samp` format was being applied as a `block` level format, instead of an `inline` format. #TINY-11390 -- Removed title attribute from dialog tree elements as they already have a tooltip. #TINY-11470 -- Fixed CSS bundling for skin UI content CSS. #TINY-11558 -- Fixed incorrect resource keys for CSS bundling JS files. #TINY-11558 - -## 7.5.0 - 2024-11-06 - -### Added -- Added support for using raw CSS in the list of possible colours, using the `color_map_raw` property. #GH-9788 - -### Improved -- Improved color picker aria support. #TINY-11291 - -### Fixed -- Autocompleter would not activate after applying an inline format like font size in some cases. #TINY-11273 -- The `toolbar-sticky-offset` would still be applied after entering fullscreen mode. #TINY-11137 -- Text and background color toolbar buttons would not be fully greyed out in readonly mode. #TINY-11313 -- Closing a nested modal dialog would lose focus from the editor. #TINY-11153 -- Inability to type '{' character on German keyboard layouts. #TINY-11395 - -## 7.4.1 - 2024-10-10 - -### Fixed -- Invalid HTML elements within SVG elements were not removed. #TINY-11332 - -## 7.4.0 - 2024-10-09 - -### Added -- New `context` property for all ui components. This allows buttons and menu items to be enabled or disabled based on whether their context matches a given predicate; status updates are checked on `init`, `NodeChange`, and `SwitchMode` events. #TINY-11211 -- Tree component now allows the addition of a custom icon. #TINY-11131 -- Added focus function to view button api. #TINY-11122 -- New option `allow_mathml_annotation_encodings` to opt-in to keep math annotations with specific encodings. #TINY-11166 -- Added global `color-active` LESS variable for use in editor skins. #TINY-11266 - -### Improved -- In read-only mode the editor now allows normal cursor movement and block element selection, including video playback. #TINY-11264 -- Pasting a table now places the cursor after the table instead of into the last cell. #TINY-11082 -- Dialog list dropdown menus now close when the browser window resizes. #TINY-11123 - -### Fixed -- Mouse hover on partially visible dialog collection elements no longer scrolls. #TINY-9915 -- Caret would unexpectedly shift to the non-editable table row above when pressing Enter. #TINY-11077 -- Deleting a selection in a list element would sometimes prevent the `input` event from being dispatched. #TINY-11100 -- Placing the cursor after a table with a br after it would misplace added newlines before the table instead of after. #TINY-11110 -- Sidebar could not be toggled until the skin was loaded. #TINY-11155 -- The image dialog lost focus after closing an image upload error alert. #TINY-11159 -- Copying tables to the clipboard did not correctly separate cells and rows for the "text/plain" MIME type. #TINY-10847 -- The editor resize handle was incorrectly rendered when all components were removed from the status bar. #TINY-11257 - -## 7.3.0 - 2024-08-07 - -### Added -- Colorpicker number input fields now show an error tooltip and error icon when invalid text has been entered. #TINY-10799 -- New `format-code` icon. #TINY-11018 - -### Improved -- When a full document was loaded as editor content the head elements were added to the body. #TINY-11053 - -### Fixed -- Unnecessary nbsp entities were inserted when typing at the edges of inline elements. #TINY-10854 -- Fixed JavaScript error when inserting a table using the context menu by adjusting the event order in `renderInsertTableMenuItem`. #TINY-6887 -- Notifications didn't position and resize properly when resizing the editor or toggling views. #TINY-10894 -- The pattern commands would execute even if the command was not enabled. #TINY-10994 -- Split button popups were incorrectly positioned when switching to fullscreen mode if the editor was inside a scrollable container. #TINY-10973 -- Sequential html comments would in some cases generate unwanted elements. #TINY-10955 -- The listbox component had a fixed width and was not a responsive ui element. #TINY-10884 -- Prevent default mousedown on toolbar buttons was causing misplaced focus bugs. #TINY-10638 -- Attempting to use focus commands on an editor where the cursor had last been in certain contentEditable="true" elements would fail. #TINY-11085 -- Colorpicker's hex-based input field showed the wrong validation error message. #TINY-11115 - -## 7.2.1 - 2024-07-03 - -### Fixed -- Text content could move unexpectedly when deleting a paragraph. #TINY-10590 -- Cursor would shift to the start of the editor body when focus was shifted to a noneditable cell of a table. #TINY-10127 -- Long translations of the bottom help text would cause minor graphical issues. #TINY-10961 -- Open Link button was disabled when selection partially covered a link or when multiple links were selected. #TINY-11009 - -## 7.2.0 - 2024-06-19 - -### Added -- Added `options.debug` API that logs the initial raw editor options to console. #TINY-10605 -- Added `referrerpolicy` as a valid attribute for an iframe element. #TINY-10374 -- New `onInit` and `stretched` properties to the `HtmlPanel` dialog component. #TINY-10900 -- Added support for querying the state of the `mceTogglePlainTextPaste` command. #TINY-10938 -- Added `for` option to dialog label components to improve accessibility. The value must be another component on the same dialog. #TINY-10971 - -### Improved -- Dialog slider components now emit an onChange event when using arrow keys. #TINY-10428 -- Accessibility for element path buttons, added tooltip to describe the button and removed incorrect `aria-level` attribute. #TINY-10891 -- Improve merging of inserted inline elements by removing nodes with redundant inheritable styles. #TINY-10869 -- Improved Find & Replace dialog accessibility by changing placeholders to labels. #TINY-10871 - -### Changed -- Replaced tiny branding logo with `Build with TinyMCE` text and logo. #TINY-11001 - -### Fixed -- Deleting in a `div` with preceeding `br` elements would sometimes throw errors. #TINY-10840 -- `autoresize_bottom_margin` was not reliably applied in some situations. #TINY-10793 -- Fixed cases where adding a newline around a br, table or img would not move the cursor to a new line. #TINY-10384 -- Focusing on `contenteditable="true"` element when using `editable_root: false` and inline mode causing selection to be shifted. #TINY-10820 -- Corrected the `role` attribute on listbox dialog components to `combobox` when there are no nested menu items. #TINY-10807 -- HTML entities that were double decoded in `noscript` elements caused an XSS vulnerability. #TINY-11019 -- It was possible to inject XSS HTML that was not matching the regexp when using the `noneditable_regexp` option. #TINY-11022 - -## 7.1.2 - 2024-06-05 - -### Fixed -- CSS color values set to `transparent` were incorrectly converted to '#000000`. #TINY-10916 - -## 7.1.1 - 2024-05-22 - -### Fixed -- Insert/Edit image dialog lost focus after the image upload completed. #TINY-10885 -- Deleting into a list from a paragraph that has an `img` tag could cause extra inline styles to be added. #TINY-10892 -- Resolved an issue where emojis configured with the `emojiimages` database were not loading correctly due to a broken CDN. #TINY-10878 -- Iframes in dialogs were not rendering rounded borders correctly. #TINY-10901 -- Autocompleter possible values are no longer capped at a length of 10. #TINY-10942 - -## 7.1.0 - 2024-05-08 - -### Added -- Parser support for math elements. #TINY-10809 -- New `math-equation` icon. #TINY-10804 - -### Improved -- Included `itemprop`, `itemscope` and `itemtype` as valid HTML5 attributes in the core schema. #TINY-9932 -- Notification accessibility improvements: added tooltips, keyboard navigation and shortcut to focus on notifications. #TINY-6925 -- Removed `aria-pressed` from the `More` button in sliding toolbar mode and replaced it with `aria-expanded`. #TINY-10795 -- The editor UI now renders correctly in Windows High Contrast Mode. #TINY-10781 - -### Fixed -- Backspacing in certain html setups resulted in data moving around unexpectedly. #TINY-10590 -- Dialog title markup changed to use an `h1` element instead of `div`. #TINY-10800 -- Dialog title was not announced in macOS VoiceOver, dialogs now use `aria-label` instead of `aria-labelledby` on macOS. #TINY-10808 -- Theme loader did not respect the suffix when it was loading skin CSS files. #TINY-10602 -- Custom block elements with colon characters would throw errors. #TINY-10813 -- Tab navigation in views didn't work. #TINY-10780 -- Video and audio elements could not be played on Safari. #TINY-10774 -- `ToggleToolbarDrawer` command did not toggle the toolbar in `sliding` mode when `{skipFocus: true}` parameter was passed. #TINY-10726 -- The buttons in the custom view header were clipped on when overflowing. #TINY-10741 -- In the custom view, the scrollbar of the container was not visible if its height was greater than the editor. #TINY-10741 -- Fixed accessibility issue by removing duplicate `role="menu"` attribute from color swatches. #TINY-10806 -- Fullscreen mode now prevents focus from leaving the editor. #TINY-10597 -- Open link context menu action did not work with selection surrounding a link. #TINY-10391 -- Styles were not retained when toggling a list on and off. #TINY-10837 -- Caret and placeholder text were invisible in Windows High Contrast Mode. #TINY-9811 -- Firefox did not announce the iframe title when `iframe_aria_text` was set. #TINY-10718 -- Notification width was not constrained to the width of the editor. #TINY-10886 -- Open link context menu action was not enabled for links on images. #TINY-10391 - -## 7.0.1 - 2024-04-10 - -### Fixed -- Toggle list behavior generated wrong html when the `forced_root_block` option was set to `div`. #TINY-10488 -- Tapping inside a composed text on Firefox Android would not close the autocompleter. #TINY-10715 -- An inline editor toolbar now behaves correctly in horizontally scrolled containers. #TINY-10684 -- Tooltips unintended shrinking and incorrectly positioned when shown in horizontally scrollable container. #TINY-10797 -- The status bar was invisible when the editor's height is short. #TINY-10705 - -## 7.0.0 - 2024-03-20 - -### Added -- New `license_key` option that must be set to `gpl` or a valid license key. #TINY-10681 -- New custom tooltip functionality, tooltip will be shown when hovering with a mouse or with keyboard focus. #TINY-9275 -- New `sandbox_iframes_exclusions` option that holds a list of URL host names to be excluded from iframe sandboxing when `sandbox_iframes` is set to `true`. #TINY-10350 -- Added 'getAllEmojis' api function to the emoticons plugin. #TINY-10572 -- Element preset support for the `valid_children` option and Schema.addValidChildren API. #TINY-9979 -- A new `trigger` property for block text pattern configurations, allowing pattern activation with either Space or Enter keys. #TINY-10324 -- onFocus callback for CustomEditor dialog component. #TINY-10596 -- icons for the import from Word, export to Word and export to PDF premium plugins. #TINY-10612 -- `data` is now a valid element in the Schema. #TINY-10611 -- More advanced schema config for custom elements. #TINY-9980 -- Custom tooltip for autocompleter, now visible on both mouse hover and keyboard focus, except single column cases. #TINY-9638 - -### Improved -- Included keyboard shortcut in custom tooltip for `ToolbarButton` and `ToolbarToggleButton`. #TINY-10487 -- Improved showing which element has focus for keyboard navigation. #TINY-9176 -- Custom tooltips will now show for items in `collection` which is rendered inside a dialog, on mouse hover and keyboard focus. #TINY-9637 -- Autocompleter will now work with IMEs. #TINY-10637 -- Make table ghost element better reflect height changes when resizing. #TINY-10658 - -### Changed -- TinyMCE is now licensed GPL Version 2 or later. #TINY-10578 -- `convert_unsafe_embeds` editor option is now defaulted to `true`. #TINY-10351 -- `sandbox_iframes` editor option is now defaulted to `true`. #TINY-10350 -- The DOMUtils.isEmpty API function has been modified to consider nodes containing only comments as empty. #TINY-10459 -- The `highlight_on_focus` option now defaults to true, adding a focus outline to every editor. #TINY-10574 -- Delay before the tooltip to show up, from 800ms to 300ms. #TINY-10475 -- Now `tox-view__pane` has `position: relative` instead of `static`. #TINY-10561 -- Update outbound link for statusbar Tiny logo #TINY-10494 -- Remove the height field from the `table` plugin cell dialog. The `table` plugin row dialog now controls the row height by setting the height on the `tr` element, not the `td` elements. #TINY-10617 -- Change table height resizing handling to remove heights from `td`/`th` elements and only apply to `tr` elements. #TINY-10589 -- Removed incorrect `aria-placeholder` attribute from editor body when `placeholder` option is set. #TINY-10452 -- The `tooltip` property for dialog's footer `togglebutton` is now optional. #TINY-10672 -- Changed the `media_url_resolver` option to use promises. #TINY-9154 -- `Styles` bespoke toolbar button fallback changed to `Formats` if `Paragraph` is not configured in `style_formats` option. #TINY-10603 -- Updated deprecation/removed console message. #TINY-10694 - -### Removed -- Deprecated `force_hex_color` option, with the default now being all colors are forced to hex format as lower case. #TINY-10436 -- Deprecated `remove_trailing_brs` option from DomParser. #TINY-10454 -- `title` attribute on buttons with visible label. #TINY-10453 -- `InsertOrderedList` and `InsertUnorderedList` commands from core, these now only exist in the `lists` plugin. #TINY-10644 -- `closeButton` from the notification API, close buttons in notifications are now required. #TINY-10646 -- The autocompleter `ch` configuration property has been removed. Use the `trigger` property instead. #TINY-8929 -- Deprecated `template` plugin. #TINY-10654 - -### Fixed -- When deleting the last row in a table, the cursor would jump to the first cell (top left), instead of moving to the next adjacent cell in some cases. #TINY-6309 -- Heading formatting would be partially applied to the content within the `summary` element when the caret was positioned between words. #TINY-10312 -- Moving focus to the outside of the editor after having clicked a menu would not fire a `blur` event as expected. #TINY-10310 -- Autocomplete would sometimes cause corrupt data when starting during text composition. #TINY-10317 -- Inline mode with persisted toolbar would show regardless of the skin being loaded, causing css issues. #TINY-10482 -- Table classes couldn't be removed via setting an empty value in `table_class_list`. Also fixed being forced to pick the first class option. #TINY-6653 -- Directly right clicking on a ol's li in FireFox didn't enable the button `List Properties...` in the context menu. #TINY-10490 -- The `link_default_target` option wasn't considered when inserting a link via `quicklink` toolbar. #TINY-10439 -- When inline editor toolbar wrapped to multiple lines the top wasn't always calculated correctly. #TINY-10580 -- Removed manually dispatching dragend event on drop in Firefox. #TINY-10389 -- Slovenian help dialog content had a dot in the wrong place. #TINY-10601 -- Pressing Backspace at the start of an empty `summary` element within a `details` element nested in a list item no longer removes the `summary` element. #TINY-10303 -- The toolbar width was miscalculated for the inline editor positioned inside a scrollable container. #TINY-10581 -- Fixed incorrect object processor for `event_root` option. #TINY-10433 -- Adding newline after using `selection.setContent` to insert a block element would throw an unhandled exception. #TINY-10560 -- Floating toolbar buttons in inline editor incorrectly wrapped into multiple rows on window resizing or zooming. #TINY-10570 -- When setting table border width and `table_style_by_css` is true, only the border attribute is set to 0 and border-width styling is no longer used. #TINY-10308 -- Clicking to the left or right of a non-editable div in Firefox would show two cursors. #TINY-10314 - -## 6.8.3 - 2024-02-08 - -### Changed -- Update outbound TinyMCE website links. #TINY-10491 - -### Fixed -- The floating toolbar would not be fully visible when the editor was placed inside a scrollable container. #TINY-10335 -- ShadowDOM skin was not loaded properly when used with js bundling feature. #TINY-10451 - -## 6.8.2 - 2023-12-11 - -### Fixed -- Bespoke select toolbar buttons including `fontfamily`, `fontsize`, `blocks`, and `styles` incorrectly used plural words in their accessible names. #TINY-10426 -- The `align` bespoke select toolbar button had an accessible name that was misleading and grammatically incorrect in certain cases. #TINY-10435 -- Accessible names of bespoke select toolbar buttons including `align`, `fontfamily`, `fontsize`, `blocks`, and `styles` were incorrectly translated. #TINY-10426 #TINY-10435 -- Clicking inside table cells with heavily nested content could cause the browser to hang. #TINY-10380 -- Toggling a list that contains an LI element having another list as its first child would remove the remaining content within that LI element. #TINY-10414 - -## 6.8.1 - 2023-11-29 - -### Improved -- Colorpicker now includes the Brightness/Saturation selector and hue slider in the keyboard navigable items. #TINY-9287 - -### Fixed -- Translation syntax for announcement text in the table grid was incorrectly formatted. #TINY-10141 -- The functions `schema.isWrapper` and `schema.isInline` did not exclude node names that started with `#` which should not be considered as elements. #TINY-10385 - -## 6.8.0 - 2023-11-22 - -### Added -- CSS files are now also generated as separate JS files to improve bundling of all resources. #TINY-10352 -- Added new `StylesheetLoader.loadRawCss` API that can be used to load CSS into a style element. #TINY-10352 -- Added new `StylesheetLoader.unloadRawCss` API that can be used to unload CSS that was loaded into a style element. #TINY-10352 -- Added `force_hex_color` editor option. Option `'always'` converts all RGB & RGBA colours to hex, `'rgb_only'` will only convert RGB and *not* RGBA colours to hex, `'off'` won't convert any colours to hex. #TINY-9819 -- Added `default_font_stack` editor option that makes it possible to define what is considered a system font stack. #TINY-10290 -- New `sandbox_iframes` option that controls whether iframe elements will be added a `sandbox=""` attribute to mitigate malicious intent. #TINY-10348 -- New `convert_unsafe_embeds` option that controls whether `` and `` elements will be converted to more restrictive alternatives, namely `` for image MIME types, `